Matplotlib: Superimpose multiple 2d quiver plots over time - python

I have some vector fields that vary in 2d space and over time. Conventionally, one could visualize the evolution of the vector fields as a 2D movie where the magnitudes and angles of all quivers change in time.
To be explicit, currently I have U and V each with shape (x,y,t) where dims 0 and 1 are spatial coordinates and t is a particular time slice. I can visualize the vector field for a specific time as: matplotlib.pyplot.quiver(U[:,:,i], V[:,:,i]) where i is a particular time index. Currently I can visualize this evolution in a for-loop iterating over all i.
However, I would like to visualize each of the quiver plots in time on a single 2 dimensional plot. To do this I want to assign each index i as a different color from a given colormap. Therefore all quivers from a particular time point appear as a single color.
Can anybody suggest an approach?
Thank you in advance!

You could do something along the lines of:
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
U = np.random.rand(10, 10, 10) - 0.5
V = np.random.rand(10, 10, 10) - 0.5
cmap = plt.cm.jet
time_samples = U.shape[-1]
for t in xrange(time_samples):
plt.quiver(U[..., t], V[..., t], color=cmap(j/time_samples))
plt.show()

Related

Downsampling Velocity Information in a Quiver Plot

I have two arrays (vel_y,vel_z) representing velocities in the y and z directions, respectively, that are both shaped as (512,512) that I am attempting to represent using a quiver plot.
Here is how I plotted the quiver:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,512,num=512)
[X,Y] = np.meshgrid(x,x)
fig, ax = plt.subplots(figsize=(7,7))
ax.quiver(X,Y,vel_y,vel_z,np.arctan2(vel_z,vel_y),pivot='mid',units='x',scale=2)
The arctan2() call is so that different orientations are colored differently as in this answer.
Obviously plotting all 5122 of these arrows makes for a jumbled and difficult to parse plot, which you can see here:
Quiver Plot.
I was wondering if there was a better way to scale/represent the arrows so that it is more readable?
However, the main question I have is how I could 'downsample' this velocity information to go from plotting 5122 arrows to 1002 for example. Would this require interpolation between points where the velocity is defined?
Thank you!
The simple way to do this is simply to take one point over N in each vectors given to quiver.
For a given np.array, you can do this using the following syntax: a[::N]. If you have multiple dimensions, repeat this in each dimension (you can give different slip for each dimension): a[::N1, ::N2].
In your case:
N1 = 5
N2 = 5
ax.quiver(X[::N1, ::N2], Y[::N1, ::N2], vel_y[::N1, ::N2], vel_z[::N1, ::N2], np.arctan2(vel_z,vel_y)[::N1, ::N2], pivot='mid',units='x',scale=2)
You don't need interpolation, unless you want to plot velocities at points not defined in the grid where you have your measurements/simulations/whatever.

How to properly show a colorbar in a polar graph (contour plot of half a circle)?

I am plotting a big matrix of temperature (for each r and theta of a circle) in a polar graph using Pyplot from matplotlib. So far, everything works fine with what I've done :
space_theta = radians(linspace(0, 180, M))
space_r = arange(0, a, delta_r)
r, theta = meshgrid(space_theta, space_r)
fig, axes = plt.subplots(subplot_kw=dict(projection='polar'))
axes.contourf(r, theta, T[W-1]) #T[W-1] is the temperatures I want to plot (T is a 3D matrix, so T[W-1] is a matrix)
axes.set_thetamin(0)
axes.set_thetamax(180)
plt.show()
With this, I get the following :
Now the only thing I want is to add a color legend, indicating which color corresponds to which temperature. It should look like this (only focus on the legend) :
I searched on several websites but didn't manage to find out how to do this. Each time the method used for plotting the graph was different. I tried using colorbar(), which solved problems for everyone, but I got an error ("No mappable was found to use for colorbar creation").
P.S.: If possible, I would like to show the max and min values on the color legend.
You can use plt.colorbar with the result of axes.contourf as first parameter.
You'll notice the default colorbar will be much too large. To shrink it, use shrink=.6 to get it similar to your contourplot. Now, you'll notice it will be too close to the plot. This can be adjusted with pad=0.08.
Note that the numpy library has lots of functions with similar names as other libraries. To make clear that you're using numpy functions, it is good practise to import numpy as np.
Here is a more complete example:
from matplotlib import pyplot as plt
import numpy as np
M = 100
a = 1
delta_r = 0.01
space_theta = np.radians(np.linspace(0, 180, M))
space_r = np.arange(0, a, delta_r)
T = np.random.uniform(-30, 40, M * len(space_r)).reshape((M, len(space_r)))
r, theta = np.meshgrid(space_theta, space_r)
fig, axes = plt.subplots(subplot_kw=dict(projection='polar'))
contourplot = axes.contourf(r, theta, T)
axes.set_thetamin(0)
axes.set_thetamax(180)
plt.colorbar(contourplot, shrink=.6, pad=0.08)
plt.show()

