Plotting piecewise contour graph in Python - python

I want to plot a piecewise function in Python where there are two variables x and y. This means I would need some kind of contour graph. In Matlab one may use
syms x y
eq1 = 0.1*(x/2)^2-0.3*(y/4)^2;
eq2 = 0.15*(x/3)^2-0.25*(y/2)^2;
ezplot(eq1,[-5 5 -10 10]);
hold on
ezplot(eq2,[-4 4 -5 5]);
where ezplot plots eq1 = 0 over xmin < x < xmax and ymin < y < ymax. Is there any (simple) equivalent function(s) in Python?
I have looked at the solutions in this post. Their problem only involves one variable x so it's not helpful in my case.

You can separate the different pieces by using numpy's masked array.
At first define your functions, the x and y ranges and their 2D versions for the contour plot:
import numpy as np
import matplotlib.pyplot as plt
from numpy.ma import masked_array as marr
def eq1(x, y):
return 0.1*(x/2)**2-0.3*(y/4)**2
def eq2(x, y):
return 0.15*(x/3)**2-0.25*(y/2)**2
x = np.linspace(-5, 5, 101)
y = np.linspace(-10, 10, 201)
xx, yy = np.meshgrid(x, y)
Now we need a 2D mask (or some, depending on the number of pieces of the piecewise function) to separate definition ranges of the different pieces of the function:
maskx = ((xx>=-4) * (xx<=4))
masky = ((yy>=-5) * (yy<=5))
mask = maskx * masky
This can be applied to different masked arrays:
res1 = marr(eq1(xx, yy), mask)
res2 = marr(eq2(xx, yy), ~mask)
Plotting a masked array leaves all the area blank where the mask is True:
fig, axs = plt.subplots(1, 2, sharey=True)
axs[0].contour(xx, yy, res1)
axs[0].contour(xx, yy, res2)
axs[0].set_title('contour')
axs[1].contourf(xx, yy, res1)
axs[1].contourf(xx, yy, res2)
axs[1].set_title('contourf')

Related

How to plot this 2D sinusoidal parametric function

