Fitting 3D data to a line in python - python

I want to fit a 3D plot to a line in python. A minimal example is the following:
from pylab import *
import numpy as np
import matplotlib.image as img
import matplotlib.pyplot as plt
x = np.arange(-10,10,0.01)
y = np.arange(-1,1,0.01)
[X,Y] = np.meshgrid(x,y)
z = exp(-(X-8*Y+2)**2/10)
fig,ax = plt.subplots()
im = img.NonUniformImage(ax, interpolation='bilinear')
im.set_data(x,y,z)
ax.images.append(im)
ax.set_xlim(-10,10)
ax.set_ylim(-1,1)
fig.colorbar(im, ax=ax)
plt.show()
The figure generated is:
I want to use a line to fit such data, with a weight such that the dark red data has most weight while the dark blue data has least weight. Essentially, I want to find that the curve is x-8y+2=0.
How do I do this? Thanks!

Related

Strange lines appear on pcolormesh in basemap when using a nonzero alpha value

When plotting data using pcolormesh on a basemap projection (or a cartopy projection) I notice strange lines appear when I set the alpha value to less than 1.
Example code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
plt.clf()
dpp =1 # degrees per pixel
lons = np.arange(-180,180+dpp,dpp)
lats = -1*np.arange(-90,90+dpp,dpp)
m = Basemap(projection='robin',lon_0=0)
data = np.random.random((np.size(lats), np.size(lons)))
lons, lats = np.meshgrid(lons, lats)
x, y = m(lons, lats)
im = m.pcolormesh(x, y, x, latlon=False, cmap='RdBu')
#im = m.pcolormesh(lons, lats, data, latlon=True, cmap='RdBu')
m.colorbar(im)
plt.show()
The output shows strange lines appearing:
If I instead set alpha=1 the lines disappear and the behavior is as expected:
Any ideas on how to get pcolormesh to work with a nonzero alpha value?
Use pcolor instead of pcolormesh, it is a bit slower but it does a better job with handling rasterized output. Be sure to set snap = True, this will align the grid to the pixels.
Example
import numpy as np
import matplotlib.pyplot as plt
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = plt.pcolor(lons, lats, lons, cmap='RdBu', alpha=0.5, snap=True)
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
This should work with mpl_toolkits.basemap as well.
The lines in the colorbar are caused by the open issue #1188, as far as I know there is not a work around known which does not involve manually creating the colorbar.
Since it is a global map, I got it to work using imshow instead of pcolor or pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
plt.clf()
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = ax.imshow(lons, transform=ccrs.PlateCarree(),cmap='RdBu', alpha=0.5, extent=[-180,180,-90,90])
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
There is still the issue with the colorbar however.

Generate 3D Surface Map from Skimage Elevation Map (2D numpy.ndarray)

In the skimage Segmentation tutorial, a 3D surface plot of the elevation map generated from the sobel function was plotted.
>>> from skimage.filters import sobel
>>> elevation_map = sobel(coins)
Question: elevation_map appears to be a 2D numpy.ndarray. How do we generate the 3D map shown using this?
This is likely produced using Paraview/VTK;
Try to play around the following:
from skimage import data
from skimage.filters import sobel
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import cm
from scipy.ndimage import zoom
coins = data.coins()
coins = zoom(coins, 10)
elevation_map = sobel(coins)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
m, n=elevation_map.shape
X, Y = np.meshgrid(np.arange(n), np.arange(m))
ax.plot_surface(X, Y, elevation_map, cmap=cm.viridis, antialiased=False)
ax.axis("off")
ax.set_facecolor('black')
plt.show()

Matplotlib: transformation of variables for narrow orbit

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

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