How can I add a single point to an existing plot with pyplot?
For example, I'm plotting a shifted sin curve over $[0,2\pi]$ with the below
Pkg.add("PyPlot")
using PyPlot
r1 = 0; r2 = 2*pi
N = 100
t = collect(r1:(r2-r1)/N:r2)
fig, ax = subplots()
ax[:plot](t, 1+sin(t),
linewidth=2.0, color="red",linestyle="--",label="constraint")
and I want to add a blue point at the minimum. How can I do this?
Related
I am calculating points along a three-dimensional logarithmic spiral between two points. I seem to be close, but I think I'm missing a conditional sign flip somewhere.
This code works relatively well:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p1 = [1,1,1]
p2 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1-p2)
t = range(0,r,rez)
theta_offset = atan((p1[2]-p2[2])/(p1[1]-p2[1]))
theta = range(0, 2*pi*rev, rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p1[1];
y = sin.(theta).*exp.(-t).*r.+p1[2];
z = exp.(-t).*log.(r).+p1[3]
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
and produces the following plot. Values of the endpoints are shown on the plot, with an arrow from the coordinate to its respective marker. The first point is off, but it's close enough for my liking.
The problem comes when I flip p2 and p1 such that
p1 = [3,10,2]
p2 = [1,1,1]
In this case, I still get a spiral from p2 to p1, and the end point (p1) is highly accurate. However, the other endpoint (p2) is wildly off:
I think this is due to me changing the relative Z position of the two points, but I'm not sure, and I haven't been able to solve this riddle. Any help would be greatly appreciated. (Bonus points if you can help figure out why the Z value on p2 is off in the first example!)
Assuming this is a follow-up of your other question: Drawing an equiangular spiral between two known points in Julia
I assume you just want to add a third dimension to your previous 2D problem using cylindric coordinate system. This means that you need to separate the treatment of x and y coordinate on one side, and the z coordinate on the other side.
First you need to calculate your r on the first two coordinate:
r = norm(p1[1:2]-p2[1:2])
Then, when calculating z, you need to take only the third dimension in your formula (not sure why you used a log function there in the first place):
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
That will fix your z-axis.
Finally for your x and y coordinate, use the two argument atan function:
julia>?atan
help?> atan
atan(y)
atan(y, x)
Compute the inverse tangent of y or y/x, respectively.
For one argument, this is the angle in radians between the positive x-axis and the point (1, y), returning a value in the interval [-\pi/2, \pi/2].
For two arguments, this is the angle in radians between the positive x-axis and the point (x, y), returning a value in the interval [-\pi, \pi]. This corresponds to a standard atan2
(https://en.wikipedia.org/wiki/Atan2) function. Note that by convention atan(0.0,x) is defined as \pi and atan(-0.0,x) is defined as -\pi when x < 0.
like this:
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
And finally, like in your previous question, add the p2 point instead of the p1 point at the end of x, y, and z:
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
In the end, I have this:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p2 = [1,1,1]
p1 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1[1:2]-p2[1:2])
t = range(0.,norm(p1-p2), length=rez)
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
theta = range(0., 2*pi*rev, length=rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
#show (x[begin], y[begin], z[begin])
#show (x[end], y[end], z[end]);
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
Which give the expected results:
p2 = [1,1,1]
p1 = [3,10,2]
(x[begin], y[begin], z[begin]) = (3.0, 10.0, 2.0)
(x[end], y[end], z[end]) = (1.0001877364735474, 1.0008448141309634, 1.0000938682367737)
and:
p1 = [1,1,1]
p2 = [3,10,2]
(x[begin], y[begin], z[begin]) = (0.9999999999999987, 1.0, 1.0)
(x[end], y[end], z[end]) = (2.9998122635264526, 9.999155185869036, 1.9999061317632263)
In 2D, let us assume the pole at the point C, and the spiral from P to Q, corresponding to a variation of the parameter in the interval [0, 1].
We have
X = Cx + cos(at+b).e^(ct+d)
Y = Cy + sin(at+b).e^(ct+d)
Using the known points,
Px - Cx = cos(b).e^d
Py - Cy = sin(b).e^d
Qx - Cx = cos(a+b).e^(c+d)
Qy - Cy = sin(a+b).e^(c+d)
From the first two, by a Cartesian to polar transformation (and logarithm), you can obtain b and d. From the last two, you similarly obtain a+b and c+d, and the spiral is now defined.
For the Z coordinate, I cannot answer precisely as you don't describe how you generalize the spiral to 3D. Anyway, we can assume a certain function Z(t), that you can map to [Pz, Qz] by the linear transformation
(Qz - Pz) . (Z(t) - Z(0)) / (Z(1) - Z(0)) + Pz.
I have two random points in a 2D Cartesian grid, p1 and p2. I would like to define a curve between p1 and p2 of N points such that the curve forms an equiangular spiral (similar to what is done in this paper (Fig. 8)). I've tried converting the paper into a script, but something is still off, so I'm trying to build a "dumbed down" example. My closest attempt is this (p2 can be seen on zoom-in, but not shown in script's plot):
using PyPlot
using LinearAlgebra
p1 = [5,7]
p2 = [1,2]
r = norm(p1-p2)
theta_offset = tan((p1[2]-p2[2])/(p1[1]-p2[1]));
# Number of points
rez = 500
# Number of revolutions
rev = 5
# Radius as spiral decreases
t = range(0,r,rez)
# Angle as spiral decreases
theta = range(0, 2*pi*rev, rez) .+ theta_offset
x = cos.(theta).*exp.(-t).+p2[1];
y = sin.(theta).*exp.(-t).+p2[2];
figure()
plot(x,y)
scatter(p1[1],p1[2],c="red",s=5)
scatter(p2[1],p2[2],c="red",s=10)
show(); gcf()
which produces the following plot:
While the plot is centered on p2 (at coordinate [1,2]), the endpoint does not lie near / pass through my specified point p1. My ideal outcome would be something like this:
EDIT: Solved problem using #PaSTE's suggestion. Changing my theta_offset, x, and y coordinate calculations to:
theta_offset = atan((p1[2]-p2[2])/(p1[1]-p2[1]));
x = cos.(theta).*exp.(-t).*r.+p2[1]
y = sin.(theta).*exp.(-t).*r.+p2[2]
yields the following plot, exactly what I was hoping for. In my solution, handedness and number of loops are not important.
As PaSTE said, The issue is the algebra: you need get the angle with atan, not tan, and multiply your exponential factor by r to get the right radius.
using LinearAlgebra
using Plots
p1 = [5,7]
p2 = [1,2]
r = norm(p1-p2)
theta_offset = atan((p1[2]-p2[2])/(p1[1]-p2[1]));
# Number of points
rez = 1500
# Number of revolutions
rev = 5
# Radius as spiral decreases
t = range(0,r,rez)
# Angle as spiral decreases
theta = range(0, 2*pi*rev, rez) .+ theta_offset
x = cos.(theta) .* r .* exp.(-t) .+ p2[1]
y = sin.(theta) .* r .* exp.(-t) .+ p2[2]
plot(x, y)
scatter!([p1[1], p2[1]], [p1[2], p2[2]])
I would like to reproduce pringle shape in Octave.
Please, look at the attachment - that is done in Mathematica using "Region" function.
Is possible to cut that circular shape also in Octave? Until now I've got this (code below) but it has rectangular shape/ platform not circular like in Mathematica (picture below).
a = 10
b = 10
x = [-10:.1:10];
y = [-10:.1:10];
[xx, yy] = meshgrid (x, y);
z = xx.^2/a.^2 - yy.^2/b.^2
h = surf(xx,yy,z);
colormap hsv;
set(h,'linestyle','none');
I am trying to produce a distribution for points within a circle where there are more towards the center, but for a donut shape
I can produce a uniformly distributed donut shape (1), or a circle where there are more points towards the center (2) but not a donut shape that has so many points towards its inside boundary.
(1)
r = sqrt(runif(250, min = 0.25, max =1))
p = runif(250)
theta = p *2*pi
a = r * cos(theta) #coordinates for circle
b = r * sin(theta)
plot(a,b)
(2)
r = runif(250)
p = runif(250)
theta = p *2*pi
a = r * cos(theta)
b = r * sin(theta)
plot(a,b)
My closest attempt is modifying program (2) where r is bound between 0.5 and 1 but this removes most of the points closest to the center and does not have as many around its inside.
As #RobertDodier said, try to use some advanced distribution for radius. What I would like to propose is Beta distribution.
First, it is naturally in the [0...1] range, no need to truncate, accept/reject etc.
Second, it has two parameters (a,b) which could be used to get single peak, zero at 0, and slope to 1. Look at graphs in the wiki page. And last, it is implemented in R. a being smaller than b means peak is on the lef of 0.5, a being larger than b means peak is on the right of 0.5.
Along the lines
N = 10000
r = rbeta(N, 7.0, 5.0)
theta = 2.0*pi*runif(N)
a = r * cos(theta)
b = r * sin(theta)
plot(a,b)
will produce plot like that
Does it look like at donut?
UPDATE
This one is with clear hole at the center and shape proposed by #RobertDodier
N = 10000
hole = 0.25
r = hole + (1.0-hole)*rbeta(N, 1.0, 3.0)
theta = 2.0*pi*runif(N)
a = r * cos(theta)
b = r * sin(theta)
plot(a,b)
Another one with clear hole in the center and symmetric shape, like a true donut
r = hole + (1.0-hole)*rbeta(N, 2.0, 2.0)
I want to visualize the roots of tan(xi) = tanh(xi), xi>0 and my plot
plot(tan(pi*xi), tanh(pi*xi), (xi, 0, 4), ylim=(-1, 2))
comes out like this
where one sees the actual roots, xi_i \approx pi*(n+1/4), n=1, ... but also
fake roots at pi*(n+1/2), the reason why being sympy plotting algorithm that draws a vertical line between plus and minus infinity.
I tried to avoid the adaptive sampling and using a low sampling rate to no avail. Other programs, eg gnuplot, give me a more reasonable plot, at least in view of my concerns, that is...
Eventually my question is, is it possible to avoid those vertical lines in sympy's plot() function?
Sympy uses matplotlib as a backend for plotting; the root cause is that matplotlib connects the dots even around a singularity. If one plots with numpy, the direct access to y-values being plotted allows one to replace overly large numbers with nan or infinity. If staying within sympy, such tight control over numerics does not appear to be available. The best I could do is to split the range into a list of smaller ranges that do not include singularities, using the knowledge of the specific function tan(pi*x):
import math
from sympy import *
xi = symbols('xi')
xmin = 0
xmax = 4
ranges = [(xi, n-0.499, n+0.499) for n in range(math.ceil(xmin+0.5), math.floor(xmax+0.5))]
ranges.insert(0, (xi, 0, 0.499))
ranges.append((xi, math.floor(xmax+0.5) - 0.499, xmax))
plot((tanh(pi*xi), (xi, xmin, xmax)), *[(tan(pi*xi), ran) for ran in ranges], ylim=(-1, 2))
Output:
When a curve has singularities, it can plotted by segments, excluding the singularities. A tiny interval around the each singularity is built with math.nextafter(a,b) which returns a plus the smallest possible increment for a float, in direction of b.
from sympy import init_printing, symbols, plot
from sympy import singularities, Interval, tan, pi
from math import nextafter
init_printing()
x = symbols('x')
# The function to plot
y = tan(pi*x)
# Split x range at x singularities
min_x = next_x = 0
max_x = 4 # 4*pi
segments = []
undefs = singularities(y, x, domain=Interval(min_x, max_x))
for u in undefs:
# Add a subrange up to singularity for singularities within x range
if (u >= min_x) and (u <= max_x):
segments.append((x, next_x, nextafter(u, u-1)))
next_x = nextafter(u, u+1)
# Add last segment
if u <= max_x: segments.append((x, next_x, max_x))
# Plot all segments
plots = plot(*[(y, segment) for segment in segments], ylim=(-2,2), show=False)
plots.aspect_ratio = (1,1)
plots.show()
Of course you can use the same color for each curve segment.