How to put multiple matshow() results in one figure? - matplotlib

I'm trying to make a figure like this. A matrix of plots, each is a visualization of a numerical matrix.
I thought code should look something like the following:
using PyPlot
figure()
for i in 1:100
subplot(10, 10, i)
matshow(rand(10, 10))
end
But the plots would pop out in new windows independently, instead of in separate parts of the same figure. What did I do wrong?
Thanks in advance for your time!

Disclaimer: I've absolutely no experience with Julia. So there may be some caveats about the following I'm not aware of.
From the matshow documentation:
matplotlib.pyplot.matshow(A, fignum=None, **kw)
Display an array as a matrix in a new figure window. [...]
fignum: [ None | integer | False ]
By default, matshow() creates a new figure window with automatic numbering. If fignum is given as an integer, the created figure will use this figure number. Because of how matshow() tries to set the figure aspect ratio to be the one of the array, if you provide the number of an already existing figure, strange things may happen.
If fignum is False or 0, a new figure window will NOT be created.
Two possible options might thus be:
Use fignum=false
figure()
for i in 1:100
subplot(10, 10, i)
matshow(rand(10, 10), fignum=false)
end
Use imshow instead of matshow (because imshow does not create a new figure by default)
figure()
for i in 1:100
subplot(10, 10, i)
imshow(rand(10, 10))
end

My preferred way using pyplot is avoid using the "magic" that guesses which subplot you want to use. Thus I would usually do something like this:
figure()
for i in 1:100
ax = subplot(10, 10, i) # assign ax to that subplot
ax[:matshow](rand(10, 10)) # call plot method on that specific subplot
end
or for even more flexibility you can do:
f,axs=subplots(10,10) # create all the subplots at the start
for ax in axs # instead use `for (i,ax) enumerate(axs)` if you need the index)
ax[:matshow](rand(10,10)) # plot on each iteration
end

Related

Matplotlib modified histograms won't display after modification

I have plotted a histogram and would like to modify it, then re-plot it. It won't plot again without redefining the Figure and Axes object definitions. I'm using Jupyter Notebook, and I'm new to matplotlib, so I don't know if this is something that I'm not understanding about matplotlib, if it's an issue with the Jupyter Notebook or something else.
Here's my 1st block of code:
"""Here's some data."""
some_data = np.random.randn(150)
"""Here I define my `Figure` and `Axes` objects."""
fig, ax = plt.subplots()
"""Then I make a histogram from them, and it shows up just fine."""
ax.hist(some_data, range=(0, 5))
plt.show()
Here's the output from my 1st block of code:
Here's my 2nd block of code:
"""Here I modify the parameter `bins`."""
ax.hist(some_data, bins=20, range=(0, 5))
"""When I try to make a new histogram, it doesn't work."""
plt.show()
My 2nd block of code generates no visible output, which is the problem.
Here's my 3rd and final block of code:
"""But it does work if I define new `Figure` and `Axes` objects.
Why is this?
How can I display new, modified plots without defining new `Figure` and/or `Axes` objects? """
new_fig, new_ax = plt.subplots()
new_ax.hist(some_data, bins=20, range=(0, 5))
plt.show()
Here's the output from my 3rd and final block of code:
Thanks in advance.
When you generate a figure or an axis, it remains accessible for rendering or display until it's used for rendering or display. Once you execute plt.show() in your first block, the ax becomes unavailable. Your 3rd block of code is showing a plot because you're regenerating the figure and axes.

Heatmap colorbars accumulating in Matplotlib/Seaborn figures

I have a list of data frames, and I want to make heatmaps of every data frame in the list. The first heatmap comes out perfectly, but the second one has two colorbars, one much larger than the other, which distorts the figure. The third has THREE colorbars, the last one being even larger, and this continues for as many heatmaps as I make.
This seems like a bug to me, as I have no idea why it's happening. Each heatmap should be stored as a separate element in the list of heatmaps, and even if I plot them individually, instead of using a loop or list comprehension, I get the same problem.
Here is my code:
# Set the seaborn font size.
sns.set(font_scale=0.5)
# Ensure that labels are not cut off.
plt.gcf().subplots_adjust(bottom=0.18)
plt.gcf().subplots_adjust(right=.3)
black_yellow = sns.dark_palette("yellow",10)
heatmap_list = [sns.heatmap(df, cmap=black_yellow, xticklabels=True, yticklabels=True) for df in df_list]
[heatmap_list[x].figure.savefig(file_names_list[x]+'.pdf', format='pdf') for x in range(0,len(heatmap_list))]
sns.heatmap() creates a problem while we are working in loop. To resolve this issue, the first iteration will be done individually and rest of the loop remains the same but we will add a parameter cbar=False to stop this recursion of colorbar in the loop portion.
# Set the seaborn font size.
sns.set(font_scale=0.5)
# Ensure that labels are not cut off.
plt.gcf().subplots_adjust(bottom=0.18)
plt.gcf().subplots_adjust(right=.3)
black_yellow = sns.dark_palette("yellow", 10)
hm = sns.heatmap(df_list[0], cmap=black_yellow, xticklabels=True, yticklabels=True)
hm.figure.savefig(file_names_list[0]+'.pdf', format='pdf')
heatmap_list = [sns.heatmap(df_list[i], cmap=black_yellow, xticklabels=True, yticklabels=True, cbar=False) for i in range(1, len(df_list))]
[heatmap_list[x].figure.savefig(file_names_list[x+1]+'.pdf', format='pdf') for x in range(0, len(heatmap_list))]

