plot matplotlib subplots indefinitely? - python

say I was testing a range of parameters of a clustering algorithm and I wanted to write python code that would plot all the results of the algorithm in subplots 2 to a row
is there a way to do this without pre-calculating how many total plots you would need?
something like:
for c in range(3,10):
k = KMeans(n_clusters=c)
plt.subplots(_, 2, _)
plt.scatter(data=data, x='x', y='y', c=k.fit_predict(data))
... and then it would just plot 'data' with 'c' clusters 2 plots per row until it ran out of stuff to plot.
thanks!

This answer from the question Dynamically add/create subplots in matplotlib explains a way to do it:
https://stackoverflow.com/a/29962074/3827277
verbatim copy & paste:
import matplotlib.pyplot as plt
# Start with one
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])
# Now later you get a new subplot; change the geometry of the existing
n = len(fig.axes)
for i in range(n):
fig.axes[i].change_geometry(n+1, 1, i+1)
# Add the new
ax = fig.add_subplot(n+1, 1, n+1)
ax.plot([4,5,6])
plt.show()

Related

How to plot multiple plots using for loop

a=pd.DataFrame({'length':[20,10,30,40,50],
'width':[5,10,15,20,25],
'height':[7,14,21,28,35]})
for i,feature in enumerate(a,1):
sns.regplot(x = feature,y= 'height',data = a)
print("{} plotting {} ".format(i,feature))
I want to plot 3 different plots with three different columns i.e 'length','width' and 'height' on x-axis and 'height' on y-axis in each one of them .
This is the code i wrote but it overlays 3 different plots over one another.I intend to plot 3 different plots.
It depends on what you want to do. It you want several individual plots, you can create a new figure for each dataset:
import matplotlib.pyplot as plt
for i, feature in enumerate(a, 1):
plt.figure() # forces a new figure
sns.regplot(data=a, x=feature, y='height')
print("{} plotting {} ".format(i,feature))
Alternatively, you can draw them all on the same figure, but in different subplots. I.E next to each other:
import matplotlib.pyplot as plt
# create a figure with 3 subplots
fig, axes = plt.subplots(1, a.shape[1])
for i, (feature, ax) in enumerate(zip(a, axes), 1):
sns.regplot(data=a, x=feature, y='height', ax=ax)
print("{} plotting {} ".format(i,feature))
plt.subplots has several options that allow you to align the plots the way you like. check the docs for more on that!

Creating a matrix of plots with sns distplot

I am plotting 20+ features like so:
for col in dsd_mod["ae_analysis"].columns[:len(dsd_mod["ae_analysis"].columns)]:
if col != "sae_flag":
sns.distplot(dsd_mod["ae_analysis"].loc[(dsd_mod["ae_analysis"]['sae_flag'] == 1),col],
color='r',
kde=True,
hist=False,
label='sae_ae = 1')
sns.distplot(dsd_mod["ae_analysis"].loc[(dsd_mod["ae_analysis"]['sae_flag'] == 0),col],
color='y',
kde=True,
hist=False,
label='sae_ae = 0')
Which creates a separate graph for each feature. How can I put these all on a matrix? Or like how pair plots outputs?
Right now I get 30 graphs like this all in one column:
How can I modify this so that I can get 6 rows and 5 columns ?
Thanks in advance!
displot can use whatever axes object you want to draw the plot. So you just need to create your axes with the desired geometry, and pass the relevant axes to your functions.
fig, axs = plt.subplots(6,5)
# axs is a 2D array with shape (6,5)
# you can keep track of counters in your for-loop to place the resulting graphs
# using ax=axs[i,j]
# or an alternative is to use a generator that you can use to get the next axes
# instance at every step of the loop
ax_iter = iter(axs.flat)
for _ in range(30):
ax = next(ax_iter)
sns.distplot(np.random.normal(loc=0, size=(1000,)), ax=ax)
sns.distplot(np.random.normal(loc=1, size=(1000,)), ax=ax)

Empty figures in python and cannot save the figure

Here is the code of plotting the figures. But why are there always two empty figures before the third expected figure, it seems I created two blank fig.
And I cannot save the figure in my local computer fig.savefig('Sens.png'). There is an error The C++ part of the object has been deleted, attribute access no longer allowed(actually successfully saved only for one time).
fig = plt.figure(figsize=(10,10))
m = 1
for s in dataList:
plt.subplot(2,2,m)
f = interp1d(FXSpotList, s, 'cubic')
xnew = np.linspace(FXSpotList[0], FXSpotList[-1], 40, True)
plt.plot(xnew, f(xnew), '-')
plt.xlabel('Spot')
plt.ylabel(titleList[m-1])
plt.axvline(x=tradeTest.Pair().Spot(), linestyle='--')
plt.axhline(y=0, linestyle='--')
m = m + 1
plt.figtext(0.5, 0.01, 'Type='+str(tradeTest.Types()[0]), ha='center')
plt.tight_layout()
plt.show()
plt.close()
fig.savefig('Sens.png')
Although you did not provide a Minimal, Complete, and Verifiable example, it is obvious that there are things wrong with your loop construction. You show, close, then save the plot in every loop, which is probably not, what you are intending to do. A minimal example of your loop would be
import numpy as np
from matplotlib import pyplot as plt
#sample list to iterate over
dataList = ["fig1", "fig2", "fig3"]
plt.figure(figsize=(10,10))
#loop over the list, retrieve data entries and index
for i, s in enumerate(dataList):
#define position of the plot in a 2 x 2 grid
plt.subplot(2, 2, i + 1)
#random plot, insert your calculations here
plt.plot(range(3), np.random.randint(0, 10, 3))
#utilize list data
plt.title(s)
#save figure
plt.savefig('test.png')
#show figure
plt.show()

Dynamically add/create subplots in matplotlib

I want to create a plot consisting of several subplots with shared x/y axes.
It should look something like this from the documentation (though my subplots will be scatterblots): (code here)
But I want to create the subplots dynamically!
So the number of subplots depends on the output of a previous function. (It will probably be around 3 to 15 subplots per diagram, each from a distinct dataset, depending on the input of my script.)
Can anyone tell me how to accomplish that?
Suppose you know total subplots and total columns you want to use:
import matplotlib.pyplot as plt
# Subplots are organized in a Rows x Cols Grid
# Tot and Cols are known
Tot = number_of_subplots
Cols = number_of_columns
# Compute Rows required
Rows = Tot // Cols
# EDIT for correct number of rows:
# If one additional row is necessary -> add one:
if Tot % Cols != 0:
Rows += 1
# Create a Position index
Position = range(1,Tot + 1)
First instance of Rows accounts only for rows completely filled by subplots, then is added one more Row if 1 or 2 or ... Cols - 1 subplots still need location.
Then create figure and add subplots with a for loop.
# Create main figure
fig = plt.figure(1)
for k in range(Tot):
# add every single subplot to the figure with a for loop
ax = fig.add_subplot(Rows,Cols,Position[k])
ax.plot(x,y) # Or whatever you want in the subplot
plt.show()
Please note that you need the range Position to move the subplots into the right place.
import matplotlib.pyplot as plt
from pylab import *
import numpy as np
x = np.linspace(0, 2*np.pi, 400)
y = np.sin(x**2)
subplots_adjust(hspace=0.000)
number_of_subplots=3
for i,v in enumerate(xrange(number_of_subplots)):
v = v+1
ax1 = subplot(number_of_subplots,1,v)
ax1.plot(x,y)
plt.show()
This code works but you will need to correct the axes. I used to subplot to plot 3 graphs all in the same column. All you need to do is assign an integer to number_of_plots variable. If the X and Y values are different for each plot you will need to assign them for each plot.
subplot works as follows, if for example I had a subplot values of 3,1,1. This creates a 3x1 grid and places the plot in the 1st position. In the next interation if my subplot values were 3,1,2 it again creates a 3x1 grid but places the plot in the 2nd position and so forth.
Based on this post, what you want to do is something like this:
import matplotlib.pyplot as plt
# Start with one
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])
# Now later you get a new subplot; change the geometry of the existing
n = len(fig.axes)
for i in range(n):
fig.axes[i].change_geometry(n+1, 1, i+1)
# Add the new
ax = fig.add_subplot(n+1, 1, n+1)
ax.plot([4,5,6])
plt.show()
However, Paul H's answer points to the submodule called gridspec which might make the above easier. I am leaving that as an exercise for the reader ^_~.
Instead of counting your own number of rows and columns, I found it easier to create the subplots using plt.subplots first, then iterate through the axes object to add plots.
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(nrows=3, ncols=2, figsize=(12, 8))
x_array = np.random.randn(6, 10)
y_array = np.random.randn(6, 10)
i = 0
for row in axes:
for ax in row:
x = x_array[i]
y = y_array[i]
ax.scatter(x, y)
ax.set_title("Plot " + str(i))
i += 1
plt.tight_layout()
plt.show()
Here I use i to iterate through elements of x_array and y_array, but you can likewise easily iterate through functions, or columns of dataframes to dynamically generate graphs.