Adding a 4th variable to a 3D plot in Python

I have 3 different parameters X,Y and Z over a range of values, and for each combination of these a certain value of V. To make it clearer, the data would look something like this.
X Y Z V
1 1 2 10
1 2 3 15
etc...
I'd like to visualize the data with a surface/contour plot, using V as a colour to see its value at that point, but I do not see how to add my custom colouring scheme into the mix using Python. Any idea on how to do this (or is this visualization outright silly)?
Thanks a lot!
Matplotlib allows one to pass the facecolors as an argument to e.g.
ax.plot_surface.
That would imply then that you would have to perform 2D interpolation on your
current array of colors, because you currently only have the colors in the
corners of the rectangular faces (you did mention that you have a rectilinear
grid).
You could use
scipy.interpolate.interp2d
for that, but as you see from the documentation, it is suggested to use
scipy.interpolate.RectBivariateSpline.
To give you a simple example:
import numpy as np
y,x = np.mgrid[1:10:10j, 1:10:10j] # returns 2D arrays
# You have 1D arrays that would make a rectangular grid if properly reshaped.
y,x = y.ravel(), x.ravel() # so let's convert to 1D arrays
z = x*(x-y)
colors = np.cos(x**2) - np.sin(y)**2
Now I have a similar dataset as you (one-dimensional arrays for x, y, z and
colors). Remark that the colors are defined for
each point (x,y). But when you want to plot with plot_surface, you'll
generate rectangular patches, of which the corners are given by those points.
So, on to interpolation then:
from scipy.interpolate import RectBivariateSpline
# from scipy.interpolate import interp2d # could 've used this too, but docs suggest the faster RectBivariateSpline
# Define the points at the centers of the faces:
y_coords, x_coords = np.unique(y), np.unique(x)
y_centers, x_centers = [ arr[:-1] + np.diff(arr)/2 for arr in (y_coords, x_coords)]
# Convert back to a 2D grid, required for plot_surface:
Y = y.reshape(y_coords.size, -1)
X = x.reshape(-1, x_coords.size)
Z = z.reshape(X.shape)
C = colors.reshape(X.shape)
#Normalize the colors to fit in the range 0-1, ready for using in the colormap:
C -= C.min()
C /= C.max()
interp_func = RectBivariateSpline(x_coords, y_coords, C.T, kx=1, ky=1) # the kx, ky define the order of interpolation. Keep it simple, use linear interpolation.
In this last step, you could also have used interp2d (with kind='linear'
replacing the kx=1, ky=1). But since the docs suggest to use the faster
RectBivariateSpline...
Now you're ready to plot it:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = ax.plot_surface(X,Y,Z,
facecolors=cm.hot(interp_func(x_centers, y_centers).T),
rstride=1, cstride=1) # only added because of this very limited dataset
As you can see, the colors on the faces have nothing to do anymore with the height of the dataset.
Note that you could have thought simply passing the 2D array C to facecolors would work, and matplotlib would not have complained. However, the result isn't accurate then, because matplotlib will use only a subset of C for the facecolors (it seems to ignore the last column and last row of C). It is equivalent to using only the color defined by one coordinate (e.g. the top-left) over the entire patch.
An easier method would have been to let matplotlib do the interpolation and obtain the facecolors and then pass those in to the real plot:
r = ax.plot_surface(X,Y,C, cmap='hot') # first plot the 2nd dataset, i.e. the colors
fc = r.get_facecolors()
ax.clear()
ax.plot_surface(X, Y, Z, facecolors=fc)
However, that won't work in releases <= 1.4.1 due to this recently submitted bug.
It really depends on how you plan on plotting this data. I like to plot graphs with gnuplot: it's easy, free and intuitive. To plot your example with gnuplot you'd have to print those line into a file (with only those four columns) and plot using a code like the following
reset
set terminal png
set output "out.png"
splot "file.txt" using 1:2:3:4 with lines palette
Assuming that you save your data into the file file.txt. splot stands for surface plot. Of course, this is a minimum example.
Alternatively you can use matplotlib, but that is not, in my opinion, as intuitive. Although it has the advantage of centering all the processing in python.

How to plot complex numbers (Argand Diagram) using matplotlib

I'd like to create an Argand Diagram from a set of complex numbers using matplotlib.
Are there any pre-built functions to help me do this?
Can anyone recommend an approach?
Image by LeonardoG, CC-SA-3.0
I'm not sure exactly what you're after here...you have a set of complex numbers, and want to map them to the plane by using their real part as the x coordinate and the imaginary part as y?
If so you can get the real part of any python imaginary number with number.real and the imaginary part with number.imag. If you're using numpy, it also provides a set of helper functions numpy.real and numpy.imag etc. which work on numpy arrays.
So for instance if you had an array of complex numbers stored something like this:
In [13]: a = n.arange(5) + 1j*n.arange(6,11)
In [14]: a
Out[14]: array([ 0. +6.j, 1. +7.j, 2. +8.j, 3. +9.j, 4.+10.j])
...you can just do
In [15]: fig,ax = subplots()
In [16]: ax.scatter(a.real,a.imag)
This plots dots on an argand diagram for each point.
edit: For the plotting part, you must of course have imported matplotlib.pyplot via from matplotlib.pyplot import * or (as I did) use the ipython shell in pylab mode.
To follow up #inclement's answer; the following function produces an argand plot that is centred around 0,0 and scaled to the maximum absolute value in the set of complex numbers.
I used the plot function and specified solid lines from (0,0). These can be removed by replacing ro- with ro.
def argand(a):
import matplotlib.pyplot as plt
import numpy as np
for x in range(len(a)):
plt.plot([0,a[x].real],[0,a[x].imag],'ro-',label='python')
limit=np.max(np.ceil(np.absolute(a))) # set limits for axis
plt.xlim((-limit,limit))
plt.ylim((-limit,limit))
plt.ylabel('Imaginary')
plt.xlabel('Real')
plt.show()
For example:
>>> a = n.arange(5) + 1j*n.arange(6,11)
>>> from argand import argand
>>> argand(a)
produces:
EDIT:
I have just realised there is also a polar plot function:
for x in a:
plt.polar([0,angle(x)],[0,abs(x)],marker='o')
If you prefer a plot like the one below
one type of plot
or this one second type of plot
you can do this simply by these two lines (as an example for the plots above):
z=[20+10j,15,-10-10j,5+15j] # array of complex values
complex_plane2(z,1) # function to be called
by using a simple jupyter code from here
https://github.com/osnove/other/blob/master/complex_plane.py
I have written it for my own purposes. Even better it it helps to others.
To get that:
You can use:
cmath.polar to convert a complex number to polar rho-theta coordinates. In the code below this function is first vectorized in order to process an array of complex numbers instead of a single number, this is just to prevent the use an explicit loop.
A pyplot axis with its projection type set to polar. Plot can be done using pyplot.stem or pyplot.scatter.
In order to plot horizontal and vertical lines for Cartesian coordinates there are two possibilities:
Add a Cartesian axis and plot Cartesian coordinates. This solution is described in this question. I don't think it's an easy solution as the Cartesian axis won't be centered, nor it will have the correct scaling factor.
Use the polar axis, and translate Cartesian coordinates for projections into polar coordinates. This is the solution I used to plot the graph above. To not clutter the graph I've shown only one point with its projected Cartesian coordinates.
Code used for the plot above:
from cmath import pi, e, polar
from numpy import linspace, vectorize, sin, cos
from numpy.random import rand
from matplotlib import pyplot as plt
# Arrays of evenly spaced angles, and random lengths
angles = linspace(0, 2*pi, 12, endpoint=False)
lengths = 3*rand(*angles.shape)
# Create an array of complex numbers in Cartesian form
z = lengths * e ** (1j*angles)
# Convert back to polar form
vect_polar = vectorize(polar)
rho_theta = vect_polar(z)
# Plot numbers on polar projection
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
ax.stem(rho_theta[1], rho_theta[0])
# Get a number, find projections on axes
n = 11
rho, theta = rho_theta[0][n], rho_theta[1][n]
a = cos(theta)
b = sin(theta)
rho_h, theta_h = abs(a)*rho, 0 if a >= 0 else -pi
rho_v, theta_v = abs(b)*rho, pi/2 if b >= 0 else -pi/2
# Plot h/v lines on polar projection
ax.plot((theta_h, theta), (rho_h, rho), c='r', ls='--')
ax.plot((theta, theta_v), (rho, rho_v), c='g', ls='--')
import matplotlib.pyplot as plt
from numpy import *
'''
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
This draws the axis for argand diagram
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
'''
r = 1
Y = [r*exp(1j*theta) for theta in linspace(0,2*pi, 200)]
Y = array(Y)
plt.plot(real(Y), imag(Y), 'r')
plt.ylabel('Imaginary')
plt.xlabel('Real')
plt.axhline(y=0,color='black')
plt.axvline(x=0, color='black')
def argand(complex_number):
'''
This function takes a complex number.
'''
y = complex_number
x1,y1 = [0,real(y)], [0, imag(y)]
x2,y2 = [real(y), real(y)], [0, imag(y)]
plt.plot(x1,y1, 'r') # Draw the hypotenuse
plt.plot(x2,y2, 'r') # Draw the projection on real-axis
plt.plot(real(y), imag(y), 'bo')
[argand(r*exp(1j*theta)) for theta in linspace(0,2*pi,100)]
plt.show()
https://github.com/QuantumNovice/Matplotlib-Argand-Diagram/blob/master/argand.py

