Conditional contour plot - python

The below code is what I'm playing around with at the minute:
x = np.linspace(0,30,1000)
y = np.linspace(0,30,1000)
X,Y = np.meshgrid(x,y)
def f(x,y):
return x**2 + y**2
Z = f(X,Y)
plt.contour(X, Y, Z, colors='black');
I want this plot to display some forbidden region, say when f(x,y) < 9;
I want this shaded in and added to the plot.
How exactly would I do this?
I've tried using plt.contourf but I can't quite get it working.

I think you can do it this way using contourf, use contourf to fill with a solid color red then mask the region you want to display with your contour chart:
x = np.linspace(0,30,1000)
y = np.linspace(0,30,1000)
X,Y = np.meshgrid(x,y)
def f(x,y):
return x**2 + y**2
Z = f(X,Y)
d = np.ma.array(Z, mask=Z>9)
plt.contour(X, Y, Z, colors='black')
plt.contourf(X, Y, d, colors='red');
Output:

Related

Changing the origin of a 3d plot

I am trying to graph a 3d plot of the function f(x,y,z) = cos(x) + cos(y) + cos(z). I found a code off here that I copied and pasted and it looked like this.
def fun(x, y, z):
return cos(x) + cos(y) + cos(z)
x, y, z = pi*np.mgrid[-1:1:31j, -1:1:31j, -1:1:31j]
vol = fun(x, y, z)
iso_val=0.0
verts, faces, _, _ = measure.marching_cubes(vol, iso_val, spacing=(0.1, 0.1, 0.1))
fig = plt.figure(figsize = (10,6))
ax = fig.add_subplot(111, projection='3d')
p = ax.plot_trisurf(verts[:, 0], verts[:,1], faces, verts[:, 2],
cmap='Spectral', lw=1)
fig.colorbar(p, ax=ax, pad = 0.1)
plt.show()
Then, I noticed that it the labels in xyz and I want the origin to be on the center of the plot and not on the corners (kind of like this)
I don't want to just mess with the labels of the graph, I want the array to reflect that the origin has been changed. I don't know how to do this, like, do I just subtract -1.5 on everything to center the whole plot?

Tricontourf changing the boundary of my plot

I am trying to use tricontourf to make a horizontal velocity contour plot for a metal rolling setup. Basically, the boundaries on the top and bottom of my horizontal velocity plot should be round but they are not because of tricontourf. Does anyone know how to fix this?
`
desired_quantity = "v_x"
x = df[["deformed_x"]].to_numpy()
x = np.transpose(x)
x = x.flatten()
y = df[["deformed_y"]].to_numpy()
y = np.transpose(y)
y = y.flatten()
z = df[[desired_quantity]].to_numpy()
z = np.transpose(z)
z = z.flatten()
y = y - y.min()
plt.figure(figsize=(12.6, 6))
levels = 18
plt.tricontourf(x, y, z, levels = levels)
plt.tricontourf(x, -1*y, z, levels = levels)
plt.colorbar()
plt.title(desired_quantity)
plt.show()`

How can I get Isocontour's xy coordinates for contour plot?

I am trying to get isosurface's x-y coordinates from 3D plot. Here is my attempt;
import matplotlib.pyplot as plt
from numpy import pi, cos, sin, linspace, meshgrid
x = linspace(0,50,1000)
y = linspace(0,50,1000)
n = 5
L = 50
t = 0
def gyroid(x, y, n, L, t):
tanım1 = (sin(2*pi*n*x/L) * cos(2*pi*n*y/L) + sin(2*pi*n*y/L) + cos(2*pi*n*x/L))
return tanım1*tanım1 - t**2
XX, YY = meshgrid(x, y)
z = gyroid(XX, YY, n, L, t)
thickness = 0.1
contour = plt.contour(XX, YY, z,levels=[thickness])
# Attempt to get x-y coordinates
dat0= contour.allsegs[0][0]
plt.plot(dat0[:,0],dat0[:,1])
The gyroid function is normally looks like;
3D plot
I am getting isocontour for z = 0.1 plane;
Void plot
I need xy pairs of these voids. But when I try, the code is only getting lower left coordinates.
It is clear that function is strongly nonlinear, but is there any way to retrieve these coordinates?
Thanks for your responses in advance.
You specify contour.allsegs[0][0] so you get the very first line of the first contour line.
for lines in contour.allsegs:
for line in lines:
X, Y = line[:,0], line[:,1]
plt.plot(X, Y)

