2
$\begingroup$

Let's create a simple data list

Clear["Global`*"];

data = Table[{i, Sin[i]}, {i, 0, 6 \[Pi], 0.01}];
L0 = ListPlot[data]

enter image description here

Now I want to find for which values of $x$ we have let's say $y = 0.5$. Note that my actual data do not correspond to a known function (e.g., sin()), so the solution should not take into account the function but purely the data list.

Any suggestions?

$\endgroup$
  • $\begingroup$ Will it always be “around” that value, for the whole of the function/plot? Perhaps an intersection with a line kind of thing could work? $\endgroup$ – CA Trevillian May 30 at 17:34
3
$\begingroup$

There are no values for which the ordinate is exactly 0.5 in your list, so you will have to decide for yourself how close is close enough:

For instance, if a tolerance of 0.01 is sufficiently close, then:

Cases[data, {x_, y_} /; Round[y, 0.01] == 0.5 :> x]
(* Out: {0.52, 2.62, 6.81, 8.9, 13.09, 15.18, 15.19} *)

If you want a stricter tolerance, e.g. 0.001, then:

Cases[data, {x_, y_} /; Round[y, 0.001] == 0.5 :> x]
(* Out: {13.09} *)

We can put this together in a function:

ClearAll[selector]
selector[data_, desiredVal_, tolerance_] := 
  Cases[data, {x_, y_} /; Round[y, tolerance] == desiredVal :> x]

selector[data, 0.5, 0.01]
(* Out: {0.52, 2.62, 6.81, 8.9, 13.09, 15.18, 15.19} *)

If, on the other hand, you would like to use an interpolation to determine the value of x (perhaps not present in your dataset, but obtained by interpolation from it) for which $y=0.5$ exactly, you could use the following method to find all zeros of a function over a range I've learned on this site (but currently can't find a link for, will update):

int = Interpolation[data];

First@Last@
  Reap@
    NDSolve[
      {f'[x] == int'[x], f[0] == int[0], WhenEvent[f[x] == 0.5, Sow[x]]},
      f, Evaluate@{x, MinMax[ data[[All, 1]] ]}
    ]

(* Out: {0.523599, 2.61799, 6.80678, 8.90118, 13.09, 15.1844} *)
| improve this answer | |
$\endgroup$
  • $\begingroup$ Cases[data, {x_, y_} /; Round[y, 0.01] == 0.5 :> {x, y}] is probably closer to what the OP is looking for. $\endgroup$ – Rohit Namjoshi May 30 at 17:38
  • $\begingroup$ @Rohit Possibly; but I read the question as only asking the values of $x$ that are associated with a given y; not the corresponding y. OP might not care about the $y$ since it is what they are selecting for, so it is implicit in the request. $\endgroup$ – MarcoB May 30 at 17:48
  • $\begingroup$ Please note that InterpolationOrder of Interpolation is 3 by default, this may not correspond with what is wanted. $\endgroup$ – kirma May 30 at 18:21
  • 1
    $\begingroup$ @kirma that’s true, but the differences In the results are very small, whereas the default interpolation order leads to much faster calculations than InterpolationOrder -> 1. $\endgroup$ – MarcoB May 30 at 18:34
3
$\begingroup$

Update

To get the n nearest values

nfun[.5, 6]

(* 
  {{1310, 0.500027}, {891, 0.501021}, {263, 0.498262}, {682, 0.502782}, {53, 0.49688}, {1519, 0.503775}}
*)

Here is one way

nfun = Nearest[data[[All, 2]] -> {"Index", "Element"}];
nfun[.5]

(* {{1310, 0.500027}} *)

The value closest to 0.5 is 0.500027 at index 1310.

| improve this answer | |
$\endgroup$
  • $\begingroup$ That's only one value. In this example, there are six values of $x$ for which $y = 0.5$. $\endgroup$ – Vaggelis_Z May 30 at 17:15
  • $\begingroup$ No, there are none that equal 0.5. Select[data, #[[2]] == 0.5 &] is an empty list. $\endgroup$ – Rohit Namjoshi May 30 at 17:16
  • $\begingroup$ So, we need to find all (six in this case) values of $x$ for which $y$ is close to 0.5. $\endgroup$ – Vaggelis_Z May 30 at 17:21
  • $\begingroup$ One comment: the output should explicitly give the values of $x$ not their position in the list. $\endgroup$ – Vaggelis_Z May 30 at 17:24
  • $\begingroup$ @Vaggelis_Z I updated my answer. You will have to define what "close" means. $\endgroup$ – Rohit Namjoshi May 30 at 17:24
2
$\begingroup$

Here's an incredibly dumb solution that tries to find values of $x$ that correspond to the linear piecewise interpolation between data points. (Frankly I find the formulation of the question imprecise for other interpretations.) For some reason SequenceCases is much slower (like thousands of times, at least) than it should really be...

With[{y0 = 0.5},
 SequenceCases[
  Table[{i, Sin[i]}, {i, 0, 6 Pi, 0.01}],
  l : {{x1_, y1_}, {x2_, y2_}} /; y1 <= y0 <= y2 || y2 <= y0 <= y1 :>
   (x /. First@Quiet@
       Solve[Interpolation[l, InterpolationOrder -> 1][x] == y0, x]),
  Overlaps -> True]]

{0.523605, 2.61799, 6.80679, 8.90118, 13.09, 15.1844}

@MarcoB's NDSolve trick is maybe cleaner version of the same (although it would be even nicer if one could just get all roots with Solve of a single Interpolation).

| improve this answer | |
$\endgroup$
1
$\begingroup$
dataSubset=Pick[data,Unitize[Clip[data[[All,2]], {0.5-0.01, 0.5+0.01},{0,0}]],1]

{{0.52, 0.49688}, {0.53, 0.505533}, {2.61, 0.506907}, {2.62, 0.498262}, {6.8, 0.494113}, {6.81, 0.502782}, {8.89, 0.50965}, {8.9, 0.501021}, {8.91, 0.492342}, {13.08, 0.491342}, {13.09, 0.500027}, {13.1, 0.508661}, {15.18, 0.503775}, {15.19, 0.495112}}

FindClusters[Rule@@@dataSubset]

{{0.49688, 0.505533}, {0.506907, 0.498262}, {0.494113, 0.502782}, {0.50965, 0.501021, 0.492342}, {0.491342, 0.500027, 0.508661}, {0.503775, 0.495112}}

Rule@@@dataSubset//FindClusters[#]/.Reverse[#,{2}]&

{{0.52, 0.53}, {2.61, 2.62}, {6.8, 6.81}, {8.89, 8.9, 8.91}, {13.08, 13.09, 13.1}, {15.18, 15.19}}

Length@% 

6

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.