I use Python lib matplotlib to plot functions, and I know how to plot several functions in different subplots in one figure, like this one,
And when handling images, I use imshow() to plot images, but how to plot multiple images together in different subplots with one figure?
The documentation provides an example (about three quarters of the way down the page):
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
fig = plt.figure()
a=fig.add_subplot(1,2,1)
img = mpimg.imread('../_static/stinkbug.png')
lum_img = img[:,:,0]
imgplot = plt.imshow(lum_img)
a.set_title('Before')
plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation ='horizontal')
a=fig.add_subplot(1,2,2)
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0.0,0.7)
a.set_title('After')
plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation='horizontal')
# ---------------------------------------
# if needed inside the application logic, uncomment to show the images
# plt.show()
Basically, it's the same as you do normally with creating axes with fig.add_subplot...
Simple python code to plot subplots in a figure;
rows=2
cols=3
fig, axes = plt.subplots(rows,cols,figsize=(30,10))
plt.subplots_adjust(wspace=0.1,hspace=0.2)
features=['INDUS','RM', 'AGE', 'DIS','PTRATIO','MEDV']
plotnum=1
for idx in features:
plt.subplot(rows,cols,plotnum)
sns.distplot(data[idx])
plotnum=plotnum+1
plt.savefig('subplots.png')
go through below link for more detail
https://exploredatalab.com/how-to-plot-multiple-subplots-in-python-with-matplotlib/
Related
I am trying to create a grid of images (e.g. 3 by 3) from a batch of tensors that will be fed into a GAN through a data loader in the next step. With the below code I was able to transform the tensors into images that are displayed in a grid in the right position. The problem is, that they are all displayed in a separate grid as shown here: Figure 1 Figure 2 Figure 5. How can put them in one grid and just get one figure returned with all 9 images?? Maybe I am making it too complicated. :D In the end tensors out of the real_samples have to be transformed and put into a grid.
real_samples = next(iter(train_loader))
for i in range(9):
plt.figure(figsize=(9, 9))
plt.subplot(330 + i + 1)
plt.imshow(np.transpose(vutils.make_grid(real_samples[i].to(device)
[:40], padding=1, normalize=True).cpu(),(1,2,0)))
plt.show()
And here is how to display a variable number of wonderful CryptoPunks using matplotlib XD:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import matplotlib.image as mpimg
row_count = 3
col_count = 3
cryptopunks = [
mpimg.imread(f"cryptopunks/{i}.png") for i in range(row_count * col_count)
]
fig = plt.figure(figsize=(8., 8.))
grid = ImageGrid(fig, 111, nrows_ncols=(row_count, col_count), axes_pad=0.1)
for ax, im in zip(grid, cryptopunks):
ax.imshow(im)
plt.show()
Please note that the code allows you to generate all the images you want, not only 3 times 3. I have a folder called cryptopunks with a lot of images called #.png (e.g., 1.png, ..., 34.png, ...). Just change the row_count and col_count variable values. For instance, for row_count=6 and col_count=8 you get:
If your image files do not have that naming pattern above (i.e., just random names), just replace the first lines with the following ones:
import os
from pathlib import Path
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import matplotlib.image as mpimg
for root, _, filenames in os.walk("cryptopunks/"):
cryptopunks = [
mpimg.imread(Path(root, filename)) for filename in filenames
]
row_count = 3
col_count = 3
# Here same code as above.
(I have downloaded the CryptoPunks dataset from Kaggle.)
For a 9 image grid you probably want three rows and three columns. Probably the simplest way to do that is something like so:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=3, ncols=3)
axes = axes.flatten() # Flattens the array so you can access individual axes
for ax in axes:
# Do stuff with your individual axes here
plt.show() # This call is here just for example, prob. better call outside of the loop
which outputs the following axes configuration with plt.tight_layout():
You might also be interested in the matplotlib mosaic functionality or gridspec one. Hope this helps.
EDIT: Here's a solution which annotates each plot with its number so you can see what goes where as well:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=3, ncols=3)
axes = axes.flatten()
for idx, ax in enumerate(axes):
ax.annotate(f"{idx+1}", xy=(0.5, 0.5), xytext=(0.5, 0.5))
Matplotlib provides a function called subplot, I think this is what you are searching for!
plt.subplot(9,1) is the syntax I guess.
And then configure your plots
I'm using matplotlib to plot many histograms in one plot successfully:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
for i in range(0, 6):
data = np.random.normal(size=1000)
plt.hist(data, bins=30, alpha = 0.5)
plt.show()
However, I wish to export this plot in a pdf, using PdfPages. I want to add each histogram in a separate page, which I successfully do like this:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
np.random.seed(1)
fig = []
with PdfPages("exported_data.pdf") as pdf:
for i in range(0, 6):
data = np.random.normal(size=1000)
fig.append(plt.hist(data, bins=30, alpha = 0.5))
pdf.savefig(fig[i])
plt.close()
But I want another, 7th page with all the plots in one figure as shown above. How do I add many histograms in the same figure (so I can then add in the pdf page)? I see many tutorials on how to plot a grid of histograms within a figure but I haven't found one with all the histograms in one plot added to a figure.
Thanks,
Stam
You can run the loop to plot all histograms together (your first code snippet) after having run the loop to plot them separately (your second code snippet). Here is an example where the random arrays are saved in the datasets list during the first loop to be able to plot them together in the second loop. This solution works by using plt.gcf() which returns the current figure.
import numpy as np # v 1.19.2
import matplotlib.pyplot as plt # v 3.3.4
from matplotlib.backends.backend_pdf import PdfPages
np.random.seed(1)
datasets = []
with PdfPages("exported_data.pdf") as pdf:
# Plot each histogram, adding each figure to the pdf
for i in range(6):
datasets.append(np.random.normal(size=1000))
plt.hist(datasets[i], bins=30, alpha = 0.5)
pdf.savefig(plt.gcf())
plt.close()
# Plot histograms together using a loop then add the completed figure to the pdf
for data in datasets:
plt.hist(data, bins=30, alpha = 0.5)
pdf.savefig(plt.gcf())
plt.close()
I am trying to finish a task for a project and my task is to create a histogram of yearly returns of Dow Jones historical returns. I have uploaded a picture of the task and my progress below. The problem I have at this point is that I can't find a way to separate the years in the histogram as it shows in the task and I don't know how to modify the y-axix and the legend to show the information that is showing in the first picture.
Any help is appreciated
What I am trying to make and My progress so far
Here is my code:
# Importing packages
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
#setting the order
order=[-60,-50,-40,-30,-20,-10,
0,10,20,30,40,50,60,70]
#getting the data
dow_jones_returns = pd.read_csv('data/dow-jones-by-year-historical-annual-returns (2).csv')
dow_jones=pd.DataFrame(data=dow_jones_returns)
dow_jones['date']=pd.to_datetime(dow_jones['date'])
dow_jones['date']=pd.DatetimeIndex(dow_jones['date']).year
pd.to_numeric(dow_jones.value)
up_to_2019=dow_jones.iloc[0:99]
lastyear= dow_jones.iloc[-1]
#ploting the histogram
fig = plt.figure()
up_to_2019['value'].plot.hist(bins = order)
plt.show()
Hi to just give you some further directions,
Regarding the Textbox
the textbox looks like it contains the summary statistics of DataFrame.describe() + a few additional ones. You can create a textbox by utilzing a combination of .text() and .subplot()
I found this guide to be very useful for creating a textbox in a plot
Since we dont have the data,
here a pseudo code:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
textstr = str(up_to_2019['value'].describe())
ax.hist(up_to_2019['value'], bins = order)
# these are matplotlib.patch.Patch properties
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
# place a text box in upper left in axes coords
ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=10,
verticalalignment='top', bbox=props)
plt.show()
Regarding the y-axis:
1) Here is how you set the right label: plt.ylabel("Number of Observations\n(Probability in%)")
2) Than add the Ticks plt.yticks(np.arange(1,27))
Regarding the labels inside the bins
Thats rather tricky, one option, though definitely not advised would to also include the labels via the .text() method. I dont know if it helps but here is how you do this in R.
Also might helpful are these two links:
how-to-add-a-text-into-a-rectangle
Change color for the patches in a hist
Apparently calling plt.hist() has three return values one of which is callled patches. You can iterate over patches and i.e. change the color of these (see the link above) however I couldn't figure how to put a text to them.
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
x = [21,22,23,4,5,6,77,8,9,10,31,32,33,34,35,36,37,18,49,50,100]
num_bins = 5
n, bins, patches = plt.hist(x, num_bins, facecolor='blue', alpha=0.5)
for i,pat in enumerate(patches):
pat.set_test("Test") #this doesnt work sadly
I'm trying to get my figures in just one pdf page, but I don't know how to do this. I found out that it's possible to save multiple figures in a pdf file with 'matplotlib.backends.backend_pdf', but it doesn't work for just one page.
Has anyone any ideas ? Convert the figures to just one figure ?
You can use matplotlib gridspec to have multiple plots in 1 window
http://matplotlib.org/users/gridspec.html
from matplotlib.gridspec import GridSpec
import random
import numpy
from matplotlib import pyplot as pl
fig = pl.figure(figsize=(12, 16))
G = GridSpec(2,2)
axes_1 = pl.subplot(G[0, :])
x = [random.gauss(3,1) for _ in range(400)]
bins = numpy.linspace(-10, 10, 100)
axes_1.hist(x, bins, alpha=0.5, label='x')
axes_2 = pl.subplot(G[1, :])
axes_2.plot(x)
pl.tight_layout()
pl.show()
You can change the rows and column values and can subdivide the sections.
The PDF backend makes one page per figure. Use subplots to get multiple plots into one figure and they'll all show up together on one page of the PDF.
Here is a solution provided by matplotlib:
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
with PdfPages('foo.pdf') as pdf:
#As many times as you like, create a figure fig and save it:
fig = plt.figure()
pdf.savefig(fig)
....
fig = plt.figure()
pdf.savefig(fig)
VoilĂ
Find a full example here: multipage pdf matplotlib
And by the way, for one figure, you don't need matplotlib.backends.backend_pdf just add pdf extension like so:
plt.savefig("foo.pdf")
I have a loop to generate millions of histograms in python and i need to store them all in one folder in my laptop is there a way to save them all without the need of pressing save button each time a histogram generated?
Thanks
If you're using matplotlib, then what you are looking for is plt.savefig(). The documentation is here: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.savefig
For example:
import matplotlib.pyplot as plt
import numpy as np
# Some random data:
x = np.random.rand(100)
fig = plt.figure(1) # create a figure instance
ax = fig.add_subplot(111) # and axes
ax.hist(x) # plot the histogram
# plt.show() # this would show the plot, but you can leave it out
# Save the figure to the current path
fig.savefig('test_image.png')