I am using this code which provides nice plots one after the next (using IPython-notebook & Pandas)
for subsm in subsl:
H7, subsm = sumsubdesc2(table, subsm)
ax1=H7.plot()
plt.title('Rolling 4q mean %s'%(subsm))
ax1.set_title('Rolling 4q mean %s'%(subsm))
ax1.set_ylim(100000,600000)
I'd like to get the plots "2up" one next to the next for 3 rows total (5 subplots) can't figure out how to handle that since all the subplot examples seem to be for subplotting ether the data or specific plots and specific grid placement.
So I don't know how to create the main plot and then subplot a number of graphs (in this case 5) with titles as two-up?
Edit line two of code since I left out the function call ;-(
Here's what you need to do:
import math
import matplotlib.pylab as plt
nrows = int(math.ceil(len(subsl) / 2.))
fig, axs = plt.subplots(nrows, 2)
ylim = 100000, 600000
for ax, subsm in zip(axs.flat, subsl):
H7, subsm = sumsubdesc2(table, subsm)
H7.plot(ax=ax, title='Rolling 4q mean %s' % subsm)
ax.set_ylim(ylim)
This will work even if axs.size > len(subsl) since StopIteration is raised when the shortest iterable runs out. Note that axs.flat is an iterator over the row-order flattened axs array.
To hide the last plot that isn't showing, do this:
axs.flat[-1].set_visible(False)
More generally, for axs.size - len(subsl) extra plots at the end of the grid do:
for ax in axs.flat[axs.size - 1:len(subsl) - 1:-1]:
ax.set_visible(False)
That slice looks a little gnarly, so I'll explain:
The array axs has axs.size elements. The index of the last element of the flattened version of axs is axs.size - 1. subsl has len(subsl) elements and the same reasoning applies about the index of the last element. But, we need to move back from the last element of axs to the last plotted element so we need to step by -1.
I'm not sure, but I think what you're asking is
# not tested
import math
import matplotlib.pylab as plt
Nrows = math.ceil(len(subsl) / 2.)
for i in range(len(subsl)):
subsm = subsl[i]
H7, subsm = sumsubdesc2(table, subsm)
plt.subplot(Nrows, 2, i+1)
# do some plotting
plt.title('Rolling 4q mean %s'%(subsm))
I'm not sure what you mean by "titles as two-up."
Related
As my code is fairly long (typical for newy), I placed here a simplified example of my issue.
From this code instead of getting a subplot graph of the datas of all the loops on figure 1, I only get the last one. I would be kind of you to help me to understand my mistake.
from numpy import *
from matplotlib.pyplot import *
import math
from pylab import *
i=0
for i in range (0,10):
x=[i-1, i, i+1]
y=[3*i, 3*i, 3*i]
x1=[2-i, 3-i, 4-i]
y1=[i, i ,i]
plt.figure(1)
f,(ax1, ax2) = plt.subplots(1, 2, sharey=True)
ax1.plot(x,y)
ax2.plot(x1,y1)
if i==9:
plt.savefig('test.jpg')
plt.clf()
plt.figure(7)
plt.scatter(x1,y)
if i==9:
plt.savefig('test2.jpg')
Create the figure outside the loop, instead of re-creating it each iteration.
You may need to either break out your second plot into its own loop, or create a second figure outside the loop and specify which your subsequent call apply to.
This question already has answers here:
Matplotlib different size subplots
(6 answers)
Closed 1 year ago.
I have a script which is creating one or two charts, depending on if one specific condition is met or not. Really basically, what I am doing so far is the following:
import matplotlib.pyplot as plt
list1 = [1,2,3,4]
list2 = [4,3,2,1]
somecondition = True
plt.figure(1) #create one of the figures that must appear with the chart
ax = plt.subplot(211) #create the first subplot that will ALWAYS be there
ax.plot(list1) #populate the "main" subplot
if somecondition == True:
ax = plt.subplot(212) #create the second subplot, that MIGHT be there
ax.plot(list2) #populate the second subplot
plt.show()
This code (with the proper data, but this simple version that I did is executable anyway) generates two subplots of the same size, one above the other. However, what I would like to get is the following:
If somecondition is True, then both subplots should appear in the figure. Hence, I would like the second subplot to be 1/2 smaller than the first one;
If somecondition is False, then just the first subplot should appear and I would like it to be sized as the all figure (without leaving the empty space behind in the case the second subplot will not appear).
I'm pretty sure it's just a matter of sizing the two subplots, probably even by the parameter 211 and 212 (that I don't understand what they stand for, since I'm new to Python and couldn't find a clear explanation on the web yet). Does anyone know how to regulate the size of the subplots in a easy way, proportionally to the number of subplots as well as to the entire size of the figure? To make it easier to understand, could you also please edit my simple code I attached to get the result I'm looking for? Thanks in advance!
does this solution satisfy?
import matplotlib.pyplot as plt
list1 = [1,2,3,4]
list2 = [4,3,2,1]
somecondition = True
plt.figure(1) #create one of the figures that must appear with the chart
if not somecondition:
ax = plt.subplot(111) #create the first subplot that will ALWAYS be there
ax.plot(list1) #populate the "main" subplot
else:
ax = plt.subplot(211)
ax.plot(list1)
ax = plt.subplot(223) #create the second subplot, that MIGHT be there
ax.plot(list2) #populate the second subplot
plt.show()
If you need the same width but with half height, better to use matplotlib.gridspec, reference here
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
list1 = [1,2,3,4]
list2 = [4,3,2,1]
somecondition = True
plt.figure(1) #create one of the figures that must appear with the chart
gs = gridspec.GridSpec(3,1)
if not somecondition:
ax = plt.subplot(gs[:,:]) #create the first subplot that will ALWAYS be there
ax.plot(list1) #populate the "main" subplot
else:
ax = plt.subplot(gs[:2, :])
ax.plot(list1)
ax = plt.subplot(gs[2, :]) #create the second subplot, that MIGHT be there
ax.plot(list2) #populate the second subplot
plt.show()
It seems you are looking for this:
if somecondition:
ax = plt.subplot(3,1,(1,2))
ax.plot(list1)
ax = plt.subplot(3,1,3)
ax.plot(list2)
else:
plt.plot(list1)
The magic numbers are nrows, ncols, plot_number, see the documentation. So 3,1,3 will create 3 rows, 1 column, and will plot into the third cell. An abbreviation for that is 313.
It's possible to use tuple as plot_number, so you can create a plot which lives in the first and second cell: 3,1,(1,2).
I am building a bar chart using matplotlib using the code below. When my first or last column of data is 0, my first column is wedged against the Y-axis.
An example of this. Note that the first column is ON the x=0 point.
If I have data in this column, I get a huge padding between the Y-Axis and the first column as seen here. Note the additional bar, now at X=0. This effect is repeated if I have data in my last column as well.
My code is as follows:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator
binVals = [0,5531608,6475325,1311915,223000,609638,291151,449434,1398731,2516755,3035532,2976924,2695079,1822865,1347155,304911,3562,157,5,0,0,0,0,0,0,0,0]
binTot = sum(binVals)
binNorm = []
for v in range(len(binVals)):
binNorm.append(float(binVals[v])/binTot)
fig = plt.figure(figsize=(6,4))
ax1 = fig.add_subplot(1,1,1)
ax1.bar(range(len(binNorm)),binNorm,align='center', label='Values')
plt.legend(loc=1)
plt.title("Demo Histogram")
plt.xlabel("Value")
plt.xticks(range(len(binLabels)),binLabels,rotation='vertical')
plt.grid(b=True, which='major', color='grey', linestyle='--', alpha=0.35)
ax1.xaxis.grid(False)
plt.ylabel("% of Count")
plt.subplots_adjust(bottom=0.15)
plt.tight_layout()
plt.show()
How can I set a constant margin between the Y-axis and my first/last bar?
Additionally, I realize it's labeled "Demo Histogram", that is a because I missed it when correcting problems discussed here.
I can't run the code snippet you gave, and even with some modification I couldn't replicate the big space. Aside from that, if you need to enforce a border to matplotlib, you ca do somthing like this:
ax.set_xlim( min(your_data) - 10, None )
The first term tells the axis to put the border at 10 units of distance from the minimum of your data, the None parameter teels it to keep the present value.
to put it into contest:
from collections import Counter
from pylab import *
data = randint(20,size=1000)
res = Counter(data)
vals = arange(20)
ax = gca()
ax.bar(vals-0.4, [ res[i] for i in vals ], width=0.8)
ax.set_xlim( min(data)-1, None )
show()
searching around stackoverflow I just learned a new trick: you can call
ax.margins( margin_you_desire )
to let automatically let matplotlib put that amount of space around your plot. It can also be configured differently between x and y.
In your case the best solution would be something like
ax.margins(0.01, None)
The little catch is that the unit is in axes unit, referred to the size of you plot, so a margin of 1 will put space around your plot at both sizes big as your present plot
The problem is align='center'. Remove it.
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.
I have written code that opens 16 figures at once. Currently, they all open as separate graphs. I'd like them to open all on the same page. Not the same graph. I want 16 separate graphs on a single page/window. Furthermore, for some reason, the format of the numbins and defaultreallimits doesn't hold past figure 1. Do I need to use the subplot command? I don't understand why I would have to but can't figure out what else I would do?
import csv
import scipy.stats
import numpy
import matplotlib.pyplot as plt
for i in range(16):
plt.figure(i)
filename= easygui.fileopenbox(msg='Pdf distance 90m contour', title='select file', filetypes=['*.csv'], default='X:\\herring_schools\\')
alt_file=open(filename)
a=[]
for row in csv.DictReader(alt_file):
a.append(row['Dist_90m(nmi)'])
y= numpy.array(a, float)
relpdf=scipy.stats.relfreq(y, numbins=7, defaultreallimits=(-10,60))
bins = numpy.arange(-10,60,10)
print numpy.sum(relpdf[0])
print bins
patches=plt.bar(bins,relpdf[0], width=10, facecolor='black')
titlename= easygui.enterbox(msg='write graph title', title='', default='', strip=True, image=None, root=None)
plt.title(titlename)
plt.ylabel('Probability Density Function')
plt.xlabel('Distance from 90m Contour Line(nm)')
plt.ylim([0,1])
plt.show()
The answer from las3rjock, which somehow is the answer accepted by the OP, is incorrect--the code doesn't run, nor is it valid matplotlib syntax; that answer provides no runnable code and lacks any information or suggestion that the OP might find useful in writing their own code to solve the problem in the OP.
Given that it's the accepted answer and has already received several up-votes, I suppose a little deconstruction is in order.
First, calling subplot does not give you multiple plots; subplot is called to create a single plot, as well as to create multiple plots. In addition, "changing plt.figure(i)" is not correct.
plt.figure() (in which plt or PLT is usually matplotlib's pyplot library imported and rebound as a global variable, plt or sometimes PLT, like so:
from matplotlib import pyplot as PLT
fig = PLT.figure()
the line just above creates a matplotlib figure instance; this object's add_subplot method is then called for every plotting window (informally think of an x & y axis comprising a single subplot). You create (whether just one or for several on a page), like so
fig.add_subplot(111)
this syntax is equivalent to
fig.add_subplot(1,1,1)
choose the one that makes sense to you.
Below I've listed the code to plot two plots on a page, one above the other. The formatting is done via the argument passed to add_subplot. Notice the argument is (211) for the first plot and (212) for the second.
from matplotlib import pyplot as PLT
fig = PLT.figure()
ax1 = fig.add_subplot(211)
ax1.plot([(1, 2), (3, 4)], [(4, 3), (2, 3)])
ax2 = fig.add_subplot(212)
ax2.plot([(7, 2), (5, 3)], [(1, 6), (9, 5)])
PLT.show()
Each of these two arguments is a complete specification for correctly placing the respective plot windows on the page.
211 (which again, could also be written in 3-tuple form as (2,1,1) means two rows and one column of plot windows; the third digit specifies the ordering of that particular subplot window relative to the other subplot windows--in this case, this is the first plot (which places it on row 1) hence plot number 1, row 1 col 1.
The argument passed to the second call to add_subplot, differs from the first only by the trailing digit (a 2 instead of a 1, because this plot is the second plot (row 2, col 1).
An example with more plots: if instead you wanted four plots on a page, in a 2x2 matrix configuration, you would call the add_subplot method four times, passing in these four arguments (221), (222), (223), and (224), to create four plots on a page at 10, 2, 8, and 4 o'clock, respectively and in this order.
Notice that each of the four arguments contains two leadings 2's--that encodes the 2 x 2 configuration, ie, two rows and two columns.
The third (right-most) digit in each of the four arguments encodes the ordering of that particular plot window in the 2 x 2 matrix--ie, row 1 col 1 (1), row 1 col 2 (2), row 2 col 1 (3), row 2 col 2 (4).
Since this question is from 4 years ago new things have been implemented and among them there is a new function plt.subplots which is very convenient:
fig, axes = plot.subplots(nrows=2, ncols=3, sharex=True, sharey=True)
where axes is a numpy.ndarray of AxesSubplot objects, making it very convenient to go through the different subplots just using array indices [i,j].
To answer your main question, you want to use the subplot command. I think changing plt.figure(i) to plt.subplot(4,4,i+1) should work.
This works also:
for i in range(19):
plt.subplot(5,4,i+1)
It plots 19 total graphs on one page. The format is 5 down and 4 across..
#doug & FS.'s answer are very good solutions. I want to share the solution for iteration on pandas.dataframe.
import pandas as pd
df=pd.DataFrame([[1, 2], [3, 4], [4, 3], [2, 3]])
fig = plt.figure(figsize=(14,8))
for i in df.columns:
ax=plt.subplot(2,1,i+1)
df[[i]].plot(ax=ax)
print(i)
plt.show()
For example, to create 6 subplots with 2 rows and 3 columns you can use:
funcs = [np.cos, np.sin, np.tan, np.arctan]
x = np.linspace(0, 10, 100)
fig = plt.figure(figsize=(10, 5))
for num, func in enumerate(funcs, start=1):
ax = fig.add_subplot(2, 2, num) # plot with 2 rows and 2 columns
ax.plot(x, func(x))
ax.set_title(func.__name__)
# add spacing between subplots
fig.tight_layout()
Result: