Plotting to 1 figure using multiple functions with Matplotlib, Python - python

I have a main program main.py in which I call various functions with the idea that each function plots something to 1 figure. i.e. all the function plots append detail to the 1 main plot.
Currently I have it set up as, for example:
main.py:
import matplotlib.pylab as plt
a,b,c = 1,2,3
fig = func1(a,b,c)
d,e,f = 4,5,6
fig = func2(d,e,f)
plt.show()
func1:
def func1(a,b,c):
import matplotlib.pylab as plt
## Do stuff with a,b and c ##
fig = plt.figure()
plt.plot()
return fig
func2:
def func2(d,e,f):
import matplotlib.pylab as plt
## Do stuff with d,e and f ##
fig = plt.figure()
plt.plot()
return fig
This approach is halfway there but it plots separate figures for each function instead of overlaying them.
How can I obtain 1 figure with the results of all plots overlaid on top of each other?

It is much better to use the OO interface for this puprose. See http://matplotlib.org/faq/usage_faq.html#coding-styles
import matplotlib.pyplot as plt
a = [1,2,3]
b = [3,2,1]
def func1(ax, x):
ax.plot(x)
def func2(ax, x):
ax.plot(x)
fig, ax = plt.subplots()
func1(ax, a)
func2(ax, b)
It seems silly for simple functions like this, but following this style will make things much much less painful when you want to do something more sophisticated.

This should work. Note that I only create one figure and use the pyplot interface to plot to it without ever explicitly obtaining a reference to the figure object.
import matplotlib.pyplot as plt
a = [1,2,3]
b = [3,2,1]
def func1(x):
plt.plot(x)
def func2(x):
plt.plot(x)
fig = plt.figure()
func1(a)
func2(b)

Related

Saving multiple subplots into one pdf using different functions

I have a user choose 4 directories using tkinter in "loadingfiles." From there, it loads all of the files from each directory.
how would I be able to save all of the subplots into a PDF. I know I have to do it from the main function, but how would I go about this?
def loadingfiles():
#loads all of the files from each directory
#returns Files
def initialize_and_Calculate(Files=[],*args):
fig = plt.figure()
fig.set_size_inches(9,5,forward=True)
gs1=gridspec.GridSpec(1,2)
ax0=fig.add_subplot(gs1[0,0])
ax1=fig.add_subplot(gs1[0,1])
#treat x and y as a parameter within a file in a directory. Can be any numbers
ax0.plot(x,y,'-')
ax1.plot(x1,y1,'-')
fig.tight_layout()
def main():
Files=loadingfiles() #this loads the files in directory
L=len(Files)
for c in range (0,L): #this for loops runs the initialize_and_Calc. function per directory.
initialize_and_Calculate(Files[c]) #'File[0]' is directory 1. 'File[1]' is directory 2...and so on
plt.show()
if __name__=="__main__":
main()
If this doesn't make any sense, then how can I pass a 'fig' in a function. Say if I were to make a figure in my main function, how can I pass 'fig' to a function?
You may return the figure from the function and append it to a list. Then you may loop through the list and save the figures to a pdf file.
from matplotlib import gridspec
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np
def loadingfiles():
return range(4)
def initialize_and_Calculate(Files=[],*args):
fig = plt.figure()
fig.set_size_inches(9,5,forward=True)
gs1=gridspec.GridSpec(1,2)
ax0=fig.add_subplot(gs1[0,0])
ax1=fig.add_subplot(gs1[0,1])
x,y = zip(*np.cumsum(np.random.rand(20,2), axis=0))
ax0.plot(x,y,'-')
#ax1.plot(x1,y1,'-')
fig.tight_layout()
return fig
def main():
Files=loadingfiles()
figures = []
for c in range (0,len(Files)):
figures.append(initialize_and_Calculate(Files[c]))
with PdfPages('multipage_pdf.pdf') as pdf:
for f in figures:
pdf.savefig(f)
plt.show()
if __name__=="__main__":
main()
Of course you may also create the figure inside a loop in the main function and pass it as argument to the plotting function.
from matplotlib import gridspec
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np
def loadingfiles():
return range(4)
def initialize_and_Calculate(Files, fig ,*args):
fig.set_size_inches(9,5,forward=True)
gs1=gridspec.GridSpec(1,2)
ax0=fig.add_subplot(gs1[0,0])
ax1=fig.add_subplot(gs1[0,1])
x,y = zip(*np.cumsum(np.random.rand(20,2), axis=0))
ax0.plot(x,y,'-')
#ax1.plot(x1,y1,'-')
fig.tight_layout()
def main():
Files=loadingfiles()
figures = []
for c in range (0,len(Files)):
fig = plt.figure()
initialize_and_Calculate(Files[c], fig)
figures.append(fig)
with PdfPages('multipage_pdf.pdf') as pdf:
for f in figures:
pdf.savefig(f)
plt.show()
if __name__=="__main__":
main()

