Projecting plane onto new coordinate system - python

Say I have a grid
xGrid = np.linspace(0.1, 1, 10)
yGrid = np.linspace(5, 10, 5)
and some data on that grid:
X, Y = np.meshgrid(xGrid, yGrid, indexing='ij')
Z = X*Y + 1
I could easily now plot Z(x, y). Now, there is a transformation t(x, y):
T = X+1+Y/2
and I would like to plot Z(t(x, y), y) instead. To do that, I need to project my Z data onto the t(x,y)-y plane. What'd be the best way of doing that?
Since I ultimately want to plot the data and not do any further work with it, direct methods of doing this in matplotlib (but actually drawing onto the correct new coordinates, not just relabeling the ticks) are also accepted.

You can use interpolation to compute the values in the projection, for example with scipy.interpolate.RectBivariateSpline:
import numpy as np
import scipy.interpolate
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
xGrid = np.linspace(0.1, 1, 10)
yGrid = np.linspace(5, 10, 5)
X, Y = np.meshgrid(xGrid, yGrid, indexing='ij')
Z = X * Y + 1
T = X + 1 + Y / 2
# Interpolate values
interp = scipy.interpolate.RectBivariateSpline(xGrid, yGrid, Z)
Zt = interp.ev(T.ravel(), Y.ravel()).reshape(Z.shape)
# Plot
fig = plt.figure(figsize=(8, 10))
ax1 = fig.add_subplot(211, projection='3d')
ax1.set_title('Original')
ax1.plot_surface(X, Y, Z)
ax2 = fig.add_subplot(212, projection='3d')
ax2.set_title('Projected')
ax2.plot_surface(T, Y, Zt)
fig.tight_layout()
Output:

If I understand your problem you could use pcolormesh that can be used for non regular meshes
In [8]: import numpy as np
...: import matplotlib.pyplot as plt
...: from matplotlib.collections import PatchCollection, QuadMesh
...: from matplotlib.patches import Rectangle
...:
...: np.random.seed(2018)
...: xGrid = np.linspace(0.1, 1, 10)
...: yGrid = np.linspace(5, 10, 6)
...: X, Y = np.meshgrid(xGrid, yGrid, indexing='ij')
...: Z = X*Y + 1
...: T = X+1+Y/2
...: Zt = T*Y + 1
...: plt.pcolormesh(T, Y, Zt)
...: plt.colorbar()
Out[8]: <matplotlib.colorbar.Colorbar at 0x7fda83cd4ef0>
that produces
If the bands are too ugly use plt.pcolormesh(T, Y, Zt, shading='gouraud')

Related

How to plot a one to many function on matplotlib in python

Very simple, if I plot x^2+y^2=z it makes this shape on python it will make this shape:
When I would like to plot it this way:
Below is my code, I am new so I copied it from the internet and have changed the line with the function to plot.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-4*np.pi,4*np.pi,50)
y = np.linspace(-4*np.pi,4*np.pi,50)
z = x**2+y**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x,y,z)
plt.show()
Also, how do I make it more high definition and smooth, this is a graph of z=sin(x)
You need to define a 2D mathematical domain with numpy.meshgrid, then you can compute the surface on that domain:
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
In order to increase the smoothness of the surface, you have in increase the number of point N you use to compute x and y arrays:
Complete code
import matplotlib.pyplot as plt
import numpy as np
N = 50
x = np.linspace(-4*np.pi, 4*np.pi, N)
y = np.linspace(-4*np.pi, 4*np.pi, N)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z)
plt.show()

Matplotlib contour hatching not working if only two levels was used

I am trying to plot hatches over contours lines that
statisfy certian criteria folliwng the example found here. Yet, I got regular contours (the yellow lines) instead of the hatches. Any ideas how to resolve that. Thanks
import matplotlib.pyplot as plt
import numpy as np
# invent some numbers, turning the x and y arrays into simple
# 2d arrays, which make combining them together easier.
x = np.linspace(-3, 5, 150).reshape(1, -1)
y = np.linspace(-3, 5, 120).reshape(-1, 1)
z = np.cos(x) + np.sin(y)
# we no longer need x and y to be 2 dimensional, so flatten them.
x, y = x.flatten(), y.flatten()
fig2, ax2 = plt.subplots()
n_levels = 6
a=ax2.contourf(x, y, z, n_levels)
fig2.colorbar(a)
[m,n]=np.where(z > 0.5)
z1=np.zeros(z.shape)
z1[m,n]=99
cs = ax2.contour(x, y, z1,2,hatches=['','.'])
plt.show()enter code here
Use contourf() with proper parameters to get useful plot with hatching. See important comment within the working code below:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 5, 150).reshape(1, -1)
y = np.linspace(-3, 5, 120).reshape(-1, 1)
z = np.cos(x) + np.sin(y)
x, y = x.flatten(), y.flatten()
fig2, ax2 = plt.subplots()
n_levels = 6
a = ax2.contourf(x, y, z, n_levels)
fig2.colorbar(a)
[m,n] = np.where(z > 0.5)
z1=np.zeros(z.shape)
z1[m, n] = 99
# use contourf() with proper hatch pattern and alpha value
cs = ax2.contourf(x, y, z1 ,3 , hatches=['', '..'], alpha=0.25)
plt.show()
The output plot:

How to draw a perturbed circle?

