3
$\begingroup$

This question already has an answer here:

I met a complicated function y=f(x) in my research, this function has no analytical expression, and only numerical values are accessible to me (So I can only use ListPlot rather than Plot). I need to plot it with points evenly distributed in my graph, and I don't know how to do it. Let me just simplify my problem as follows:

Now I am trying to plot y=1/x around x=0:

ListPlot[Table[{n,y = 1/n}, {n, -10, 10}]]

and I can get:

enter image description here

I am happy with those data with |n|>3, but I am not happy with the data around n=0, so I want to find a way to plot more data around n=0 while keep the data density elsewhere unchanged. I know I can plot two graphs with different range and interval of n and use Show[] to combine them together, but I hope to find a neat way to it. Thank you!

$\endgroup$

marked as duplicate by corey979, Feyre, xzczd, MarcoB, m_goldberg plotting Jan 3 '17 at 18:42

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    $\begingroup$ Just to make sure, you don't want to use Plot, right? $\endgroup$ – xzczd Jan 3 '17 at 2:19
  • 3
    $\begingroup$ Does Plot[1/x, {x, -10, 10}, Mesh -> 30, MeshFunctions -> {"ArcLength"}, MeshStyle -> Red, PlotRange -> {-2, 2}, PlotStyle -> None] work for you? $\endgroup$ – J. M. will be back soon Jan 3 '17 at 4:01
  • $\begingroup$ Plot can be used on numeric functions: func[n_?NumericQ] := 1/n; Plot[func@n, {n, -1, 1}] $\endgroup$ – xzczd Jan 3 '17 at 5:11
3
$\begingroup$

So after the other answer and comment I really really hope you ment working with ListPlot. Otherwise im sad :D

-

So it's not an anwser with a pretty short code but it works well.

To uniformly distribute your points, we want the length between adjacent points to be constant. So we formulate:

$$l=\sqrt{(\Delta x)^2+(\Delta y)^2}$$ $$l=\sqrt{(x_1-x_2)^2+(1/x_1-1/x_2)^2}$$

Solving this for $x_2$ gives two solutions. One backward (the first) and one forward solution (represented by Root). So if we define a $l$ and a $y_{min,max}$-value

l = 1/5; (*length between points*)
yBorder = 2; (*max absolute y value*)
sol = x2 /. Solve[l == Sqrt[(x1 - x2)^2 + (1/x1 - 1/x2)^2], x2, Reals];

we could solve the points as long as they are in the range using Reap and Sow in a Do from both sides starting by $x=3$ and $x=-3$:

xPoints = Reap[
    Do[
     x = 3*(-1)^(i + 1); Sow[x];
     y = 1/x;
     While[Abs[y] <= yBorder, x = N[sol[[i]] /. {x1 -> x}]; Sow[x]; 
      y = 1/x];
     , {i, 1, 2}]
    ][[2, 1]];

getting everything together and ploting it:

l = 1/5; (*length between points*)
yBorder = 2; (*max absolute y value*)
xBorder = 3;
sol = x2 /. Solve[l == Sqrt[(x1 - x2)^2 + (1/x1 - 1/x2)^2], x2, Reals];
xPoints = Reap[
    Do[
     x = xBorder*(-1)^(i + 1); Sow[x];
     y = 1/x;
     While[Abs[y] <= yBorder, x = N[sol[[i]] /. {x1 -> x}]; Sow[x]; 
      y = 1/x];
     , {i, 1, 2}]
    ][[2, 1]];
yPoints = 1/xPoints;
points = Transpose[{xPoints, yPoints}];
ListPlot[points]

Blockquote

Attention: You should also take the AspectRatio and PlotRange into account, since it seems that for bigger $y$-values the distance between the adjacent points shrinks or grows which is not the case.

I've did it for you (which was more easier than i thought):

It uses the fact that we just need to stretch one of the coordinates to the PlotRange and AspectRatio:

$$l=\sqrt{(\Phi\cdot (y_{max}-y_{min})/(x_{max}-x_{min})\cdot\Delta x)^2+(\Delta y)^2}$$

Where $\Phi$ is the inverse AspectRatio which is by default the GoldenRatio.

l = 1; (*length between points*)
yBorder = 10; (*max absolute y value*)
xBorder = 50;
sol = x2 /. 
   Solve[l == 
     Sqrt[(yBorder/xBorder)^2*
        GoldenRatio^2*(x1 - x2)^2 + (1/x1 - 1/x2)^2], x2, Reals];
xPoints = Reap[
    Do[
     x = xBorder*(-1)^(i + 1); Sow[x];
     y = 1/x;
     While[Abs[y] <= yBorder, x = N[sol[[i]] /. {x1 -> x}]; Sow[x]; 
      y = 1/x];
     , {i, 1, 2}]
    ][[2, 1]];
yPoints = 1/xPoints;
points = Transpose[{xPoints, yPoints}];
ListPlot[points, PlotRange -> Full]

enter image description here

$\endgroup$
  • $\begingroup$ Thank you! I can only use ListPlot since the real problem I met is so complicated that no analytical answer can be used for Plot. It is not neat, but I can accept it. $\endgroup$ – Jieyu You Jan 3 '17 at 3:55
0
$\begingroup$

If you are planning to use Plot then...

You can do it fairly easily with Piecewise

f[x_] := Piecewise[{{1/x, -10 <= x < 0}, {1/x, 0 < x <= 10}}]
Plot[f[x], {x, -10, 10}]

enter image description here

$\endgroup$
  • $\begingroup$ Plot[1/x, {x, -10, 10}] will give this Plot $\endgroup$ – Bob Hanlon Jan 3 '17 at 3:30
  • $\begingroup$ @BobHanlon You are right but the idea was split the interval. $\endgroup$ – zhk Jan 3 '17 at 10:07

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