matplotlib wireframe plot / 3d plot howTo

I would like to have a 3d plot with matplotlib.
Data are the following: I have a matrix with each row containing Y coordinates for the 3d plot. Each row first elements are the X coordinates for the 3d plot. Finally, a second matrix contains high for each point, at a X,Y position. This second matrix thus contains my Z coordinates. Both matrices are arrays of arrays with Python. I would like to know how to transform data so as to obtain:
a plot of each 1d signal corresponding to an X, like this (photo available online)
a wireframe plot for same data, like this
I have written an helper function for a wireframe work,
######## HELPER FOR PLOT 3-D
def plot_3d(name,X,Y,Z):
fig = plt.figure(name)
ax = fig.gca(projection='3d')
X = np.array(X)
Y = np.array(Y)
Z = np.array(Z)
ax.plot_wireframe(X,Y,Z,rstride=10,cstride=10)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
plt.show()
but I dont know how to transform data X,Y,Z to make them fit requirements for matplotlib function, which want 2D lists for X, Y ,Z.
For first graph, I read help, and want to use 2d plot in 3d. Example source code gives:
x = np.linspace(0, 1, 100)
y = np.sin(x * 2 * np.pi) / 2 + 0.5
ax.plot(x, y, zs=0, zdir='z', label='zs=0, zdir=z')
where z is the constant coordinate. In my case, x is the constant coordinate. I adapt with
fig = plt.figure('2d profiles')
ax = fig.gca(projection='3d')
for i in range(10):
x = pt ## this is a scalar
y = np.array(y)
z = np.array(z)
ax.plot(xs = x, y, z, xdir='x')
plt.show()
but there is warning: non-keyword arg after keyword arg. How to fix?
Thanks and regards
Regarding the display of a serie of vectors in 3D, I came with following 'almost working' solution:
def visualizeSignals(self, imin, imax):
times = self.time[imin:imax]
nrows = (int)((times[(len(times)-1)] - times[0])/self.mod) + 1
fig = plt.figure('2d profiles')
ax = fig.gca(projection='3d')
for i in range(nrows-1):
x = self.mat1[i][0] + self.mod * i
y = np.array(self.mat1T[i])
z = np.array(self.mat2[i])
ax.plot(y, z, zs = x, zdir='z')
plt.show()
As for 2D surface or meshgrid plot, I come through using meshgrid. Note that you can reproduce a meshgrid by yourself once you know how a meshgrid is built. For more info on meshgrid, I refer to this post.
Here is the code (cannot use it as such since it refers to class members, but you can build your code based on 3d plot methods from matplotlib I am using)
def visualize(self, imin, imax, typ_ = "wireframe"):
"""
3d plot signal between imin and imax
. typ_: type of plot, "wireframce", "surface"
"""
times = self.retT[imin:imax]
nrows = (int)((times[(len(times)-1)] - times[0])/self.mod) + 1
self.modulate(imin, imax)
fig = plt.figure('3d view')
ax = fig.gca(projection='3d')
x = []
for i in range(nrows):
x.append(self.matRetT[i][0] + self.mod * i)
y = []
for i in range(len(self.matRetT[0])):
y.append(self.matRetT[0][i])
y = y[:-1]
X,Y = np.meshgrid(x,y)
z = [tuple(self.matGC2D[i]) for i in range(len(self.matGC))] # matGC a matrix
zzip = zip(*z)
for i in range(len(z)):
print len(z[i])
if(typ_ == "wireframe"):
ax.plot_wireframe(X,Y,zzip)
plt.show()
elif(typ_ == "contour"):
cset = ax.contour(X, Y, zzip, zdir='z', offset=0)
plt.show()
elif(typ_ == "surf_contours"):
surf = ax.plot_surface(X, Y, zzip, rstride=1, cstride=1, alpha=0.3)
cset = ax.contour(X, Y, zzip, zdir='z', offset=-40)
cset = ax.contour(X, Y, zzip, zdir='x', offset=-40)
cset = ax.contour(X, Y, zzip, zdir='y', offset=-40)
plt.show()

How to visualize scalar 2D data with Matplotlib?

