Matplotlib: transformation of variables for narrow orbit - python

I have an annoyingly narrow orbit in phase space that looks like this:
What kind of transformation of the variables can I do to get a nice circular orbit in this case?
My code is this:
import numpy as np
import matplotlib.pylab as plt
x,y = np.loadtxt("data.txt").T
plt.plot(x,y)
plt.show()
The data can be found here - link

I'm not sure if this is what you're after. What you can do is shift one of the two coordinates by the quarter of a circle and normalize to the other coordinate.
import numpy as np
import matplotlib.pylab as plt
x,y = np.loadtxt("data/orbit.txt").T
y = np.roll(y, len(y)//4)
y = (y-y.mean())*((x.max()-x.min())/(y.max()-y.min())) +y.mean()
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.set_aspect("equal")
ax.plot(x,y)
t = np.linspace(0,2*np.pi, len(x))
ax2.plot(t,x-x.mean())
ax2.plot(t,y-y.mean())
plt.show()

Related

How to plot marker at beggining and end points using matplotlib

How can I automate a code so that I can place a marker for the starting and end points of this plot using matplotlib.pyplot?
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 9, 9)
y = x**2
A simple way would be just to overplot 2 points (being the begining and end points) ontop of your current plot. Using plt.figure(), we can have two plots ontop of each other.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 9, 9)
y = x**2
plt.figure()
plt.plot(x,y)
plt.scatter([x[0],x[-1]], [y[0],y[-1]])
Futhermore, this can be automatated by declare your own function which plots two plots on top automatically:
def plot(x,y):
plt.figure()
plt.plot(x,y)
plt.scatter([x[0],x[-1]], [y[0],y[-1]])

matplotlib.pyplot: set distance for axis units

import numpy as np
import matplotlib.pyplot as plt
x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.plot(x,y)
plt.xticks(np.arange(min(x), max(x)+1, 1))
plt.show()
shows
But if I set unit to 0.5:
plt.xticks(np.arange(min(x), max(x)+1, 0.5)) shows
x-axis is hardly readable.
Is there a way to set distance for every x-axis unit so it could extend the plot automatically (on x direction)?
This works:
import numpy as np
import matplotlib.pyplot as plt
x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.figure(figsize=(20,10))
plt.plot(x,y)
plt.xticks(np.arange(min(x), max(x)+1, 0.5))
plt.show()
Operating on size of the figure does the job. Play with it, find your desired size/ratio etc.

Drawing a logarithmic spiral in three axes in Python

I try to draw a logarithmic spiral in the form of a spring in three axes.
Using the parametric equations:
x=a*exp(b*th)*cos(th)
y=a*exp(b*th)*sin(th)
Using the code:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from math import exp,sin,cos
from pylab import *
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
n=100
a=0.5
b=0.20
th=np.linspace(0, 500, 10000)
x=a*exp(b*th)*cos(th)
y=a*exp(b*th)*sin(th)
ax.plot(x, y)
ax.legend()
plt.show()
I get:
However, I would like to stretch the spiral along the Z axis to get a result similar to the following, but using the logarithmic spiral as the basis:
How can you do it? How do you modify the function by adding a condition to the Z axis?
Which z to take it's a bit up to you. From the plot itself it's hard to say but my guess is that it's linear (the simplest option).
Taking your code and adding the z axis you can do something like this
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from math import exp,sin,cos
from pylab import *
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
a=0.05
b=0.10
# took the liberty of reducing the max value for th
# as it was giving you values of the order of e42
th=np.linspace(0, 50, 10000)
x=a*exp(b*th)*cos(th)
y=a*exp(b*th)*sin(th)
z=np.linspace(0,2, 10000) # creating the z array with the same length as th
ax.plot(x, y, z) # adding z as an argument for the plot
ax.legend()
plt.show()
You can play with your a and b parameters to get the elliptical shape you want. You can also play with the definition of z to make it exponential, or logarithmic in growth.. or something else entirely.
BTW, your imports are a bit redundant and probably some funtions from one package are being shadowed by another package.
Since 95% of the points of the spiral are condensed in a single point in the middle of the plot it would make sense to restrict the plotted range to something like
th=np.linspace(475, 500, 10000)
Then using a linear range of z values would directly give you the desired curve in the plot, by simply specifying that range in the plot function, plot(x,y,z).
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
a=0.5
b=0.20
th=np.linspace(475, 500, 10000)
x=a*np.exp(b*th)*np.cos(th)
y=a*np.exp(b*th)*np.sin(th)
z = np.linspace(0,2, len(th))
ax.plot(x, y, z)
#ax.legend()
plt.show()
Note that I cleaned up the imports here. E.g. if you import cos from math but later import everything (*) from pylab into the namespace, the function cos that is used is the numpy cos function, not the one from math (the math cos function would not work here anyways). In general: don't use pylab at all.