PyPlot in Juno: Fixing axis height

I apologise if this has already been asked, I've searched long and hard on this site and couldn't find anything that worked. I'm using Julia, specifically the Juno IDE, and I am trying to use PyPlot to create my graphs. I wanted to set the y axis height when plotting, but leave the x axis variable. Here is the code I have been using to generate my plots
fig = figure()
ax = fig[:add_axes]
BEFE250 = (plot(s1, s2, lw=1.0, "-", color="b"))
ylabel("u(x,t)", size=20)
xlabel("t", size=20)
gcf()
which gives me
However, I need space in the top left corner as I am going to layer another picture on top in latex. So I need to set the y-axis height to between -3 and 3. However, if I set the axes height in PyPlot
fig = figure()
ax = fig[:add_axes]([0.1, 0.1, -3.0, 3.0])
BEFE250 = (plot(s1, s2, lw=1.0, "-", color="b"))
ylabel("u(x,t)", size=20)
xlabel("t", size=20)
gcf()
then it switches the orientation of the x-axis. If I set the axis height after running the plot, PyPlot puts the picture in a box in a legend off to the side of the main picture, and the main picture is empty? If someone could help me out it would be greatly appreciated.
Thanks for your help.
EDIT: Using xlim=(-10.,10.) and ylim=(-2.,12.) doesn't work either. PyPlot still adapts the axes to the data.
Try xlim(-10, 10) and ylim(-2, 12) after the plot command:
plot(s1, s2, lw=1.0, "-", color="b")
ylim(-3, 3)
Just try this, without the add_axes.
You probably also want LaTeX labels -- just add an L before the string, which gives a special LaTeX string from the LaTeXString package. You can either just add the L, or add $ inside too:
ylabel(L"u(x,t)", size=20)
ylabel(L"$u(x,t)$", size=20)
[The $ are necessary in certain circumstances that I forget.]
I'm not sure how good the PyPlot support is in Juno.
You might want to try this in IJulia.
By the way, is there a reason you want to layer on a separate figure in LaTeX? That might not be the best way to do it.

Add a new axis to the right/left/top-right of an axis

How do you add an axis to the outside of another axis, keeping it within the figure as a whole? legend and colorbar both have this capability, but implemented in rather complicated (and for me, hard to reproduce) ways.
You can use the subplots command to achieve this, this can be as simple as py.subplot(2,2,1) where the first two numbers describe the geometry of the plots (2x2) and the third is the current plot number. In general it is better to be explicit as in the following example
import pylab as py
# Make some data
x = py.linspace(0,10,1000)
cos_x = py.cos(x)
sin_x = py.sin(x)
# Initiate a figure, there are other options in addition to figsize
fig = py.figure(figsize=(6,6))
# Plot the first set of data on ax1
ax1 = fig.add_subplot(2,1,1)
ax1.plot(x,sin_x)
# Plot the second set of data on ax2
ax2 = fig.add_subplot(2,1,2)
ax2.plot(x,cos_x)
# This final line can be used to adjust the subplots, if uncommentted it will remove all white space
#fig.subplots_adjust(left=0.13, right=0.9, top=0.9, bottom=0.12,hspace=0.0,wspace=0.0)
Notice that this means things like py.xlabel may not work as expected since you have two axis. Instead you need to specify ax1.set_xlabel("..") this makes the code easier to read.
More examples can be found here.

Multiplot with matplotlib without knowing the number of plots before running

I have a problem with Matplotlib's subplots. I do not know the number of subplots I want to plot beforehand, but I know that I want them in two rows. so I cannot use
plt.subplot(212)
because I don't know the number that I should provide.
It should look like this:
Right now, I plot all the plots into a folder and put them together with illustrator, but there has to be a better way with Matplotlib. I can provide my code if I was unclear somewhere.
My understanding is that you only know the number of plots at runtime and hence are struggling with the shorthand syntax, e.g.:
plt.subplot(121)
Thankfully, to save you having to do some awkward math to figure out this number programatically, there is another interface which allows you to use the form:
plt.subplot(n_cols, n_rows, plot_num)
So in your case, given you want n plots, you can do:
n_plots = 5 # (or however many you programatically figure out you need)
n_cols = 2
n_rows = (n_plots + 1) // n_cols
for plot_num in range(n_plots):
ax = plt.subplot(n_cols, n_rows, plot_num)
# ... do some plotting
Alternatively, there is also a slightly more pythonic interface which you may wish to be aware of:
fig, subplots = plt.subplots(n_cols, n_rows)
for ax in subplots:
# ... do some plotting
(Notice that this was subplots() not the plain subplot()). Although I must admit, I have never used this latter interface.
HTH