So i have a meshgrid (matrices X and Y) together with scalar data (matrix Z), and i need to visualize this. Preferably some 2D image with colors at the points showing the value of Z there.
I've done some research but haven't found anything which does exactly what i want.
pyplot.imshow(Z) has a good look, but it doesn't take my X and Y matrices, so the axes are wrong and it is unable to handle non-linearly spaced points given by X and Y.
pyplot.pcolor(X,Y,Z) makes colored squares with colors corresponding to the data at one of its corners, so it kind of misrepresents the data (it should show the data in its center or something). In addition it ignores two of the edges from the data matrix.
I pretty sure there must exist some better way somewhere in Matplotlib, but the documentation makes it hard to get an overview. So i'm asking if someone else knows of a better way. Bonus if it allows me to refresh the matrix Z to make an animation.
This looks nice, but it's inefficient:
from pylab import *
origin = 'lower'
delta = 0.025
x = y = arange(-3.0, 3.01, delta)
X, Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)
nr, nc = Z.shape
CS = contourf(
X, Y, Z,
levels = linspace(Z.min(), Z.max(), len(x)),
ls = '-',
cmap=cm.bone,
origin=origin)
CS1 = contour(
CS,
levels = linspace(Z.min(), Z.max(), len(x)),
ls = '-',
cmap=cm.bone,
origin=origin)
show()
It it were me, I'd re-interpolate (using scipy.interpolate) the data to a regular grid and use imshow(), setting the extents to fix the axes.
Edit (per comment):
Animating a contour plot can be accomplished like this, but, like I said, the above is inefficient just plain abuse of the contour plot function. The most efficient way to do what you want is to employ SciPy. Do you have that installed?
import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab
import time
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
def animate():
origin = 'lower'
delta = 0.025
x = y = arange(-3.0, 3.01, delta)
X, Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)
CS1 = ax.contourf(
X, Y, Z,
levels = linspace(Z.min(), Z.max(), 10),
cmap=cm.bone,
origin=origin)
for i in range(10):
tempCS1 = contourf(
X, Y, Z,
levels = linspace(Z.min(), Z.max(), 10),
cmap=cm.bone,
origin=origin)
del tempCS1
fig.canvas.draw()
time.sleep(0.1)
Z += x/10
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()
If your meshgrid has uniform spacing, you could continue to use pcolor, but just shift X and Y for the purposes of centering the data at the particular values rather than at the corners.
You could also use a scatter plot to explicitly place points of some size at the exact X and Y points and then set the color to Z:
x = numpy.arange(10)
y = numpy.arange(10)
X,Y = numpy.meshgrid(x,y)
Z = numpy.arange(100).reshape((10,10))
scatter(X,Y,c=Z,marker='s',s=1500)
#I picked a marker size that basically overlapped the symbols at the edges
axis('equal')
or:
pcolor(X+0.5,Y+0.5,Z)
axis('equal')
or as Paul suggested, using one of the contour functions
In case anyone comes across this article looking for what I was looking for, I took the above example and modified it to use imshow with an input stack of frames, instead of generating and using contours on the fly. Starting with a 3D array of images of shape (nBins, nBins, nBins), called frames.
def animate_frames(frames):
nBins = frames.shape[0]
frame = frames[0]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
for k in range(nBins):
frame = frames[k]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
del tempCS1
fig.canvas.draw()
#time.sleep(1e-2) #unnecessary, but useful
fig.clf()
fig = plt.figure()
ax = fig.add_subplot(111)
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate_frames, frames)
I also found a much simpler way to go about this whole process, albeit less robust:
fig = plt.figure()
for k in range(nBins):
plt.clf()
plt.imshow(frames[k],cmap=plt.cm.gray)
fig.canvas.draw()
time.sleep(1e-6) #unnecessary, but useful
Note that both of these only seem to work with ipython --pylab=tk, a.k.a.backend = TkAgg
Thank you for the help with everything.
The following function creates boxes of half the size at the boundary (as shown in the attached picture).
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage.filters import convolve
def pcolor_all(X, Y, C, **kwargs):
X = np.concatenate([X[0:1,:], X], axis=0)
X = np.concatenate([X[:,0:1], X], axis=1)
Y = np.concatenate([Y[0:1,:], Y], axis=0)
Y = np.concatenate([Y[:,0:1], Y], axis=1)
X = convolve(X, [[1,1],[1,1]])/4
Y = convolve(Y, [[1,1],[1,1]])/4
plt.pcolor(X, Y, C, **kwargs)
X, Y = np.meshgrid(
[-1,-0.5,0,0.5,1],
[-2,-1,0,1,2])
C = X**2-Y**2
plt.figure(figsize=(4,4))
pcolor_all(X, Y, C, cmap='gray')
plt.savefig('plot.png')

Categories