The plot3d figure in matplotlib is somewhat canted

I am using matplotlib to get a water fall figure, but the results look very strange. Anyone have any idea what could be wrong with it?
Here I attached the figures. The second one is the same data but in an ordinary plot. In the waterfall figure, why the color is not fully filled?
Here is the code:
def water_fall_1(x,y,Z):
#x=[...]
#y=[...]
#Z=[[z1],[z2],...z[ny]]
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
from mpl_toolkits.mplot3d import Axes3D
figs=[]
for jc in range(len(y)):
figs.append(list(zip(x,Z[jc])))
x=np.array(x)
y=np.array(y)
Z=np.array(Z)
xmin=np.floor(np.min((x.astype(np.float))))
xmax=np.ceil(np.max((x.astype(np.float))))
ymin=np.min((y.astype(np.float)))
ymax=np.max((y.astype(np.float)))
zmin=(np.min((Z.astype(np.float))))
zmax=np.max((Z.astype(np.float)))
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection(figs, facecolors=colorConverter.to_rgba("r", alpha=0.5))
ax.add_collection3d(poly, zs=y.astype(np.float), zdir='y')
ax.set_xlim(xmin,xmax)
ax.set_ylim(ymin,ymax)
ax.set_zlim(zmin,zmax)
ax.set_xlabel('$\omega$')
ax.set_ylabel('$T$')
#ax.set_zlabel('$\\frac{1}{2}$')
plt.show()
The curve is fully filled. I.e. the surface in between the points of the curve is red.
Consider the following example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
from mpl_toolkits.mplot3d import Axes3D
bottom=-0.3
x = np.linspace(0,6, num=50)
z = np.sinc(x-4)
verts = zip(x,z)
#verts=verts + [(x.max(),bottom),(x.min(),bottom)]
fig=plt.figure()
ax = Axes3D(fig)
poly = PolyCollection([verts], facecolors="r", alpha=0.5)
ax.add_collection3d(poly, zs=1, zdir='y')
ax.set_xlim(x.min(),x.max())
ax.set_ylim(0,2)
ax.set_zlim(bottom,z.max())
plt.show()
which produces the following plot, where everything between the points of the curve is filled as expected.
If we now want to have the area between the curve and some bottom line filled, we would need to add some points,
verts=verts + [(x.max(),bottom),(x.min(),bottom)]
such that the bottom line is part of the curve and can thus be filled as well.

Smoothed 2D histogram using matplotlib and imshow

I try to do a 2D histogram plot and to obtain a "smooth" picture by a sort of interpolation. Thus I do the following combining plt.hist2d and plt.imshow
import matplotlib.pyplot as plt
import numpy as np
data = np.loadtxt("parametre_optMC.dat", skiprows=50, usecols=(1,2))
h, x, y, p = plt.hist2d(data[:,0], data[:,1], bins = 20)
plt.imshow(h, origin = "lower", interpolation = "gaussian")
plt.savefig("test.pdf")
As you can see on the picture below, the two plots are superimposed and that is the problem for which I need some help
Adding clf works but I lose axes dimenions :
import matplotlib.pyplot as plt
import numpy as np
data = np.loadtxt("parametre_optMC.dat", skiprows=50, usecols=(1,2))
h, x, y, p = plt.hist2d(data[:,0], data[:,1], bins = 20)
plt.clf()
plt.imshow(h, origin = "lower", interpolation = "gaussian")
plt.savefig("test.pdf")
Perhaps it would be better to plot a kernel density estimate?
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
data = np.random.multivariate_normal([0, 0], [(1, .6), (.6, 1)], 100)
f, ax = plt.subplots(figsize=(7, 7))
sns.kdeplot(data, shade=True, ax=ax)
To your first question:
You need to clear data from a previous plot, putting the following before you plot should do this:
plt.clf()
plt.close()
To your second question:
To change the axis values I'd suggest the extent parameter (see this answer).
e.g. something like:
plt.imshow(h, origin = "lower", interpolation = "gaussian",extent=[-100,100,-75,75])
You need to add the 'extent' parameter to you imshow command. imshow accepts a grid of arbitrary values but does not know the dimensions.

Categories