# How can I force points in a list to have distinct x values?

I have a list of points that may be used for linear interpolation using Interpolation and need to ensure that no two points have the same $x$ value, since, if they do, Interpolation reports errors:

Ideally I'd like to simply tweak such points just enough, that their control points don't shift visibly, but that they satisfy Interpolation (e.g. by adding a very small number to one of the offending points).

Alternatively, perhaps a different Mathematica interpolation function or different options for Interpolation avoid this error.

I've tried randomizing the points a bit, using various methods, but I get strange behavior, including briefly jagged plots (e.g. when changing settings for iorder) and eventual unresponsiveness of the control points (they just won't move).

Manipulate[
(*pts = MapAt[# + RandomReal[NormalDistribution[0, 10^-4]] &,
pts, -1];*)
(*pts={RandomReal[{#[[1]]-.0001,#[[1]]+.0001}],#[[2]]}&/@pts;*)
Plot[Interpolation[Prepend[pts, {0, 0}], InterpolationOrder -> iorder][x], {x, 0, 1}],
{{pts, {{.2, .1}, {.4, .2}, {.6, .3}, {.8, .25}, {1, 0}}}, Locator},
{{iorder, 3, "InterpolationOrder"}, Range[3], SetterBar}]


In context, I switch among even more curve fitting methods (e.g. Bezier, etc.), so dropping points is not an option, nor is moving them perceptibly, or skipping them.

-
Why not just add a tiny amount of random floating point error to all coordinates? – whuber Nov 8 '12 at 21:19
@whuber: I'm not sure how to do that, if I precede the plot with something like pts = {RandomReal[{#[[1]] - .0001, #[[1]] + .0001}], #[[2]]} & /@ pts;, I get a wobbly plot. – raxacoricofallapatorius Nov 8 '12 at 21:36
what about DeleteDuplicates? – chris Nov 8 '12 at 21:40
@chris: No dropping, skipping or (perceptibly) moving of points. All the control points need to pretty much seem to stay where there are. They can "stick" of shift a tiny amount if that's the only way, but removing them is definitely out. – raxacoricofallapatorius Nov 8 '12 at 21:48
I don't know what the structure of points is intended to be, so I'll give you an inefficient generic solution to jitter all the coordinates: MapAt[# + RandomReal[NormalDistribution[0, 10^-4]] &, points, -1]. Use a uniform distribution to limit the amount of jittering if you like and change the 10^-4 to suit your tastes. Generalizations of this approach will jitter only the x-coordinates. The idea here is to avoid looking for duplicates altogether. And if you're willing to change some coordinates, arguably it's best to change them all in the same fashion. – whuber Nov 8 '12 at 21:51

Assuming your points are in order, then you could just use a rule:

rule = {before___, {x_, y1_}, {x_, y2_}, after___} ->
{before, {x, y1}, {x + tweak, y2}, after}


Then apply with repeated replacement:

pts //. rule

-
That seems to do the trick! – raxacoricofallapatorius Nov 8 '12 at 22:13

It seems that interpolation in two dimensions is desired. To do so, interpolate the x- and y-coordinates separately and plot the curve parametrically:

Manipulate[
Module[{f = Interpolation[#, InterpolationOrder -> iorder] & /@
Transpose[Prepend[pts, {0, 0}]]},
ParametricPlot[Through[f[x]], {x, 1, Length[pts]+1}, PlotRange -> {Full, Full}]],
{{pts, {{.2, .1}, {.4, .2}, {.6, .3}, {.8, .25}, {1, 0}}}, Locator},
{{iorder, 3, "InterpolationOrder"}, Range[3]}]


Now it does not matter that some of the x-coordinates may have been duplicated.

-
"...interpolate the $x$- and $y$-coordinates separately and plot the curve parametrically." - in that regard, one might consider using something like centripetal parametrization for the purpose... – J. M. Nov 9 '12 at 16:21
@J.M. Thanks for that reference. – whuber Nov 9 '12 at 16:24