Python Subplot function parameters

I am having a hard time with putting in the parameters for the python subplot function.
What I want is to plot 4 graphs on a same image file with the following criteria
left
space
right
space
left
space
right
I have tried different ways of the 3 numbers but the output doesnt show up correctly.
Do you mean something like this?
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(4,2,1)
ax2 = fig.add_subplot(4,2,4)
ax3 = fig.add_subplot(4,2,5)
ax4 = fig.add_subplot(4,2,8)
fig.subplots_adjust(hspace=1)
plt.show()
Well, the not-so-easily-found documentation regarding the sublot function template is as follows:
subplot (number_of_graphs_horizontal, number of graphs_vertical, index)
Let us investigate the code from Joe Kington above:
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(4,2,1)
ax2 = fig.add_subplot(4,2,4)
ax3 = fig.add_subplot(4,2,5)
ax4 = fig.add_subplot(4,2,8)
fig.subplots_adjust(hspace=1)
plt.show()
You told matplotlib that you want a grid with 4 rows and 2 columns of graphs. ax1, ax2 and so on are the graphs that you add at the index positions which you can read as the third parameter. You count from left to right in a row-wise manner.
I hope that helped :)
Matplotlib provides several ways deal with the deliberate placement of plots on a single page; i think the best is gridspec, which i believe first appeared in the 1.0 release. The other two, by the way, are (i) directly indexing subplot and (ii) the new ImageGrid toolkit).
GridSpec works like grid-based packers in GUI toolkits used to placed widgets in a parent frame, so for that reason at least, it seems the easiest to use and the most configurable of the three placement techniques.
import numpy as NP
import matplotlib.pyplot as PLT
import matplotlib.gridspec as gridspec
import matplotlib.cm as CM
V = 10 * NP.random.rand(10, 10) # some data to plot
fig = PLT.figure(1, (5., 5.)) # create the top-level container
gs = gridspec.GridSpec(4, 4) # create a GridSpec object
# for the arguments to subplot that are identical across all four subplots,
# to avoid keying them in four times, put them in a dict
# and let subplot unpack them
kx = dict(frameon = False, xticks = [], yticks = [])
ax1 = PLT.subplot(gs[0, 0], **kx)
ax3 = PLT.subplot(gs[2, 0], **kx)
ax2 = PLT.subplot(gs[1, 1], **kx)
ax4 = PLT.subplot(gs[3, 1], **kx)
for itm in [ax1, ax2, ax3, ax4] :
itm.imshow(V, cmap=CM.jet, interpolation='nearest')
PLT.show()
Beyond just arranging the four plots in a 'checkerboard' configuration (per your Question), I have not tried to tune this configuration, but that's easy to do. E.g.,
# to change the space between the cells that hold the plots:
gs1.update(left=.1, right=,1, wspace=.1, hspace=.1)
# to create a grid comprised of varying cell sizes:
gs = gridspec.GridSpec(4, 4, width_ratios=[1, 2], height_ratios=[4, 1])

Categories

Resources