Matplotlib : quiver and imshow superimposed, how can I set two colorbars?

I have a figure that consists of an image displayed by imshow(), a contour and a vector field set by quiver(). I have colored the vector field based on another scalar quantity. On the right of my figure, I have made a colorbar(). This colorbar() represents the values displayed by imshow() (which can be positive and negative in my case). I'd like to know how I could setup another colorbar which would be based on the values of the scalar quantity upon which the color of the vectors is based. Does anyone know how to do that?
Here is an example of the image I've been able to make. Notice that the colors of the vectors go from blue to red. According to the current colorbar, blue means negative. However I know that the quantity represented by the color of the vector is always positive.
Simply call colorbar twice, right after each plotting call. Pylab will create a new colorbar matching to the latest plot. Note that, as in your example, the quiver values range from 0,1 while the imshow takes negative values. For clarity (not shown in this example), I would use different colormaps to distinguish the two types of plots.
import numpy as np
import pylab as plt
# Create some sample data
dx = np.linspace(0,1,20)
X,Y = np.meshgrid(dx,dx)
Z = X**2 - Y
Z2 = X
plt.imshow(Z)
plt.colorbar()
plt.quiver(X,Y,Z2,width=.01,linewidth=1)
plt.colorbar()
plt.show()
Running quiver doesn't necessarily return the type of mappable object that colorbar() requires. I think it might be because I explicitly "have colored the vector field based on another scalar quantity" like Heimdall says they did. Therefore, Hooked's answer didn't work for me.
I had to create my own mappable for the color bar to read. I did this by using Normalize from matplotlib.colors on the data that I wanted to use to color my quiver vectors (which I'll call C, which is an array of the same shape as X, Y, U, and V.)
My quiver call looks like this:
import matplotlib.pyplot as pl
import matplotlib.cm as cm
import matplotlib.colors as mcolors
import matplotlib.colorbar as mcolorbar
pl.figure()
nz = mcolors.Normalize()
nz.autoscale(C)
pl.quiver(X, Y, U, V, color=cm.jet(nz(C)))
cax,_ = mcolorbar.make_axes(pl.gca())
cb = mcolorbar.ColorbarBase(cax, cmap=cm.jet, norm=nz)
cb.set_label('color data meaning')
Giving any other arguments to the colorbar function gave me a variety of errors.

Categories

Resources