I am trying to plot profiles from an interpolated data. To begin with my data is three columns x,y,c.
First I interpolate the data onto a regular grid using:
xi , yi = np.linspace(np.min(X), np.max(X),300) , np.linspace(np.min(Y), np.max(Y),300)
xi, yi = np.meshgrid(xi, yi)
zi = scipy.interpolate.griddata((X, Y), C , (xi, yi),method='nearest')
now following the thread: How to extract an arbitrary line of values from a numpy array?
I want to plot the values at X = 5 for Y = -4,4
x0, y0 = 5, -4 # These are in _pixel_ coordinates!!
x1, y1 = 5, 4
num = 50
x, y = np.linspace(x0, x1, num), np.linspace(y0, y1, num)
#Getting values at that location
zi2 = scipy.ndimage.map_coordinates(np.transpose(zi), np.vstack((x,y)))
#Plotting
fig, axes = plt.subplots(nrows=2)
axes[0].imshow(zi, vmin=np.min(C), vmax=110, origin='lower',extent= [np.min(X), np.max(X), np.min(Y), np.max(Y)])
axes[0].plot([x0, x1], [y0, y1], 'ro-')
axes[0].axis('image')
axes[1].plot(y,zi2)
plt.show()
I get the following plot which is not looking the same as the way contour is behaving.
Related
I am trying to achieve a plot like the one shown bellow:
The code I am using is the following:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.tri as tri
from matplotlib.colors import Normalize
# Example usage
x = np.linspace(0, 10, 500)
f1 = lambda x: x**2
f2 = lambda x: 3*x**1.4
f3 = lambda x: 2*x**1.2
f4 = lambda x: 2*x**1
X = f1(x)
Y = f2(x)
Z = f3(x)
Z1 = f4(x)
# Find the indices of the non-nan values
valid_indices = np.logical_not(np.logical_or(np.isnan(X), np.logical_or(np.isnan(Y), np.isnan(Z))))
# Use the non-nan indices to index into the arrays
x = X[valid_indices]
y = Y[valid_indices]
z = Z[valid_indices]
z1 = Z1[valid_indices]
# Create grid values first.
ngridx = 300
ngridy = 300
xi = np.linspace(x.min(), x.max(), ngridx)
yi = np.linspace(y.min(), y.max(), ngridy)
# Perform linear interpolation of the data (x,y)
# on a grid defined by (xi,yi)
triang = tri.Triangulation(x, y)
interpolator_z = tri.LinearTriInterpolator(triang, z)
interpolator_z1 = tri.LinearTriInterpolator(triang, z1)
Xi, Yi = np.meshgrid(xi, yi)
zi = interpolator_z(Xi, Yi)
z1i = interpolator_z1(Xi, Yi)
X, Y, Z, Z1 = xi, yi, zi, z1i
fig = plt.gcf()
ax1 = fig.add_subplot(111, projection='3d')
minn, maxx = z1.min(), z1.max()
norm = Normalize()
surf = ax1.plot_surface(X,Y,Z, rstride=1, cstride=1, facecolors=cm.jet(norm(Z1)), vmin=minn, vmax=maxx, shade=False)
#surf =ax.plot_trisurf(X,Y,Z, triangles=tri.triangles, cmap=plt.cm.Spectral)
m = cm.ScalarMappable(cmap=cm.jet)
m.set_array(Z1)
The result I am getting is close but not quite what I want:
I am looking to get something that looks closer to this:
Any ideas on how I could improve my result?
I am trying to generate 2D line plots at different angles or slices of a matplotlib contourf plot.
As an example from the matplotlib contourf demo example below
import numpy as np
import matplotlib.pyplot as plt
origin = 'lower'
delta = 0.025
x = y = np.arange(-3.0, 3.01, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
nr, nc = Z.shape
fig1, ax2 = plt.subplots(constrained_layout=True)
CS = ax2.contourf(X, Y, Z, 10, cmap=plt.cm.viridis, origin=origin,extend='both')
ax2.set_title('Random Plot')
ax2.set_xlabel('X Axis')
ax2.set_ylabel('Y Axis')
cbar = fig1.colorbar(CS)
Ideally, I want to generate lines at different angles (30,45,60 degrees) across the map (starting at any arbitrary point till the end of existing array) and then plot the Z variations across that line.
I think a simpler problem in principle would be, lines from (X2,Y2) to (X1,Y1) and plot the Z variation for the given contour (which is already interpolated data).
As an example, original problem would be line from (-3,-3) at angle 45 deg across. Analogous problem would be lets say a line from (-3,-3) to (3,3) and plot the Z variation at different locations on that line.
The source contour plot generated is :
Here is a rather inefficient approach, but it does the job. It recalculates the function on a new grid of which it only needs the diagonal.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import RectBivariateSpline
delta = 0.025
x = y = np.arange(-3.0, 3.01, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X ** 2 - Y ** 2)
Z2 = np.exp(-(X - 1) ** 2 - (Y - 1) ** 2)
Z = (Z1 - Z2) * 2
nr, nc = Z.shape
x1, y1 = -3, -2
x2, y2 = 3, 2
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(15, 5))
CS = ax1.contourf(X, Y, Z, 10, cmap=plt.cm.viridis, origin='lower', extend='both')
ax1.plot([x1, x2], [y1, y2], color='k', ls='--', lw=3, alpha=0.6)
ax1.set_xlabel('X Axis')
ax1.set_ylabel('Y Axis')
cbar = fig.colorbar(CS, ax=ax1)
spline_func = RectBivariateSpline(x, y, Z)
xline = np.linspace(x1, x2, 200)
yline = np.linspace(y1, y2, 200)
zline = spline_func(xline, yline)
ax2.plot(xline, zline.diagonal())
ax2.set_xlabel('X Axis')
ax2.set_ylabel('Z Axis')
plt.show()
I am using the following code in order to smooth my data
a = get_data()
y, x = a.T
t = np.linspace(0, 1, len(x))
t2 = np.linspace(0, 1, len(x))
x2 = np.interp(t2, t, x)
y2 = np.interp(t2, t, y)
sigma = 50
x3 = gaussian_filter1d(x2, sigma)
y3 = gaussian_filter1d(y2, sigma)
x4 = np.interp(t, t2, x3)
y4 = np.interp(t, t2, y3)
plt.plot(x, y, "o-", lw=2)
plt.plot(x3, y3, "r", lw=2)
plt.plot(x4, y4, "o", lw=2)
plt.show()
I found this code here:
line smoothing algorithm in python?
My problem is that I need to get points from the new fit which are exactly with the same x values as my original x values (the points that I have smoothed).
The fit works well but the x values of the new points are different.
How can I get points from the new fit which has the same x value but with the new fit y values. The x values for the points starts from 0 and the space between each one should be 1800.
I think what is particular to your case is that the data to smooth are like a free line in the plane (x, y) = f(t) rather than a function y = f(x)
Maybe the trick is that the points have to be sorted before the interpolation (see numpy.interp):
# Generate random data:
t = np.linspace(0, 3, 20)
x = np.cos(t) + 0.1*np.random.randn(np.size(t))
y = np.sin(t) + 0.1*np.random.randn(np.size(t))
# Smooth the 2D data:
sigma = 2
x_smooth = gaussian_filter1d(x, sigma)
y_smooth = gaussian_filter1d(y, sigma)
# Sort (see: https://stackoverflow.com/a/1903579/8069403)
permutation = x_smooth.argsort()
x_smooth = x_smooth[permutation]
y_smooth = y_smooth[permutation]
x_new = np.sort(x) # not mandatory
# Interpolation on the original x points:
y_smooth_new = np.interp(x_new, x_smooth, y_smooth)
# Plot:
plt.plot(x, y, label='x, y');
plt.plot(x_smooth, y_smooth, label='x_smooth, y_smooth');
plt.plot(x_new, y_smooth_new, '-ro', label='x_new, Y_smooth_new', alpha=0.7);
plt.legend(); plt.xlabel('x');
My goal is to plot the probability distribution functions (pdfs) of two classes. Each class has Gaussian likelihood and equivalent covariance matrices, but different mean vectors. I want both pdfs on the same plane in the z-axis, with the x and y axes containing the projections of the pdfs.
The following code (mostly borrowed from here) plots one of the pdfs:
# Our 2-dimensional distribution will be over variables X and Y
N = 100
X = np.linspace(-10, 15, N)
Y = np.linspace(-10, 15, N)
X, Y = np.meshgrid(X, Y)
# Mean vector and covariance matrix
mu1 = np.array([8, 2])
mu2 = np.array([2,8])
Sigma1 = Sigma2 = np.array([[4.1,0],[0,2.8]])
# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y
F1 = multivariate_normal(mu1, Sigma1)
F2 = multivariate_normal(mu2, Sigma2)
Z1 = F1.pdf(pos)
Z2 = F2.pdf(pos)
# Create a surface plot and projected filled contour plot under it.
fig1 = plt.figure(figsize=[10,10])
ax1 = fig1.gca(projection='3d')
ax1.plot_surface(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno)
cset = ax1.contourf(X, Y, Z1, zdir='z', offset=-0.15, cmap=cm.inferno)
# Adjust the limits, ticks and view angle
ax1.set_zlim(-0.15,0.2)
ax1.set_zticks(np.linspace(0,0.2,5))
ax1.view_init(27, -21)
plt.show()
This is the plot that results from the above code: plot_surfaces for plotting bivariate pdf. However, I need to plot both Z1 and Z2 on the same plane. If I try creating two plots, they overlap and the Z2 pdf cannot be seen. Tweaking the code slightly, I get roughly what I want:
ax1 = fig1.gca(projection='3d')
ax2 = fig1.gca(projection='3d')
ax1.plot_wireframe(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno)
ax2.plot_wireframe(X,Y,Z2,rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno)
the resulting plot of which can be found here: wireframe method to plot 2 bivariate pdfs. But these plots are still overlapping. How can I get around this issue? I want the result to be styled as the first plot, with the surface_plot method and projections on the x-y plane.
You can play with alpha:
ax1.plot_surface(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno, alpha = 0.5)
ax1.plot_surface(X, Y, Z2, rstride=3, cstride=3, linewidth=1,
antialiased=True,cmap=cm.inferno, alpha = 1)
cset = ax1.contourf(X, Y, Z1, zdir='z', offset=-0.15, cmap=cm.inferno, alpha=1)
cset = ax1.contourf(X, Y, Z2, zdir='z', offset=-0.15, cmap=cm.inferno, alpha=0.5)
But in some cases you can get the same results by just summing your pdf's
ax1.plot_surface(X, Y, Z1 + Z2, rstride=3, cstride=3, linewidth=1, antialiased=True,cmap=cm.inferno)
cset = ax1.contourf(X, Y, Z1 + Z2, zdir='z', offset=-0.15, cmap=cm.inferno)
I have a set of data for that I need identify patterns, so I tried to use plt.contours and plt.contourf for that task and it works well, now I can plot contours and show graphically the overdensity among the data. In this step, I tried to get the information of the surface contours (I mean, save the values that define the contour in a variable to use it later.) without success: Is there a way to do this?
Also, I have doubts of what does the values in the color bar means, I know that is the level of overdensity of the data, but if someone could tell me more details, would be great.
I attach the code that I'm using so far (I generate the data in this case), and a plot of the code.
import scipy.interpolate
import numpy as np
import scipy.stats as st
import matplotlib.pyplot as plt
np.random.seed(20)
data = np.random.rand(400,2)
x = data[:,0]
y = data[:,1]
plt.figure(figsize=(12,7))
# Set up a regular grid of points
xi, yi = np.linspace(x.min(), x.max(), 100), np.linspace(y.min(), y.max(), 100)
xi, yi = np.meshgrid(xi, yi)
#contours:
n_contours = 6
positions = np.vstack([xi.ravel(), yi.ravel()])
values = np.vstack([x, y])
kernel = st.gaussian_kde(values)
f = np.reshape(kernel(positions).T, xi.shape)
cfset = plt.contourf(xi, yi, f,n_contours, cmap='Greens')
cset = plt.contour(xi, yi, f,n_contours, colors='k')
#For the points data:
positions = np.vstack([x.ravel(), y.ravel()])
values = np.vstack([x, y])
kernel = st.gaussian_kde(values)
z = np.reshape(kernel(positions).T, x.shape)
#plot:
plt.scatter(x, y, c=z)
plt.colorbar(cfset)
plt.show()
thanks!
EDIT:
I founded a way to do this, using the get_paths() feature, so basically, you need to choose the contour, and then the number of the segment that you need to get the values (x,y), for example:
#contour 3, section 0
p = cset.collections[3].get_paths()[0]
v = p.vertices
x0 = v[:,0]
y0 = v[:,1]
#contour 3, section 1
p = cset.collections[3].get_paths()[1]
v = p.vertices
x1 = v[:,0]
y1 = v[:,1]
#contour 3, section 2
p = cset.collections[3].get_paths()[2]
v = p.vertices
x2 = v[:,0]
y2 = v[:,1]
plt.plot(x0,y0,'-',x1,y1,'-',x2,y2,'-')
With this, you get: