How draw a surface plot using matlplotlib - python-3.x

I have three variables:
gamma= [0.001, 0.0001]
c= [1, 10, 100, 1000]
f = [9.350473612990527483e-01, 8.848238482384823689e-01, 9.769335142469470767e-01, 8.534599728629578275e-01, 9.198369565217391353e-01, 8.953804347826085364e-01, 9.713506139154161056e-01, 9.836065573770491621e-01]
My question is how can I draw a surface plot using the above variables?

Ok, here is the solution using your gamma, c and f values although the surface looks a bit strange but that's due to your data. Please check the order of data. I assumed it to be np.meshgrid(gamma, c) but it could very well be np.meshgrid(c, gamma). You need to verify that
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
gamma= np.array([0.001, 0.0001])
c= np.array([1, 10, 100, 1000])
X, Y = np.meshgrid(gamma, c)
f = np.array([9.350473612990527483e-01, 8.848238482384823689e-01, 9.769335142469470767e-01, 8.534599728629578275e-01, 9.198369565217391353e-01, 8.953804347826085364e-01, 9.713506139154161056e-01, 9.836065573770491621e-01])
Z = f.reshape(X.shape)
ax.plot_surface(X, Y, Z)
Output

Related

Change colorbar limits without changing the values of the data it represents in scatter

I'm trying to change a colorbar attached to a scatter plot so that the minimum and maximum of the colorbar are the minimum and maximum of the data, but I want the data to be centred at zero as I'm using a colormap with white at zero. Here is my example
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1, 61)
y = np.linspace(0, 1, 61)
C = np.linspace(-10, 50, 61)
M = np.abs(C).max() # used for vmin and vmax
fig, ax = plt.subplots(1, 1, figsize=(5,3), dpi=150)
sc=ax.scatter(x, y, c=C, marker='o', edgecolor='k', vmin=-M, vmax=M, cmap=plt.cm.RdBu_r)
cbar=fig.colorbar(sc, ax=ax, label='$R - R_0$ (mm)')
ax.set_xlabel('x')
ax.set_ylabel('y')
As you can see from the attached figure, the colorbar goes down to -M, where as I want the bar to just go down to -10, but if I let vmin=-10 then the colorbar won't be zerod at white. Normally, setting vmin to +/- M when using contourf the colorbar automatically sorts to how I want. This sort of behaviour is what I expect when contourf uses levels=np.linspace(-M,M,61) rather than setting it with vmin and vmax with levels=62. An example showing the default contourf colorbar behaviour I want in my scatter example is shown below
plt.figure(figsize=(6,5), dpi=150)
plt.contourf(x, x, np.reshape(np.linspace(-10, 50, 61*61), (61,61)),
levels=62, vmin=-M, vmax=M, cmap=plt.cm.RdBu_r)
plt.colorbar(label='$R - R_0$ (mm)')
Does anyone have any thoughts? I found this link which I thought might solve the problem, but when executing the cbar.outline.set_ydata line I get this error AttributeError: 'Polygon' object has no attribute 'set_ydata' .
EDIT a little annoyed that someone has closed this question without allowing me to clarify any questions they might have, as none of the proposed solutions are what I'm asking for.
As for Normalize.TwoSlopeNorm, I do not want to rescale the smaller negative side to use the entire colormap range, I just want the colorbar attached to the side of my graph to stop at -10.
This link also does not solve my issue, as it's the TwoSlopeNorm solution again.
After changing the ylim of the colorbar, the rectangle formed by the surrounding spines is too large. You can make this outline invisible. And then add a new rectangular border:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1, 61)
y = np.linspace(0, 1, 61)
C = np.linspace(-10, 50, 61)
M = np.abs(C).max() # used for vmin and vmax
fig, ax = plt.subplots(1, 1, figsize=(5, 3), dpi=150)
sc = ax.scatter(x, y, c=C, marker='o', edgecolor='k', vmin=-M, vmax=M, cmap=plt.cm.RdBu_r)
cbar = fig.colorbar(sc, ax=ax, label='$R - R_0$ (mm)')
cb_ymin = C.min()
cb_ymax = C.max()
cb_xmin, cb_xmax = cbar.ax.get_xlim()
cbar.ax.set_ylim(cb_ymin, cb_ymax)
cbar.outline.set_visible(False) # hide the surrounding spines, which are too large after set_ylim
cbar.ax.add_patch(plt.Rectangle((cb_xmin, cb_ymin), cb_xmax - cb_xmin, cb_ymax - cb_ymin,
fc='none', ec='black', clip_on=False))
plt.show()
Another approach until v3.5 is released is to make a custom colormap that does what you want (see also https://matplotlib.org/stable/tutorials/colors/colormap-manipulation.html#sphx-glr-tutorials-colors-colormap-manipulation-py)
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.cm as cm
from matplotlib.colors import ListedColormap
fig, axs = plt.subplots(2, 1)
X = np.random.randn(32, 32) + 2
pc = axs[0].pcolormesh(X, vmin=-6, vmax=6, cmap='RdBu_r')
fig.colorbar(pc, ax=axs[0])
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.cm as cm
from matplotlib.colors import ListedColormap
fig, axs = plt.subplots(2, 1)
X = np.random.randn(32, 32) + 2
pc = axs[0].pcolormesh(X, vmin=-6, vmax=6, cmap='RdBu_r')
fig.colorbar(pc, ax=axs[0])
def keep_center_colormap(vmin, vmax, center=0):
vmin = vmin - center
vmax = vmax - center
dv = max(-vmin, vmax) * 2
N = int(256 * dv / (vmax-vmin))
RdBu_r = cm.get_cmap('RdBu_r', N)
newcolors = RdBu_r(np.linspace(0, 1, N))
beg = int((dv / 2 + vmin)*N / dv)
end = N - int((dv / 2 - vmax)*N / dv)
newmap = ListedColormap(newcolors[beg:end])
return newmap
newmap = keep_center_colormap(-2, 6, center=0)
pc = axs[1].pcolormesh(X, vmin=-2, vmax=6, cmap=newmap)
fig.colorbar(pc, ax=axs[1])
plt.show()

Draw curves with triple colors and width by using matplotlib and LineCollection [duplicate]

The figure above is a great artwork showing the wind speed, wind direction and temperature simultaneously. detailedly:
The X axes represent the date
The Y axes shows the wind direction(Southern, western, etc)
The variant widths of the line were stand for the wind speed through timeseries
The variant colors of the line were stand for the atmospheric temperature
This simple figure visualized 3 different attribute without redundancy.
So, I really want to reproduce similar plot in matplotlib.
My attempt now
## Reference 1 http://stackoverflow.com/questions/19390895/matplotlib-plot-with-variable-line-width
## Reference 2 http://stackoverflow.com/questions/17240694/python-how-to-plot-one-line-in-different-colors
def plot_colourline(x,y,c):
c = plt.cm.jet((c-np.min(c))/(np.max(c)-np.min(c)))
lwidths=1+x[:-1]
ax = plt.gca()
for i in np.arange(len(x)-1):
ax.plot([x[i],x[i+1]], [y[i],y[i+1]], c=c[i],linewidth = lwidths[i])# = lwidths[i])
return
x=np.linspace(0,4*math.pi,100)
y=np.cos(x)
lwidths=1+x[:-1]
fig = plt.figure(1, figsize=(5,5))
ax = fig.add_subplot(111)
plot_colourline(x,y,prop)
ax.set_xlim(0,4*math.pi)
ax.set_ylim(-1.1,1.1)
Does someone has a more interested way to achieve this? Any advice would be appreciate!
Using as inspiration another question.
One option would be to use fill_between. But perhaps not in the way it was intended. Instead of using it to create your line, use it to mask everything that is not the line. Under it you can have a pcolormesh or contourf (for example) to map color any way you want.
Look, for instance, at this example:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interp1d
def windline(x,y,deviation,color):
y1 = y-deviation/2
y2 = y+deviation/2
tol = (y2.max()-y1.min())*0.05
X, Y = np.meshgrid(np.linspace(x.min(), x.max(), 100), np.linspace(y1.min()-tol, y2.max()+tol, 100))
Z = X.copy()
for i in range(Z.shape[0]):
Z[i,:] = c
#plt.pcolormesh(X, Y, Z)
plt.contourf(X, Y, Z, cmap='seismic')
plt.fill_between(x, y2, y2=np.ones(x.shape)*(y2.max()+tol), color='w')
plt.fill_between(x, np.ones(x.shape) * (y1.min() - tol), y2=y1, color='w')
plt.xlim(x.min(), x.max())
plt.ylim(y1.min()-tol, y2.max()+tol)
plt.show()
x = np.arange(100)
yo = np.random.randint(20, 60, 21)
y = interp1d(np.arange(0, 101, 5), yo, kind='cubic')(x)
dv = np.random.randint(2, 10, 21)
d = interp1d(np.arange(0, 101, 5), dv, kind='cubic')(x)
co = np.random.randint(20, 60, 21)
c = interp1d(np.arange(0, 101, 5), co, kind='cubic')(x)
windline(x, y, d, c)
, which results in this:
The function windline accepts as arguments numpy arrays with x, y , a deviation (like a thickness value per x value), and color array for color mapping. I think it can be greatly improved by messing around with other details but the principle, although not perfect, should be solid.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.linspace(0,4*np.pi,10000) # x data
y = np.cos(x) # y data
r = np.piecewise(x, [x < 2*np.pi, x >= 2*np.pi], [lambda x: 1-x/(2*np.pi), 0]) # red
g = np.piecewise(x, [x < 2*np.pi, x >= 2*np.pi], [lambda x: x/(2*np.pi), lambda x: -x/(2*np.pi)+2]) # green
b = np.piecewise(x, [x < 2*np.pi, x >= 2*np.pi], [0, lambda x: x/(2*np.pi)-1]) # blue
a = np.ones(10000) # alpha
w = x # width
fig, ax = plt.subplots(2)
ax[0].plot(x, r, color='r')
ax[0].plot(x, g, color='g')
ax[0].plot(x, b, color='b')
# mysterious parts
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
# mysterious parts
rgba = list(zip(r,g,b,a))
lc = LineCollection(segments, linewidths=w, colors=rgba)
ax[1].add_collection(lc)
ax[1].set_xlim(0,4*np.pi)
ax[1].set_ylim(-1.1,1.1)
fig.show()
I notice this is what I suffered.

Using scipy's solve_ivp to solve non linear pendulum motion

I am still trying to understand how solve_ivp works against odeint, but just as I was getting the hang of it something happened.
I am trying to solve for the motion of a non linear pendulum. With odeint, everything works like a charm, on solve_ivp hoever something weird happens:
import numpy as np
from matplotlib import pyplot as plt
from scipy.integrate import solve_ivp, odeint
g = 9.81
l = 0.1
def f(t, r):
omega = r[0]
theta = r[1]
return np.array([-g / l * np.sin(theta), omega])
time = np.linspace(0, 10, 1000)
init_r = [0, np.radians(179)]
results = solve_ivp(f, (0, 10), init_r, method="RK45", t_eval=time) #??????
cenas = odeint(f, init_r, time, tfirst=True)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(results.t, results.y[1])
ax1.plot(time, cenas[:, 1])
plt.show()
What am I missing?
It is a numerical problem. The default relative and absolute tolerances of solve_ivp are 1e-3 and 1e-6, respectively. For many problems, these values are too big, and tighter error tolerances should be given. The default relative tolerance for odeint is 1.49e-8.
If you add the argument rtol=1e-8 to the solve_ivp call, the plots agree:
import numpy as np
from matplotlib import pyplot as plt
from scipy.integrate import solve_ivp, odeint
g = 9.81
l = 0.1
def f(t, r):
omega = r[0]
theta = r[1]
return np.array([-g / l * np.sin(theta), omega])
time = np.linspace(0, 10, 1000)
init_r = [0, np.radians(179)]
results = solve_ivp(f, (0, 10), init_r, method='RK45', t_eval=time, rtol=1e-8)
cenas = odeint(f, init_r, time, tfirst=True)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(results.t, results.y[1])
ax1.plot(time, cenas[:, 1])
plt.show()
Plot:

Cannot change hatch density using contourf in Matplotlib 2.2.2

I want to change the density of hatch lines using Matplotlib v2.2.2 and the contourf() function (specifically, I want to increase the density). I have read that you can increase the density of a hatch by increasing how many times you use the hatch figure (e.g. replace x with xx). However, that change is having no effect for me. My backend is Qt5Agg, and I'm using Python v3.6.4.
MWE:
import matplotlib.pyplot as plt
import numpy as np
def main():
x = np.arange( 0, 1.01, 0.01 )
X, Y = np.meshgrid( x, x )
Z = X + Y
fig, (ax1, ax2) = plt.subplots( 1, 2 )
ax1.contourf( X, Y, Z, [1,2], colors='none', hatches='x' )
ax2.contourf( X, Y, Z, [1,2], colors='none', hatches='xx' )
plt.show()
main()
which produces the output
Possible Duplicates:
This question is 7 years old and requires defining a custom class. Is this still the best option?
This question is basically exactly what I'm asking, but the MWE was a bit complicated, and didn't attract any answers.
It's in general no problem to make the hatching more dense. This is indeed done by repeating the hatching pattern. E.g. /, //, ///.
Here, you have two contour regions/levels. Hence you need two hatches.
import matplotlib.pyplot as plt
import numpy as np
def main():
x = np.arange( 0, 1.01, 0.01 )
X, Y = np.meshgrid( x, x )
Z = X + Y
fig, (ax1, ax2) = plt.subplots( 1, 2 )
ax1.contourf( X, Y, Z, [1,2], colors='none', hatches=['/',None] )
ax2.contourf( X, Y, Z, [1,2], colors='none', hatches=['//',None] )
plt.show()
main()

More areas in contourf using logscale

I'm currently trying to get an impression of continuous change in my contour plot. I have to use a logscale for the values, because some of them are some orders of magnitude bigger than the others.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker
K = np.linspace(-0.99, 5, 100)
x = np.linspace(1, 5, 100)
K, x = np.meshgrid(K, x)
static_diff = 1 / (1 + K)
fig = plt.figure()
plot = plt.contourf(K, x, static_diff, locator=ticker.LogLocator(numticks=300))
plt.grid(True)
plt.xlabel('K')
plt.ylabel('x')
plt.xlim([-0.99, 5])
plt.ylim([1, 5])
fig.colorbar(plot)
plt.show()
Despite the number of ticks given to be 300 it returns a plot like:
Is there a way to get more of these lines? I also tried adding the number of parameters as the fourth parameter of the plt.contourf function.
To specify the levels of a contourf plot you may
use the levels argument and supply a list of values for the levels. E.g for 20 levels,
plot = plt.contourf(K, x, static_diff, levels=np.logspace(-2, 3, 20))
use the locator argument to which you would supply a matplotlib ticker
plt.contourf(K, x, static_diff, locator=ticker.LogLocator(subs=range(1,10)))
Note however that the LogLocator does not use a numticks argument but instead a base and a subs argument to determine the locations of the ticks. See documentation.
Complete example for the latter case, which also uses a LogNormto distribute the colors better in logspace:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker
import matplotlib.colors
K = np.linspace(-0.99, 5, 100)
x = np.linspace(1, 5, 100)
K, x = np.meshgrid(K, x)
static_diff = 1 / (1 + K)
fig = plt.figure()
norm= matplotlib.colors.LogNorm(vmin=static_diff.min(), vmax=static_diff.max())
plot = plt.contourf(K, x, static_diff, locator=ticker.LogLocator(subs=range(1,10)), norm=norm)
#plot = plt.contourf(K, x, static_diff, levels=np.logspace(-2, 3, 20), norm=norm)
plt.grid(True)
plt.xlabel('K')
plt.ylabel('x')
plt.xlim([-0.99, 5])
plt.ylim([1, 5])
fig.colorbar(plot)
plt.show()

Resources