How do I draw a Perturbed Circle?
import matplotlib.pyplot as plt
import numpy as np
e=0.3
ylist = np.linspace(0, 2*np.pi, 20)
R=1+e*np.sin(2*ylist)
circle1 = plt.Circle((0, 0),R)
fig, ax = plt.subplots()
ax.add_artist(circle1)
plt.axis([-3, 3, -3, 3])
You cannot set a list as radius to a Circle.
There might be other methods to draw a "disturbed" circle, but I find it very intuitive to draw a parametric curve using plt.contour().
The parametric curve for a perfect circle with radius R would be
0 = x**2 + y**2 - R
while in this case it's
0 = x**2 + y**2 - 1 -e*np.sin(2*np.arctan(y/x)) =: f
So we can plot f(x,y) and in the call to contour(X,Y,Z, levels) we set levels to 0.
import matplotlib.pyplot as plt
import numpy as np
e=0.3
x = np.linspace(-3.0, 3.0, 101)
X, Y = np.meshgrid(x, x)
f = lambda x,y: x**2 + y**2 - 1 -e*np.sin(2*np.arctan(y/x))
fig, ax = plt.subplots(figsize=(3,3))
ax.contour(X,Y, f(X, Y), 0)
plt.axis([-2, 2, -2, 2])
plt.gca().set_aspect("equal")
plt.axis('off')
plt.savefig(__file__+".png")
plt.show()

Plotting vertical cylindrical surfaces

Provided we have a contour on the xy plane, how can we plot "a curtain" raised from the contour to the limiting surface?
An example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
def figure():
fig = plt.figure(figsize=(8,6))
axes = fig.gca(projection='3d')
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
x, y = np.meshgrid(x, y)
t1 = np.linspace(0, 8/9, 100)
x1 = t1
y1 = (2*t1)**0.5
f1 = lambda x, y: y
plt.plot(x1, y1)
axes.plot_surface(x, y, f1(x, y),color ='red', alpha=0.1)
axes.set_xlim(-2,2)
axes.set_ylim(-2,2)
figure()
How to plot a surface from the given line to the limiting surface?
Somebody wanted help plotting an intersection here cylinder "cuts" a sphere in python you could use the vertical cylinder part. It uses u, v parameters to generate x, y, z values

Contour plot in Python importing txt table file

I am trying to make a contour plot like:
Using a table of data like 3 columns in a txt file, with a long number of lines.
Using this code:
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate
data = np.loadtxt(r'dataa.txt')
a = [data[:,0]]
b = [data[:,1]]
n = [data[:,2]]
x = np.asarray(a)
y = np.asarray(b)
z = np.asarray(n)
print "x = ", x
print "y = ", y
print "z = ", z
fig=plt.figure()
CF = contour(x,y,z,colors = 'k')
plt.xlabel("X")
plt.ylabel("Y")
plt.colorbar()
plt.show()
I don't know why, it is not working. Python gives me the right axes for the values that I am expecting to see, but in the graph is just a blank and I know that it is importing the data in right way because it shows me my values before the plot.
Example of table: (the diference is because my table has 90000 lines)
Using this code:
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate
N = 1000 #number of points for plotting/interpolation
x, y, z = np.genfromtxt(r'dataa.txt', unpack=True)
xi = np.linspace(x.min(), x.max(), N)
yi = np.linspace(y.min(), y.max(), N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
fig = plt.figure()
plt.contour(xi, yi, zi)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
Ive got this result:
I think I've got the advices wrongly.
Followup from my comment... first, I would replace all these lines:
data = np.loadtxt(r'dataa.txt')
a = [data[:,0]]
b = [data[:,1]]
n = [data[:,2]]
x = np.asarray(a)
y = np.asarray(b)
z = np.asarray(n)
With:
x, y, z = np.genfromtxt(r'dataa.txt', unpack=True)
Your original code is adding an extra axis at the front, since [data[:,0]] is a list of arrays with one element. The result is that x.shape will be (1, N) instead if (N,). All of this can be done automatically using the last line above, or you could just use the same data loading and say:
x = data[:,0]
y = data[:,1]
z = data[:,2]
since those slices will give you an array back.
However, you're not quite done, because plt.contour expects you to give it a 2d array for z, not a 1d array of values. Right now, you seem to have z values at given x, y points, but contour expects you to give it a 2d array, like an image.
Before I can answer that, I need to know how x and y are spaced. If regularly, you can just populate an array pretty easily. If not regularly, you basically have to interpolate before you can make a contour plot.
To do the interpolation, use
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate
N = 1000 #number of points for plotting/interpolation
x, y, z = np.genfromtxt(r'dataa.txt', unpack=True)
xi = np.linspace(x.min(), x.max(), N)
yi = np.linspace(y.min(), y.max(), N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
fig = plt.figure()
plt.contour(xi, yi, zi)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
The code below worked for me:
import scipy.interpolate
import numpy as np
N = 500 #number of points for plotting/interpolation
x, y, z = np.genfromtxt(r'data.dat', unpack=True)
xll = x.min(); xul = x.max(); yll = y.min(); yul = y.max()
xi = np.linspace(xll, xul, N)
yi = np.linspace(yll, yul, N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
contours = plt.contour(xi, yi, zi, 6, colors='black')
plt.clabel(contours, inline=True, fontsize=7)
plt.imshow(zi, extent=[xll, xul, yll, yul], origin='lower', cmap=plt.cm.jet, alpha=0.9)
plt.xlabel(r'$x$')
plt.ylabel(r'$y$')
plt.clim(0, 1)
plt.colorbar()
plt.show()

Categories