Retrieving all matplotlib axes in a Figure instance: should I use figure.get_axes() or figure.axes?

Simple question: what is the difference between
import matplotlib.pyplot as plt
f = plt.figure()
a = f.get_axes()
and
f = plt.figure()
a = f.axes
for retrieving all axes in a Figure instance? Are there situations where either would be preferable?`
The sourcecode for get_axes is:
def get_axes(self):
return self.axes
It therefore makes absolutely no difference at all which one you use.

python lineplot with color according to y values

I am quite a beginner in coding ... Im trying to plot curves from 2columns xy data with full line not scatter. I want y to be colored according to the value of y.
I can make it work for scatter but not for line plot.
my code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
read data ... (data are xy 2 columns so one can simply use 2 lists, say a and b)
# a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
# b = [11,12,3,34,55,16,17,18,59,50,51,42,13,14,35,16,17]
fig = plt.figure()
ax = fig.add_subplot(111)
bnorm = []
for i in b:
i = i/float(np.max(b)) ### normalizing the data
bnorm.append(i)
plt.scatter(a, b, c = plt.cm.jet(bnorm))
plt.show()
with scatter it works ...
how can I make it as a line plot with colors ? something like this:

How to assign a plot to a variable and use the variable as the return value in a Python function

I am creating two Python scripts to produce some plots for a technical report. In the first script I am defining functions that produce plots from raw data on my hard-disk. Each function produces one specific kind of plot that I need. The second script is more like a batch file which is supposed to loop around those functions and store the produced plots on my hard-disk.
What I need is a way to return a plot in Python. So basically I want to do this:
fig = some_function_that_returns_a_plot(args)
fig.savefig('plot_name')
But what I do not know is how to make a plot a variable that I can return. Is this possible? Is so, how?
You can define your plotting functions like
import numpy as np
import matplotlib.pyplot as plt
# an example graph type
def fig_barh(ylabels, xvalues, title=''):
# create a new figure
fig = plt.figure()
# plot to it
yvalues = 0.1 + np.arange(len(ylabels))
plt.barh(yvalues, xvalues, figure=fig)
yvalues += 0.4
plt.yticks(yvalues, ylabels, figure=fig)
if title:
plt.title(title, figure=fig)
# return it
return fig
then use them like
from matplotlib.backends.backend_pdf import PdfPages
def write_pdf(fname, figures):
doc = PdfPages(fname)
for fig in figures:
fig.savefig(doc, format='pdf')
doc.close()
def main():
a = fig_barh(['a','b','c'], [1, 2, 3], 'Test #1')
b = fig_barh(['x','y','z'], [5, 3, 1], 'Test #2')
write_pdf('test.pdf', [a, b])
if __name__=="__main__":
main()
If you don't want the picture to be displayed and only get a variable in return, then you can try the following (with some additional stuff to remove axis):
def myplot(t,x):
fig = Figure(figsize=(2,1), dpi=80)
canvas = FigureCanvasAgg(fig)
ax = fig.add_subplot()
ax.fill_between(t,x)
ax.autoscale(tight=True)
ax.axis('off')
canvas.draw()
buf = canvas.buffer_rgba()
X = np.asarray(buf)
return X
The returned variable X can be used with OpenCV for example and do a
cv2.imshow('',X)
These import must be included:
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg
The currently accepted answer didn't work for me as such, as I was using scipy.stats.probplot() to plot. I used matplotlib.pyplot.gca() to access an Axes instance directly instead:
"""
For my plotting ideas, see:
https://pythonfordatascience.org/independent-t-test-python/
For the dataset, see:
https://github.com/Opensourcefordatascience/Data-sets
"""
# Import modules.
from scipy import stats
import matplotlib.pyplot as plt
import pandas as pd
from tempfile import gettempdir
from os import path
from slugify import slugify
# Define plot func.
def get_plots(df):
# plt.figure(): Create a new P-P plot. If we're inside a loop, and want
# a new plot for every iteration, this is important!
plt.figure()
stats.probplot(diff, plot=plt)
plt.title('Sepal Width P-P Plot')
pp_p = plt.gca() # Assign an Axes instance of the plot.
# Plot histogram. This uses pandas.DataFrame.plot(), which returns
# an instance of the Axes directly.
hist_p = df.plot(kind = 'hist', title = 'Sepal Width Histogram Plot',
figure=plt.figure()) # Create a new plot again.
return pp_p, hist_p
# Import raw data.
df = pd.read_csv('https://raw.githubusercontent.com/'
'Opensourcefordatascience/Data-sets/master//Iris_Data.csv')
# Subset the dataset.
setosa = df[(df['species'] == 'Iris-setosa')]
setosa.reset_index(inplace= True)
versicolor = df[(df['species'] == 'Iris-versicolor')]
versicolor.reset_index(inplace= True)
# Calculate a variable for analysis.
diff = setosa['sepal_width'] - versicolor['sepal_width']
# Create plots, save each of them to a temp file, and show them afterwards.
# As they're just Axes instances, we need to call get_figure() at first.
for plot in get_plots(diff):
outfn = path.join(gettempdir(), slugify(plot.title.get_text()) + '.png')
print('Saving a plot to "' + outfn + '".')
plot.get_figure().savefig(outfn)
plot.get_figure().show()

Get the list of figures in matplotlib

I would like to:
pylab.figure()
pylab.plot(x)
pylab.figure()
pylab.plot(y)
# ...
for i, figure in enumerate(pylab.MagicFunctionReturnsListOfAllFigures()):
figure.savefig('figure%d.png' % i)
What is the magic function that returns a list of current figures in pylab?
Websearch didn't help...
Pyplot has get_fignums method that returns a list of figure numbers. This should do what you want:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(100)
y = -x
plt.figure()
plt.plot(x)
plt.figure()
plt.plot(y)
for i in plt.get_fignums():
plt.figure(i)
plt.savefig('figure%d.png' % i)
The following one-liner retrieves the list of existing figures:
import matplotlib.pyplot as plt
figs = list(map(plt.figure, plt.get_fignums()))
Edit: As Matti Pastell's solution shows, there is a much better way: use plt.get_fignums().
import numpy as np
import pylab
import matplotlib._pylab_helpers
x=np.random.random((10,10))
y=np.random.random((10,10))
pylab.figure()
pylab.plot(x)
pylab.figure()
pylab.plot(y)
figures=[manager.canvas.figure
for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()]
print(figures)
# [<matplotlib.figure.Figure object at 0xb788ac6c>, <matplotlib.figure.Figure object at 0xa143d0c>]
for i, figure in enumerate(figures):
figure.savefig('figure%d.png' % i)
This should help you (from the pylab.figure doc):
call signature::
figure(num=None, figsize=(8, 6),
dpi=80, facecolor='w', edgecolor='k')
Create a new figure and return a
:class:matplotlib.figure.Figure
instance. If num = None, the
figure number will be incremented and
a new figure will be created.** The
returned figure objects have a
number attribute holding this number.
If you want to recall your figures in a loop then a good aproach would be to store your figure instances in a list and to call them in the loop.
>> f = pylab.figure()
>> mylist.append(f)
etc...
>> for fig in mylist:
>> fig.savefig()
Assuming you haven't manually specified num in any of your figure constructors (so all of your figure numbers are consecutive) and all of the figures that you would like to save actually have things plotted on them...
import matplotlib.pyplot as plt
plot_some_stuff()
# find all figures
figures = []
for i in range(maximum_number_of_possible_figures):
fig = plt.figure(i)
if fig.axes:
figures.append(fig)
else:
break
Has the side effect of creating a new blank figure, but better if you don't want to rely on an unsupported interface
I tend to name my figures using strings rather than using the default (and non-descriptive) integer. Here is a way to retrieve that name and save your figures with a descriptive filename:
import matplotlib.pyplot as plt
figures = []
figures.append(plt.figure(num='map'))
# Make a bunch of figures ...
assert figures[0].get_label() == 'map'
for figure in figures:
figure.savefig('{0}.png'.format(figure.get_label()))

Categories

Resources