I have a 2D sinusoidal function and I want to plot its boundary threshold of t=0. Could someone give me a hint on how to do it?
f (x, y) = sin(10x) + cos(4y) − cos(3xy)
x ∈ [0, 1], y ∈ [0, 2], with a boundary threshold of t = 0
The expected plot should look like this: Plot A dashed lines
Actually the function I am referring to is a toy one from paper "Active Learning For Identifying Function Threshold Boundaries"(https://papers.nips.cc/paper/2005/file/8e930496927757aac0dbd2438cb3f4f6-Paper.pdf)
Page 4 of that paper
Update: I tried the following code but apparently it does not give what I want. The top view is a straight line from (0,0) to (1,2), instead of some curves...
ax = plt.axes(projection='3d')
# Data for a three-dimensional line
xline = np.linspace(0, 1, 1000)
yline = np.linspace(0, 2, 1000)
zline = np.sin(10*xline)+np.cos(4*yline)-np.cos(3*xline*yline)
ax.plot3D(xline, yline, zline, 'gray')
Welcome to stackoverflow. Your math is wrong. Your function f is a function of two variables, f(x, y). Hence you need to evaluate it on a grid (all combinations of valid x and y values), if you want to find the solutions for f = 0 computationally. Your code is currently evaluating f only on the y = 2x axis (hence the "straight line from (0,0) to (1, 2) in top-down view").
import numpy as np
import matplotlib.pyplot as plt
def f(x, y):
return np.sin(10*x)+np.cos(4*y)-np.cos(3*x*y)
x = np.arange(0, 1, 1e-3)
y = np.arange(0, 2, 1e-3)
XX, YY = np.meshgrid(x, y)
ZZ = f(XX, YY)
plt.contour(XX, YY, ZZ, levels=[0.])
plt.show()

How to display a contour plot of a parametrical function in Python?

I have a function g(psi, k) where psi is a two components array and k is a real parameter. I would like to display the g function in a 3D contour plot with respect to the coordinates psi given a selected parameter k. How can I do that in Python?
I tried using the function contour3D with a wrapper function in the following way:
import numpy as np
import matplotlib.pyplot as plt
k = 32 # Change this value to display different plots
# Wrapper of the g function
def f(x, y):
psi = np.array([x, y])
return g(psi, k)
x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.contour3D(X, Y, Z, 50, cmap='binary')
plt.show()
But I get the following error relative to the line Z = f(X, Y):
ValueError: setting an array element with a sequence.
Running simply:
print(f(-0.33, -0.5))
I obtain a real value as expected:
28.08105396614395
How can I fix it? Is there any other way more straightforward to display the plot of g(psi, 32)?
Your function g(psi, k) is probably only working with psi being a 1D array, meaning only accepting x and y being scalars. Either call f in a loop, or vectorize the g function. Here is how to call the function f in a loop:
Z = np.empty(shape=(X.shape))
for row, (xx, yy) in enumerate(zip(X,Y)): # into rows
for col, (xxx, yyy) in enumerate(zip(xx,yy)): # rows to single values
Z[row, col] = f(xxx, yyy)

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:

Contour plot in python [duplicate]

This question already has answers here:
Make contour of scatter
(3 answers)
Closed 5 years ago.
I have 3 lots of data. These are x and y values as well as a temperature value for each xy point. I would like to plot each point and interpolate the area between points to get a continuous surface. The issue I have is specifying the temperature values. I can't get it to work with an equal number of x,y and z (temperature) values and all the examples I can find online use a function of x and y to create z or have z values for every point on an xy grid.
Is there a simple way to do this?
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots()
x = np.linspace(0, 1, 100)
y = np.linspace(0,1,100)
X, Y = np.meshgrid(x, y)
#Z = np.sin(X)*np.sin(Y) # want to specify not an equation
Z = np.linspace(1,2,100)
levels = np.linspace(-1, 1, 40)
cs = axs.contourf(X, Y, Z, levels=levels)
fig.colorbar(cs, ax=axs, format="%.2f")
plt.show()
Update:
Here is what I have so far. I still need to work out a good method to fill in the area between points. Does anyone have any ideas?
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots()
# create a grid in the correct shape / size
x = np.linspace(0, 1, 3)
y = np.linspace(0,1,3)
X, Y = np.meshgrid(x, y)
# specify and change the relevent areas
y = [1,2,0] # location of point in x direction
x =[2,1,1] #location of point in y direction
z = [40,30,20] #temperature
Z = np.arange(1,10).reshape((3,3))
Z[y,x] = z
levels = np.linspace(0, 40, 40)
cs = axs.contourf(X, Y, Z, levels=levels)
fig.colorbar(cs, ax=axs, format="%.2f")
plt.show()
The reason people use a function of x and y is because your Z value has to be a function of x and y. In your test code Z is 1D but it needs to be 2D to plot the contours.
If you have Z (temperature) values that have the same shape as your x and y coordinates then it should work.
x = np.linspace(0, 1, 100)
y = np.linspace(0,1,100)
X, Y = np.meshgrid(x, y)
#Z = np.sin(X)*np.sin(Y) # want to specify not an equation
Z = np.linspace(1,2,100)
print X.shape
print Z.shape
(100L,100L)
(100L)

Python: How to revolve a surface around z axis and make a 3d plot?

I want to get 2d and 3d plots as shown below.
The equation of the curve is given.
How can we do so in python?
I know there may be duplicates but at the time of posting
I could not fine any useful posts.
My initial attempt is like this:
# Imports
import numpy as np
import matplotlib.pyplot as plt
# to plot the surface rho = b*cosh(z/b) with rho^2 = r^2 + b^2
z = np.arange(-3, 3, 0.01)
rho = np.cosh(z) # take constant b = 1
plt.plot(rho,z)
plt.show()
Some related links are following:
Rotate around z-axis only in plotly
The 3d-plot should look like this:
Ok so I think you are really asking to revolve a 2d curve around an axis to create a surface. I come from a CAD background so that is how i explain things.
and I am not the greatest at math so forgive any clunky terminology. Unfortunately you have to do the rest of the math to get all the points for the mesh.
Heres your code:
#import for 3d
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
change arange to linspace which captures the endpoint otherwise arange will be missing the 3.0 at the end of the array:
z = np.linspace(-3, 3, 600)
rho = np.cosh(z) # take constant b = 1
since rho is your radius at every z height we need to calculate x,y points around that radius. and before that we have to figure out at what positions on that radius to get x,y co-ordinates:
#steps around circle from 0 to 2*pi(360degrees)
#reshape at the end is to be able to use np.dot properly
revolve_steps = np.linspace(0, np.pi*2, 600).reshape(1,600)
the Trig way of getting points around a circle is:
x = r*cos(theta)
y = r*sin(theta)
for you r is your rho, and theta is revolve_steps
by using np.dot to do matrix multiplication you get a 2d array back where the rows of x's and y's will correspond to the z's
theta = revolve_steps
#convert rho to a column vector
rho_column = rho.reshape(600,1)
x = rho_column.dot(np.cos(theta))
y = rho_column.dot(np.sin(theta))
# expand z into a 2d array that matches dimensions of x and y arrays..
# i used np.meshgrid
zs, rs = np.meshgrid(z, rho)
#plotting
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
fig.tight_layout(pad = 0.0)
#transpose zs or you get a helix not a revolve.
# you could add rstride = int or cstride = int kwargs to control the mesh density
ax.plot_surface(x, y, zs.T, color = 'white', shade = False)
#view orientation
ax.elev = 30 #30 degrees for a typical isometric view
ax.azim = 30
#turn off the axes to closely mimic picture in original question
ax.set_axis_off()
plt.show()
#ps 600x600x600 pts takes a bit of time to render
I am not sure if it's been fixed in latest version of matplotlib but the setting the aspect ratio of 3d plots with:
ax.set_aspect('equal')
has not worked very well. you can find solutions at this stack overflow question
Only rotate the axis, in this case x
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d
np.seterr(divide='ignore', invalid='ignore')
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.linspace(-3, 3, 60)
rho = np.cosh(x)
v = np.linspace(0, 2*np.pi, 60)
X, V = np.meshgrid(x, v)
Y = np.cosh(X) * np.cos(V)
Z = np.cosh(X) * np.sin(V)
ax.set_xlabel('eje X')
ax.set_ylabel('eje Y')
ax.set_zlabel('eje Z')
ax.plot_surface(X, Y, Z, cmap='YlGnBu_r')
plt.plot(x, rho, 'or') #Muestra la curva que se va a rotar
plt.show()
The result:

Categories