Display images with matplotlib - python

I wanna display in a list of lists the images inside it using matplotlib. So for example I wanna have in the first row, the images of the first list, the second row, the images of the second list and so on. I tried this, but I obtain the images in each row, maybe because it will call over and over again subplot. How can I fix it?
index_plot=0
for query in list_plot:
for qm_images in query:
plt.subplot(3,5,index_plot+1)
plt.imshow(np.array(Image.open(qm_images)))
plt.show()
index_plot += 1

Instead of creating many subplots initially create a nested list of subplots with plt.subplots(), call imshow on each axis
import matplotlib.pyplot as plt
fig, axs = plt.subplots(3, 6)
for i, query in enumerate(list_plot):
for j, qm_images in enumerate(query:
axs[i][j].imshow(np.array(Image.open(qm_images)))
plt.show()

Related

How can I add multiple pre-generated subplots into a figure?

I'm using this library called FMSkill.
One of the method in this library is called .plot_timeseries
This method returns an Axes.Subplot object from matplotlib.
I'm trying to use that method to build a Multiplot Figure. I have a list called comparison that contains items upon which I can call the .plot_timeseries() method.
I've tried something like:
import math
import matplotlib as mpl
import numpy as np
import fmskill as fms
#Code to determine how many subplots in the figure
fig = plt.figure()
if len(comparison) % 2 == 0:
col, row = (int(math.ceil(np.sqrt(len(comparison)))),int(math.ceil(np.sqrt(len(comparison)))))
if len(comparison) % 2 == 1:
col, row = (int(math.ceil(np.sqrt(len(comparison)+1))),int(math.ceil(np.sqrt(len(comparison)+1))))
#Code where I try to iterate on the axes in my figures and set them using the .plot_timeseries() method
for graphs in range(len(comparison)):
ax = comparison[graphs].plot_timeseries()
fig.add_subplot(col,row,graphs+1)
This particular codes outputs a figure with the appropriate number of subplots. However the subplots are all empty. Also, it outputs every graphs generated by the .plot_timeseries() method separately.
I would like them to be put inside the subplots into one Figure.
Any ideas?
Thanks
The last portion of code is backwards.
# original
for graphs in range(len(comparison)):
ax = comparison[graphs].plot_timeseries()
fig.add_subplot(col,row,graphs+1)
Generate the axes object first, the pass it to the plot_timeseries function:
for graphs in range(len(comparison)):
ax = fig.add_subplot(col, row, graphs+1)
comparison[graphs].plot_timeseries(ax=ax)

How to print multiple plots together in python?

I am trying to print about 42 plots in 7 rows, 6 columns, but the printed output in jupyter notebook, shows all the plots one under the other. I want them in (7,6) format for comparison. I am using matplotlib.subplot2grid() function.
Note: I do not get any error, and my code works, however the plots are one under the other, vs being in a grid/ matrix form.
Here is my code:
def draw_umap(n_neighbors=15, min_dist=0.1, n_components=2, metric='euclidean', title=''):
fit = umap.UMAP(
n_neighbors=n_neighbors,
min_dist=min_dist,
n_components=n_components,
metric=metric
)
u = fit.fit_transform(df);
plots = []
plt.figure(0)
fig = plt.figure()
fig.set_figheight(10)
fig.set_figwidth(10)
for i in range(7):
for j in range(6):
plt.subplot2grid((7,6), (i,j), rowspan=7, colspan=6)
plt.scatter(u[:,0], u[:,1], c= df.iloc[:,0])
plt.title(title, fontsize=8)
n=range(7)
d=range(6)
for n in n_neighbors:
for d in dist:
draw_umap(n_neighbors=n, min_dist=d, title="n_neighbors={}".format(n) + " min_dist={}".format(d))
I did refer to this post to get the plots in a grid and followed the code.
I also referred to this post, and modified my code for size of the fig.
Is there a better way to do this using Seaborn?
What am I missing here? Please help!
Both questions that you have linked contain solutions that seem more complicated than necessary. Note that subplot2grid is useful only if you want to create subplots of varying sizes which I understand is not your case. Also note that according to the docs Using GridSpec, as demonstrated in GridSpec demo is generally preferred, and I would also recommend this function only if you want to create subplots of varying sizes.
The simple way to create a grid of equal-sized subplots is to use plt.subplots which returns an array of Axes through which you can loop to plot your data as shown in this answer. That solution should work fine in your case seeing as you are plotting 42 plots in a grid of 7 by 6. But the problem is that in many cases you may find yourself not needing all the Axes of the grid, so you will end up with some empty frames in your figure.
Therefore, I suggest using a more general solution that works in any situation by first creating an empty figure and then adding each Axes with fig.add_subplot as shown in the following example:
import numpy as np # v 1.19.2
import matplotlib.pyplot as plt # v 3.3.4
# Create sample dataset
rng = np.random.default_rng(seed=1) # random number generator
nvars = 8
nobs = 50
xs = rng.uniform(size=(nvars, nobs))
ys = rng.normal(size=(nvars, nobs))
# Create figure with appropriate space between subplots
fig = plt.figure(figsize=(10, 8))
fig.subplots_adjust(hspace=0.4, wspace=0.3)
# Plot data by looping through arrays of variables and list of colors
colors = plt.get_cmap('tab10').colors
for idx, x, y, color in zip(range(len(xs)), xs, ys, colors):
ax = fig.add_subplot(3, 3, idx+1)
ax.scatter(x, y, color=color)
This could be done in seaborn as well, but I would need to see what your dataset looks like to provide a solution relevant to your case.
You can find a more elaborate example of this approach in the second solution in this answer.

How to put multiple imshow() results in one figure?

I'd like to plot all the iterations in one plot for the matrix syn0, but the following code is showing just the last iteration and if I change the code it will open the plot 60000 times, how can I plot all the iteration in just one plot?
syn0 = 2 * np.random.random((3, 4)) - 1
arr_syn0[0][0].append(syn0[0][0])
arr_syn0[0][1].append(syn0[0][1])
arr_syn0[0][2].append(syn0[0][2])
arr_syn0[0][3].append(syn0[0][3])
arr_syn0[1][0].append(syn0[1][0])
arr_syn0[1][1].append(syn0[1][1])
arr_syn0[1][2].append(syn0[1][2])
arr_syn0[1][3].append(syn0[1][3])
arr_syn0[2][0].append(syn0[2][0])
arr_syn0[2][1].append(syn0[2][1])
arr_syn0[2][2].append(syn0[2][2])
arr_syn0[2][3].append(syn0[2][3])
plt.figure()
x=plt.imshow(syn0,aspect='auto', interpolation="nearest", cmap='YlOrRd_r', origin="upper")
plt.colorbar(x)
plt.title('syn1')
plt.show()
You say you want to plot all the iterations in one plot, but since you're iterating over 60000 images I guess what you want is to plot the new data on the same figure without opening a new one.
In order to do that you should use the imshow method on the first image only, and use the draw method on the other images, followed by the pause method that will call the GUI event loop and update the image.
Trying to reduce your code to a minimal, complete and verifiable example I'd do something like this:
import numpy as np
import matplotlib.pyplot as plt
firstImage = True
for j in range(5):
syn0 = 2 * np.random.random((3, 4)) - 1
if firstImage:
img=plt.imshow(syn0,aspect='auto', interpolation="nearest", cmap='YlOrRd_r', origin="upper")
firstImage = False
else:
img.set_data(syn0)
plt.pause(0.1)
plt.draw()
plt.title('syn1')
This code shows the different images on the same figure one after the other.
Hope this helps.

matplotlib: subplots y-axis too squashed, pdfpages only outputs to one page

I am trying to create a number (>100) subplots for later analysis. A grid up to 5x5 seems to work fine, any larger than that and the y-axis begins to get very squashed and the whole thing is unreadable. I have tried various different things, like setting aspect etc, but to no avail.
Here is the output for a 5x50 grid:
squashed subplots
and here is my code:
from matplotlib.backends.backend_pdf import PdfPages
pp = PdfPages('./output.pdf')
num_investigate = len(investigate)
ncols = 5
nrows = 50#math.ceil(num_investigate/ncols)
fig, axs = plt.subplots(nrows=nrows, ncols=ncols, sharex=False, figsize=(15,15))
for ax, file in zip(axs.flat, investigate[:(ncols*nrows)]):
try:
df = get_df_from_csv(file)
df['perf'] = df['val'] / df['val'].ix[0] - 1
#ax.set_ylim(bottom=df['perf'].min(), top=df['perf'].max())
ax.set_aspect('auto')
df['perf'].plot(ax=ax, title=file)
except:
pass
plt.tight_layout()
pp.savefig()
pp.close()
I'm at a real loss of how to solve this after much research.
How do I ensure that the each subplot size is constant and the output goes to more than one pdf page?
thanks
PdfPages saves one matplotlib figure to one page. A second calls to the savefig command will lead to the creation of a second page. Hence, if you want a second page in the output pdf, you need to create a second figure.
E.g. you can produce the first figure with a 5x5 grid and put the first 25 plots in that figure, then save it. Then create the next figure, add the next 25 plots to it and save it again.
There is a multipage_pdf example on the matplotlib page.

How to subplot multiple graphs when calling a function that plots the graph?

I have a function that plots a graph. I can call this graph with different variables to alter the graph. I'd like to call this function multiple times and plot the graphs along side each other but not sure how to do so
def plt_graph(x, graph_title, horiz_label):
df[x].plot(kind='barh')
plt.title(graph_title)
plt.ylabel("")
plt.xlabel(horiz_label)
plt_graph('gross','Total value','Gross (in millions)')
In case you know the number of plots you want to produce beforehands, you can first create as many subplots as you need
fig, axes = plt.subplots(nrows=1, ncols=5)
(in this case 5) and then provide the axes to the function
def plt_graph(x, graph_title, horiz_label, ax):
df[x].plot(kind='barh', ax=ax)
Finally, call every plot like this
plt_graph("framekey", "Some title", "some label", axes[4])
(where 4 stands for the fifth and last plot)
I have created a tool to do this really easily. I use it all the time in jupyter notebooks and find it so much neater than a big column of charts. Copy the Gridplot class from this file:
https://github.com/simonm3/analysis/blob/master/analysis/plot.py
Usage:
gridplot = Gridplot()
plt.plot(x)
plt.plot(y)
It shows each new plot in a grid with 4 plots to a row. You can change the size of the charts or the number per row. It works for plt.plot, plt.bar, plt.hist and plt.scatter. However it does require you use matplot directly rather than pandas.
If you want to turn it off:
gridplot.off()
If you want to reset the grid to position 1:
gridplot.on()
Here is a way that you can do it. First you create the figure which will contain the axes object. With those axes you have something like a canvas, which is where every graph will be drawn.
fig, ax = plt.subplots(1,2)
Here I have created one figure with two axes. This is a one row and two columns figure. If you inspect the ax variable you will see two objects. This is what we'll use for all the plotting. Now, going back to the function, let's start with a simple dataset and define the function.
df = pd.DataFrame({"a": np.random.random(10), "b": np.random.random(10)})
def plt_graph(x, graph_title, horiz_label, ax):
df[x].plot(kind = 'barh', ax = ax)
ax.set_xlabel(horiz_label)
ax.set_title(graph_title)
Then, to call the function you will simply do this:
plt_graph("a", "a", "a", ax=ax[0])
plt_graph("b", "b", "b", ax=ax[1])
Note that you pass each graph that you want to create to any of the axes you have. In this case, as you have two, you pass the first to the first axes and so on. Note that if you include seaborn in your import (import seaborn as sns), automatically the seaborn style will be applied to your graphs.
This is how your graphs will look like.
When you are creating plotting functions, you want to look at matplotlib's object oriented interface.

Categories