I am working on a visualization script for a linear algebra class at the university and I am trying to show multiple vectors using the quiver function in python. I am trying to plot vectors coming from a 2x2 matrix in one quiver function, however, now that I am trying to label them I would like to access each vector individually.
import numpy as np
import matplotlib.pyplot as plt
A = np.array([[1,3], [2,2]])
# create figure
fig = plt.figure()
# creates variable containing current figure
ax = fig.gca()
baseArrow = ax.quiver(*origin, A[0,:], A[1,:], color=['r','g']', angles='xy', scale_units='xy', scale=1)
ax.quiverkey(baseArrow,.85,.85,0.8,'i-hat',labelcolor='k',labelpos='S', coordinates = 'figure')
# display grid
plt.grid()
# display figure
plt.show()
This alows me to label the first vector with the respective color (red). Now what I would like to do is label the second vector in green with a different label?
Maybe something like:
ax.quiverkey(baseArrow**[2]**,.85,.85,0.8,'i-hat',labelcolor='k',labelpos='S', coordinates = 'figure')
Is there any way to pull out each vector by itself or would it be better to plot them individually instead of as a vector? I looked at the following question but it doesn't really solve my issue. Matplotlib Quiver plot matching key label color with arrow color
My feeling is that the quiver function is better suited/intended to plot numerous vectors as you would find in a graph depicting magnetic forces, vortices (sic) or gradients (see meshgrid for example). And it's API reflects that, in that it accepts end and start coordinates separately: i.e. you need to split the components of your vectors as you have done above.
May I suggest you look into the plot or arrow functions which will give you greater control over your visualization (e.g. vector-independent labels) and will also provide greater clarity in your code, as you will be able to declare vectors (as np.arrays of course) and use them directly.
Finally note that you can obtain fig and ax in one call: fib, ax = plt.subplots().
Hope this helps!
Related
My goal is to have a single column heat map, but for some reason to code I normally use for heat maps doesn't work with if I'm not using a 2-D array.
vec1 = np.asarray([1,2,3,4,5])
fig, ax = plt.subplots()
plt.imshow(vec1, cmap='jet')
I know it's weird to show I single column vector as a heat map, but it's a nice visual for my purposes. I just want a column of colored squares that I can label along the y-axis to show a ranked list of things to people.
You could use the library Seaborn to do this. In Seaborn you can identify specific columns to plot. In this case that'd be your array. The following should accomplish what you're wanting
vec1 = np.asarray([1,2,3,4,5])
fig, ax = plt.subplots()
seaborn.heatmap([vec1])
Then you'll just have to do your formatting on that heatmap as you would in pyplotlib.
http://seaborn.pydata.org/generated/seaborn.heatmap.html
Starting from the previous answer, I've come up with an approach which uses both Seaborn and Matplotlib's transform to do what pavlov requested within its comment (that is, swapping axis in a heatmap even though Seaborn does not have an orientation parameter).
Let's start from the previous answer:
vec1 = np.asarray([1,2,3,4,5])
sns = heatmap([vec1])
plt.show()
Using heatmap on a single vector yields to the following result:
Ok, let's swap the x-axis with the y-axis. To do that, we can use an Affine2D transform, applying a rotation of 90 degrees.
from matplotlib import transforms
tr = transforms.Affine2D().rotate_deg(90)
Let's also reshape the initial array to make it resemble a column vector:
vec2 = vec1.reshape(vec1.shape[0], 1)
Now we can plot the heatmap and force Matplotlib to perform an affine transform:
sns.heatmap(vec2)
plt.show(tr)
The resulting plot is:
Now, if we want to force each row to be a square, we can simply use the square=True parameter:
sns.heatmap(vec2, square=True)
plt.show(tr)
This is the final result:
Hope it helps!
I have a pair of lists of numbers representing points in a 2-D space, and I want to represent the y/x ratios for these points as a 1-dimensional heatmap, with a diverging color map centered around 1, or the logs of my ratios, with a diverging color map centered around 0.
How do I do that?
My current attempt (borrowing somewhat from Heatmap in matplotlib with pcolor?):
from matplotlib import numpy as np
import matplotlib.pyplot as plt
# There must be a better way to generate arrays of random values
x_values = [np.random.random() for _ in range(10)]
y_values = [np.random.random() for _ in range(10)]
labels = list("abcdefghij")
ratios = np.asarray(y_values) / np.asarray(x_values)
axis = plt.gca()
# I transpose the array to get the points arranged vertically
heatmap = axis.pcolor(np.log2([ratios]).T, cmap=plt.cm.PuOr)
# Put labels left of the colour cells
axis.set_yticks(np.arange(len(labels)) + 0.5, minor=False)
# (Not sure I get the label order correct...)
axis.set_yticklabels(labels)
# I don't want ticks on the x-axis: this has no meaning here
axis.set_xticks([])
plt.show()
Some points I'm not satisfied with:
The coloured cells I obtain are horizontally-elongated rectangles. I would like to control the width of these cells and obtain a column of cells.
I would like to add a legend for the color map. heatmap.colorbar = plt.colorbar() fails with RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).
One important point:
matplotlib/pyplot always leaves me confused: there seems to be a lot of ways to do things and I get lost in the documentation. I never know what would be the "clean" way to do what I want: I welcome suggestions of reading material that would help me clarify my very approximative understanding of these things.
Just 2 more lines:
axis.set_aspect('equal') # X scale matches Y scale
plt.colorbar(mappable=heatmap) # Tells plt where it should find the color info.
Can't answer your final question very well. Part of it is due to we have two branches of doing things in matplotlib: the axis way (axis.do_something...) and the MATLAB clone way plt.some_plot_method. Unfortunately we can't change that, and it is a good feature for people to migrate into matplotlib. As far as the "Clean way" is concerned, I prefer to use whatever produces the shorter code. I guess that is inline with Python motto: Simple is better than complex and Readability counts.
I have a calculated data (x,y) which I would like to put on top of an image from a paper to compare with some of its boundaries. If this image was a 2D x,y plot, I would have extracted easily the points and then plot together with mine. However this image is a 3D color plot, therefore if I want just to read the image, define my coordinates according to it and plot my data on top, so at the end would seem like 2 layers.
I can plot scatter points by following:
import matplotlib.pyplot as plt
im = plt.imread('fig_exp.png')
implot = plt.imshow(im)
# put a blue dot at (10, 20)
plt.scatter([10], [20], c='r', s=2000, marker=u'*')
plt.show()
But how can I define image coordinates so I can plot e.g
x=[-100,-80,-60,-40]
y=[10,15,20,25]
plt.plot(x,y,'-ro')
The problem here is that I dont know how to define the coordinates as in the figure. Beside I dont know how to plot not as scatter but a line.
I appreciate any helpful solution!
You are looking for the extent= keyword argument to imshow() as detailed in the documentation
As for your second question, if you want a line plot, you use the plot() function instead of scatter().
I'm trying to add a color bar in a graph, but I don't understand how it works. The problem is that I make my own colorcode by:
x = np.arange(11)
ys = [i+x+(i*x)**2 for i in range(11)]
colors = cm.rainbow(np.linspace(0, 1, len(ys)))
and colors[i] will give me a new color. Then I use (homemade) functions to select the relevant data and plot them accordingly. This would look something like this:
function(x,y,concentration,temperature,1,37,colors[0])
function(x,y,concentration,temperature,2,37,colors[1])
# etc
Now I want to add the colors in a color bar, with labels I can change. How do I do this?
I have seen several examples where you plot all the data as one array, with automated color bars, but here I plot the data one by one (by using functions to select the relevant data).
EDIT:
function(x,y,concentration,temperature,1,37,colors[0]) looks like this (simplified):
def function(x,y,c,T,condition1,condition2,colors):
import matplotlib.pyplot as plt
i=0
for element in c:
if element == condition1:
if T[i]==condition2:
plt.plot(x,y,color=colors,linewidth=2)
i=i+1
return
Drawing a colorbar aside a line plot
Please map my solution (I used simply 11 sines of different amplitudes) to your problem (as I told you, it is difficult to understand from what you wrote in your Q).
import matplotlib
import numpy as np
from matplotlib import pyplot as plt
# an array of parameters, each of our curves depend on a specific
# value of parameters
parameters = np.linspace(0,10,11)
# norm is a class which, when called, can normalize data into the
# [0.0, 1.0] interval.
norm = matplotlib.colors.Normalize(
vmin=np.min(parameters),
vmax=np.max(parameters))
# choose a colormap
c_m = matplotlib.cm.cool
# create a ScalarMappable and initialize a data structure
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
# plotting 11 sines of varying amplitudes, the colors are chosen
# calling the ScalarMappable that was initialised with c_m and norm
x = np.linspace(0,np.pi,31)
for parameter in parameters:
plt.plot(x,
parameter*np.sin(x),
color=s_m.to_rgba(parameter))
# having plotted the 11 curves we plot the colorbar, using again our
# ScalarMappable
plt.colorbar(s_m)
# That's all, folks
plt.show()
Example
Acknowledgements
A similar problem, about a scatter plot
Update — April 14, 2021
With recent versions of Matplotlib, the statement s_m.set_array([]) is not required any more. On the other hand, it does no harm.
When plotting, in place of color=s_m.to_rgba(parameter) one may want to use the (slightly) more obvious color=c_m(norm(parameter)).
I'm trying to reproduce this plot in python with little luck:
It's a simple number density contour currently done in SuperMongo. I'd like to drop it in favor of Python but the closest I can get is:
which is by using hexbin(). How could I go about getting the python plot to resemble the SuperMongo one? I don't have enough rep to post images, sorry for the links. Thanks for your time!
Example simple contour plot from a fellow SuperMongo => python sufferer:
import numpy as np
from matplotlib.colors import LogNorm
from matplotlib import pyplot as plt
plt.interactive(True)
fig=plt.figure(1)
plt.clf()
# generate input data; you already have that
x1 = np.random.normal(0,10,100000)
y1 = np.random.normal(0,7,100000)/10.
x2 = np.random.normal(-15,7,100000)
y2 = np.random.normal(-10,10,100000)/10.
x=np.concatenate([x1,x2])
y=np.concatenate([y1,y2])
# calculate the 2D density of the data given
counts,xbins,ybins=np.histogram2d(x,y,bins=100,normed=LogNorm())
# make the contour plot
plt.contour(counts.transpose(),extent=[xbins.min(),xbins.max(),
ybins.min(),ybins.max()],linewidths=3,colors='black',
linestyles='solid')
plt.show()
produces a nice contour plot.
The contour function offers a lot of fancy adjustments, for example let's set the levels by hand:
plt.clf()
mylevels=[1.e-4, 1.e-3, 1.e-2]
plt.contour(counts.transpose(),mylevels,extent=[xbins.min(),xbins.max(),
ybins.min(),ybins.max()],linewidths=3,colors='black',
linestyles='solid')
plt.show()
producing this plot:
And finally, in SM one can do contour plots on linear and log scales, so I spent a little time trying to figure out how to do this in matplotlib. Here is an example when the y points need to be plotted on the log scale and the x points still on the linear scale:
plt.clf()
# this is our new data which ought to be plotted on the log scale
ynew=10**y
# but the binning needs to be done in linear space
counts,xbins,ybins=np.histogram2d(x,y,bins=100,normed=LogNorm())
mylevels=[1.e-4,1.e-3,1.e-2]
# and the plotting needs to be done in the data (i.e., exponential) space
plt.contour(xbins[:-1],10**ybins[:-1],counts.transpose(),mylevels,
extent=[xbins.min(),xbins.max(),ybins.min(),ybins.max()],
linewidths=3,colors='black',linestyles='solid')
plt.yscale('log')
plt.show()
This produces a plot which looks very similar to the linear one, but with a nice vertical log axis, which is what was intended:
Have you checked out matplotlib's contour plot?
Unfortunately I couldn't view yours images. Do you mean something like this? It was done by MathGL -- GPL plotting library, which have Python interface too. And you can use arbitrary data arrays as input (including numpy's one).
You can use numpy.histogram2d to get a number density distribution of your array.
Try this example:
http://micropore.wordpress.com/2011/10/01/2d-density-plot-or-2d-histogram/