matplotlib streamline with the area of divergence and convergence - matplotlib

I ploted streamlines using the u and v. How do i determine whether divergence or convergence was occurring and plot those shapes in same figure with matplotlib?
streamline test, red is divergence and blue is convergence.

You can colour streamlines in any way you want, so get whatever form of divergence you want and use that,
import numpy as np
import matplotlib.pyplot as plt
Y, X = np.mgrid[-3:3:100j, -3:3:100j]
U = -1 - X**2 + Y
V = 1 + X - Y**2
divUV = reduce(np.add,np.gradient(U)) + reduce(np.add,np.gradient(V))
fig, ax = plt.subplots()
strm = ax.streamplot(X, Y, U, V, color=divUV, cmap=plt.cm.RdBu)
fig.colorbar(strm.lines)
plt.show()
Not sure the divergence looks right here but you get the idea. Alternatively, you could overlay a colormesh with transparency,
cm = ax.pcolormesh(X, Y, divU, cmap=plt.cm.RdBu, alpha=0.4)
fig.colorbar(cm)

Related

Can matplotlib.pyplot.plot color code a curve pointwise

Here is an example from matplotlib, where pyplot.plot is used and a curve is piecewise color coded.
import numpy as np
import matplotlib.pyplot as plt
t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2 * np.pi * t)
upper = 0.77
lower = -0.77
supper = np.ma.masked_where(s < upper, s)
slower = np.ma.masked_where(s > lower, s)
smiddle = np.ma.masked_where((s < lower) | (s > upper), s)
fig, ax = plt.subplots()
ax.plot(t, smiddle, t, slower, t, supper)
plt.show()
My question is: Can matplotlib.pyplot.plot color code a curve also pointwise (using any color map). I know that I could use matplotlib.pyplot.scatter instead to do that.
No, it can't. See the documentation. As you say, use plt.scatter() for this.
You could call it for every point in your dataset using a different marker format for each, but that would be insanity, because it would effectively call .plot() for every point it plots, which is very wasteful when .scatter() exists.
If you insist though:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
n = 1000
x = np.linspace(0, 2*np.pi, n)
y = np.sin(x)
cmap = plt.get_cmap('hsv')
norm = mpl.colors.Normalize(vmin=y.min(), vmax=y.max())
for i in range(n):
plt.plot(x[i], y[i], marker='.', markersize=25, c=cmap(norm(y[i])))
plt.show()

Shaded region up to the end of frame with Matplotlib

Using Matplotlib I am trying to shade the region y > N, with N some number.
The problem is that I am not able to have the shaded region going to the end of the frame.
Here is a simple example.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1,1)
x = [i for i in range(0,100,10)]
ax.plot(x,x,'-o')
N=110
ylim = max(ax.get_ylim())
ax.axhspan(N,ylim,alpha=.5)
plt.show()
The result is this:
How to have the shaded region not stopping, but arriving up to the end of the frame?
ax.autoscale() can come in handy here. Default, matplotlib automatically adapts the limits of the axes every time something is added. Normally also some padding is added to leave some free space above and below (and left and right).
Calling ax.autoscale(enable=True, axis='y', tight=True) changes this behavior for the y-axis, forcing "tight" limits, so without padding.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
x = [i for i in range(0, 100, 10)]
ax.plot(x, x, '-o')
N = 110
ylim1 = max(ax.get_ylim())
ax.autoscale(enable=True, axis='y', tight=True)
ax.axhspan(N, ylim1, alpha=.5)
plt.show()
Alternatively, you could collect the limits before calling axhspan and setting them manually afterwards:
ax.plot(x, x, '-o')
N = 110
ylim0, ylim1 = ax.get_ylim()
ax.axhspan(N, ylim1, alpha=.5)
ax.set_ylim(ylim0, max(N, ylim1))

Matplotlib 3d barplot failing to draw just one face

import numpy as np
import matplotlib.pyplot as plt
x, y = np.array([[x, y] for x in range(5) for y in range(x+1)]).T
z = 1/ (5*x + 5)
fig = plt.figure()
ax = fig.gca(projection = '3d')
ax.bar3d(x, y, np.zeros_like(z), dx = 1, dy = 1, dz = z)
yields
How do I get the face at (1,0) to display properly?
There is currently no good solution to this. Fortunately though, it happens only for some viewing angles. So you can choose an angle where it plots fine, e.g.
ax.view_init(azim=-60, elev=25)

Matplotlib: scatter plot with colormaps for edgecolor but no facecolor

I want to have a scatter plot with colormap for edgecolors but no facecolors.
When I use facecolor='None', it does not work.
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radii
plt.scatter(x, y, s=area,c=colors,facecolors='None',cmap="gist_rainbow", alpha=0.5)
plt.show()
Any solution?
The c argument will affect facecolor and edgecolor simultaneouly, the arguments facecolor and edgecolor are hence ignored.
A solution would be not to use the c argument together with a colormap, but instead use facecolors and edgecolors alone. In this case facecolors can be set to "None" and edgecolors can be given a list of colors to use.
To create this list, the same colormap can be applied.
c = plt.cm.gist_rainbow(colors)
plt.scatter(x, y, s=area,facecolors="None", edgecolors=c, lw=1,alpha=0.5)
A complete example:
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radii
c = plt.cm.gist_rainbow(colors)
plt.scatter(x, y, s=area,facecolors="None", edgecolors=c, lw=2,alpha=0.5)
plt.show()
The problem is that color= overrides the facecolors= argument.
The solution I came up with is to get the PathCollection returned by pyplot.scatter() and then change the facecolor directly. Note that you probably need to increase the line width to see the edges better.
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radii
a = plt.scatter(x, y, s=area,c=colors,facecolor='none',lw=2,cmap="gist_rainbow", alpha=0.5)
a.set_facecolor('none')
plt.show()
I know this has been dead for a while, but I wanted to add my experience as I just encountered this same problem.
I prefer Diziet's method as passing the PathCollection object to a colorbar and having it match the cmap used in the scatter plot works exactly as it would if you didn't alter the facecolors.
With the accepted solution, however, I encountered some odd behavior where even after removing the cmap argument from the ax.scatter call the scatter plot edge colormap and the colorbar colormap didn't match.

How to set set the marker size of a 3D scatter plot fixed to the axis?

I've asked a similar question before (How to set a fixed/static size of circle marker on a scatter plot?), but now I wanna do it in 3D. How can I do that?
thanks
As in the 2D case, you need to draw the spheres yourself. If you want nicely shaped spheres this means to draw many patches and thus gets slow quite quickly.
Here's a basic way of doing it:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
def plot_shere(ax, x, y, z, r, resolution=100, **kwargs):
""" simple function to plot a sphere to a 3d axes """
u = np.linspace(0, 2 * np.pi, resolution)
v = np.linspace(0, np.pi, resolution)
xx = r * np.outer(np.cos(u), np.sin(v)) + x
yy = r * np.outer(np.sin(u), np.sin(v)) + y
zz = r * np.outer(np.ones(np.size(u)), np.cos(v)) + z
ax.plot_surface(xx, yy, zz, rstride=4, cstride=4, **kwargs)
# create some random data (set seed to make it reproducable)
np.random.seed(0)
(x,y,z) = np.random.randint(0,10,(3,5))
r = np.random.randint(2,4,(5,))
# set up the figure
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# loop through the data and plot the spheres
for p in zip(x,y,z,r):
plot_shere(ax, *p, edgecolor='none', color=np.random.rand(3))
# set the axes limits and show the plot
ax.set_ylim([-4,14])
ax.set_xlim([-4,14])
ax.set_zlim([-4,14])
plt.show()
Result: