2

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?

Vaggelis_Z
  • 8,740
  • 6
  • 34
  • 79
  • 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? – CA Trevillian May 30 '20 at 17:34

4 Answers4

3

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.

Rohit Namjoshi
  • 10,212
  • 6
  • 16
  • 67
3

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} *)
MarcoB
  • 67,153
  • 18
  • 91
  • 189
  • Cases[data, {x_, y_} /; Round[y, 0.01] == 0.5 :> {x, y}] is probably closer to what the OP is looking for. – Rohit Namjoshi May 30 '20 at 17:38
  • @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. – MarcoB May 30 '20 at 17:48
  • Please note that InterpolationOrder of Interpolation is 3 by default, this may not correspond with what is wanted. – kirma May 30 '20 at 18:21
  • 1
    @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. – MarcoB May 30 '20 at 18:34
2

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).

kirma
  • 19,056
  • 1
  • 51
  • 93
1
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

user1066
  • 17,923
  • 3
  • 31
  • 49