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!
Related
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!
Using matlotlib, I can create figures that look like this:
Here, each row consists of a series of numbers from 0 to 0.6. The left hand axis text indicates the maximum value in each row. The bottom axis text represents the column indices.
The code for the actual grid essentially involves this line:
im = ax[r,c].imshow(info_to_use, vmin=0, vmax=0.6, cmap='gray')
where ax[r,c] is the current subplot axes at row r and column c, and info_to_use is a numpy array of shape (num_rows, num_cols) and has values between 0 and 0.6.
I am wondering if there is a way to convert the code above so that it instead displays bar charts, one per row? Something like this hand-drawn figure:
(The number of columns is not the same in my hand-drawn figure compared to the earlier one.) I know this would result in a very hard-to-read plot if it were embedded into a plot like the first one here. I would have this for a plot with fewer rows, which would make the bars easier to read.
The references that helped me make the first plot above were mostly from:
Python - Plotting colored grid based on values
custom matplotlib plot : chess board like table with colored cells
https://matplotlib.org/3.1.1/gallery/subplots_axes_and_figures/colorbar_placement.html#sphx-glr-gallery-subplots-axes-and-figures-colorbar-placement-py
https://matplotlib.org/3.1.1/gallery/images_contours_and_fields/image_annotated_heatmap.html#sphx-glr-gallery-images-contours-and-fields-image-annotated-heatmap-py
But I'm not sure how to make the jump from these to a bar chart in each row. Or at least something that could mirror it, e.g., instead of shading the full cell gray, only shade as much of it based on the percentage of the vmax?
import numpy as np
from matplotlib import pyplot as plt
a = np.random.rand(10,20)*.6
In a loop, call plt.subplot then plt.bar for each row in the 2-d array.
for i, thing in enumerate(a,1):
plt.subplot(a.shape[0],1,i)
plt.bar(range(a.shape[1]),thing)
plt.show()
plt.close()
Or, create all the subplots; then in a loop make a bar plot with each Axes.
fig, axes = plt.subplots(a.shape[0],1,sharex=True)
for ax, data in zip(axes, a):
ax.bar(range(a.shape[1]), data)
plt.show()
plt.close()
Let's look at a swarmplot, made with Python 3.5 and Seaborn on some data (which is stored in a pandas dataframe df with column lables stored in another class. This does not matter for now, just look at the plot):
ax = sns.swarmplot(x=self.dte.label_temperature, y=self.dte.label_current, hue=self.dte.label_voltage, data = df)
Now the data is more readable if plotted in log scale on the y-axis because it goes over some decades.
So let's change the scaling to logarithmic:
ax.set_yscale("log")
ax.set_ylim(bottom = 5*10**-10)
Well I have a problem with the gaps in the swarms. I guess they are there because they have been there when the plot is created with a linear axis in mind and the dots should not overlap there. But now they look kind of strange and there is enough space to from 4 equal looking swarms.
My question is: How can I force seaborn to recalculate the position of the dots to create better looking swarms?
mwaskom hinted to me in the comments how to solve this.
It is even stated in the swamplot doku:
Note that arranging the points properly requires an accurate transformation between data and point coordinates. This means that non-default axis limits should be set before drawing the swarm plot.
Setting an existing axis to log-scale and use this for the plot:
fig = plt.figure() # create figure
rect = 0,0,1,1 # create an rectangle for the new axis
log_ax = fig.add_axes(rect) # create a new axis (or use an existing one)
log_ax.set_yscale("log") # log first
sns.swarmplot(x=self.dte.label_temperature, y=self.dte.label_current, hue=self.dte.label_voltage, data = df, ax = log_ax)
This yields in the correct and desired plotting behaviour:
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 produced 3 sets of data which are organised in numpy arrays. I'm interested in plotting the probability distribution of these three sets of data as normed histograms. All three distributions should look almost identical so it seems sensible to plot all three on the same axis for ease of comparison.
By default matplotlib histograms are plotted as bars which makes the image I want look very messy. Hence, my question is whether it is possible to force pyplot.hist to only draw a box/circle/triangle where the top of the bar would be in the default form so I can cleanly display all three distributions on the same graph or whether I have to calculate the histogram data and then plot it separately as a scatter graph.
Thanks in advance.
There are two ways to plot three histograms simultaniously, but both are not what you've asked for. To do what you ask, you must calculate the histogram, e.g. by using numpy.histogram, then plot using the plot method. Use scatter only if you want to associate other information with your points by setting a size for each point.
The first alternative approach to using hist involves passing all three data sets at once to the hist method. The hist method then adjusts the widths and placements of each bar so that all three sets are clearly presented.
The second alternative is to use the histtype='step' option, which makes clear plots for each set.
Here is a script demonstrating this:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(101)
a = np.random.normal(size=1000)
b = np.random.normal(size=1000)
c = np.random.normal(size=1000)
common_params = dict(bins=20,
range=(-5, 5),
normed=True)
plt.subplots_adjust(hspace=.4)
plt.subplot(311)
plt.title('Default')
plt.hist(a, **common_params)
plt.hist(b, **common_params)
plt.hist(c, **common_params)
plt.subplot(312)
plt.title('Skinny shift - 3 at a time')
plt.hist((a, b, c), **common_params)
plt.subplot(313)
common_params['histtype'] = 'step'
plt.title('With steps')
plt.hist(a, **common_params)
plt.hist(b, **common_params)
plt.hist(c, **common_params)
plt.savefig('3hist.png')
plt.show()
And here is the resulting plot:
Keep in mind you could do all this with the object oriented interface as well, e.g. make individual subplots, etc.