How to save figure in Matplotlib in Python - python

I am trying to save my figure in Matplotlib to a file but when I run the command to save the image, it doesn't give any errors but I can't see the file.
plt.savefig('Traveling Salesmen Graph.png')

pyplot keeps track of the "current figure", and functions called on the library which require a figure operate on that, but you can also be more explicit by calling savefig() on the figure object.
as an example from https://pythonspot.com/matplotlib-save-figure-to-image-file/:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
y = [2,4,6,8,10,12,14,16,18,20]
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
ax.plot(x, y, label='$y = numbers')
plt.title('Legend inside')
ax.legend()
#plt.show()
fig.savefig('plot.png')
Being explicit in this way should solve your issue.
For references to pyplot functions which operate on the "current figure" see: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.html

Related

How to reuse and plot more than once the same plot

Using matplotlib, on Jupyter books, I want to make a figure with some plots, show it, add more plots, and show it again (old and new plots)
instead, it shows me only new plots on the new second image
This is the code I have:
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
a=np.random.rand(10,)
b=np.random.rand(10,)
fig1 = plt.figure(1)
plt.plot(a,'b')
#plt.draw();
plt.show();
plt.figure(1)
plt.plot(b,'g--')
plt.show();
left is what I have, right is what I want :
enter image description here
The question upside has been reduced to the most simplistic form, therefore I may have not explain that I do not want to having to recreate the figure each time (as it has about 15 lines to configure as I desire)
This is an example of code I DO NOT want:
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
a=np.random.rand(10,)
b=np.random.rand(10,)
c=np.random.rand(10,)
plt.plot(a, 'b')
plt.grid(True)
dig, ax = plt.subplots(1)
ax.plot(a,'b')
ax.plot(b,'g--')
dig, bx = plt.subplots(1)
bx.plot(a,'b')
bx.plot(b,'g--')
bx.plot(c,'r.')
plt.show()
this is a sort of pseudocode I would expect:
a=np.random.rand(10,)
b=np.random.rand(10,)
c=np.random.rand(10,)
my_plot = plt.figure()
my_plot.grid(True)
my_plot.addplot(a,'b')
my_plot.show()
my_plot.addplot(a,'g--')
my_plot.show()
my_plot.addplot(a,'r.')
my_plot.show()
(I know, this is not phyton/matplotlib, but I am sure something elegant like this should be possible)
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
a=np.random.rand(10,)
b=np.random.rand(10,)
c=np.random.rand(10,)
d=np.random.rand(10,)
p = [a,b,c,d]
colors = ['r','g','b', 'g--']
for i in range(len(p)):
fig, ax = plt.subplots(1)
for j in range(i + 1):
ax.plot(p[j], colors[j])

figsize in matplotlib is not changing the figure size? [duplicate]

This question already has answers here:
How do I change the size of figures drawn with Matplotlib?
(14 answers)
Closed 4 years ago.
As you can see the code produces a barplot that is not as clear and I want to make the figure larger so the values can be seen better. This doesn't do it. What is the correct way?
x is a dataframe and x['user'] is the x axis in the plot and x['number'] is the y.
import matplotlib.pyplot as plt
%matplotlib inline
plt.bar(x['user'], x['number'], color="blue")
plt.figure(figsize=(20,10))
The line with the plt.figure doesn't change the initial dimensions.
One option (as mentioned by #tda), and probably the best/most standard way, is to put the plt.figure before the plt.bar:
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plt.bar(x['user'], x['number'], color="blue")
Another option, if you want to set the figure size after creating the figure, is to use fig.set_size_inches (note I used plt.gcf here to get the current figure):
import matplotlib.pyplot as plt
plt.bar(x['user'], x['number'], color="blue")
plt.gcf().set_size_inches(20, 10)
It is possible to do this all in one line, although its not the cleanest code. First you need to create the figure, then get the current axis (fig.gca), and plot the barplot on there:
import matplotlib.pyplot as plt
plt.figure(figsize=(20, 10)).gca().bar(x['user'], x['number'], color="blue")
Finally, I will note that it is often better to use the matplotlib object-oriented approach, where you save a reference to the current Figure and Axes and call all plotting functions on them directly. It may add more lines of code, but it is usually clearer code (and you can avoid using things like gcf() and gca()). For example:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111)
ax.bar(x['user'], x['number'], color="blue")
Try setting up the size of the figure before assigning what to plot, as below:
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(20,10))
plt.bar(x['user'], x['number'], color="blue")

What is the currently correct way to dynamically update plots in Jupyter/iPython?

In the answers to how to dynamically update a plot in a loop in ipython notebook (within one cell), an example is given of how to dynamically update a plot inside a Jupyter notebook within a Python loop. However, this works by destroying and re-creating the plot on every iteration, and a comment in one of the threads notes that this situation can be improved by using the new-ish %matplotlib nbagg magic, which provides an interactive figure embedded in the notebook, rather than a static image.
However, this wonderful new nbagg feature seems to be completely undocumented as far as I can tell, and I'm unable to find an example of how to use it to dynamically update a plot. Thus my question is, how does one efficiently update an existing plot in a Jupyter/Python notebook, using the nbagg backend? Since dynamically updating plots in matplotlib is a tricky issue in general, a simple working example would be an enormous help. A pointer to any documentation on the topic would also be extremely helpful.
To be clear what I'm asking for: what I want to do is to run some simulation code for a few iterations, then draw a plot of its current state, then run it for a few more iterations, then update the plot to reflect the current state, and so on. So the idea is to draw a plot and then, without any interaction from the user, update the data in the plot without destroying and re-creating the whole thing.
Here is some slightly modified code from the answer to the linked question above, which achieves this by re-drawing the whole figure every time. I want to achieve the same result, but more efficiently using nbagg.
%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
pl.clf()
pl.plot(pl.randn(100))
display.display(pl.gcf())
display.clear_output(wait=True)
time.sleep(1.0)
Here is an example that updates a plot in a loop. It updates the data in the figure and does not redraw the whole figure every time. It does block execution, though if you're interested in running a finite set of simulations and saving the results somewhere, it may not be a problem for you.
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import time
def pltsin(ax, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
fig.canvas.draw()
fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, ['b', 'r'])
time.sleep(1)
I put this up on nbviewer here.
There is an IPython Widget version of nbagg that is currently a work in progress at the Matplotlib repository. When that is available, that will probably be the best way to use nbagg.
EDIT: updated to show multiple plots
I'm using jupyter-lab and this works for me (adapt it to your case):
from IPython.display import clear_output
from matplotlib import pyplot as plt
import numpy as np
import collections
%matplotlib inline
def live_plot(data_dict, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
for label,data in data_dict.items():
plt.plot(data, label=label)
plt.title(title)
plt.grid(True)
plt.xlabel('epoch')
plt.legend(loc='center left') # the plot evolves to the right
plt.show();
Then in a loop you populate a dictionary and you pass it to live_plot():
data = collections.defaultdict(list)
for i in range(100):
data['foo'].append(np.random.random())
data['bar'].append(np.random.random())
data['baz'].append(np.random.random())
live_plot(data)
make sure you have a few cells below the plot, otherwise the view snaps in place each time the plot is redrawn.
If you don't want to clear all outputs, you can use display_id=True to obtain a handle and use .update() on it:
import numpy as np
import matplotlib.pyplot as plt
import time
from IPython import display
def pltsin(ax, *,hdisplay, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
hdisplay.update(fig)
fig,ax = plt.subplots(1,1)
hdisplay = display.display("", display_id=True)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, colors=['b', 'r'], hdisplay=hdisplay)
time.sleep(1)
plt.close(fig)
(adapted from #pneumatics)
I've adapted #Ziofil answer and modified it to accept x,y as list and output a scatter plot plus a linear trend on the same plot.
from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
def live_plot(x, y, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
plt.xlim(0, training_steps)
plt.ylim(0, 100)
x= [float(i) for i in x]
y= [float(i) for i in y]
if len(x) > 1:
plt.scatter(x,y, label='axis y', color='k')
m, b = np.polyfit(x, y, 1)
plt.plot(x, [x * m for x in x] + b)
plt.title(title)
plt.grid(True)
plt.xlabel('axis x')
plt.ylabel('axis y')
plt.show();
you just need to call live_plot(x, y) inside a loop.
here's how it looks:
The canvas.draw method of the figure dynamically updates its graphs, for the current figure:
from matplotlib import pyplot as plt
plt.gcf().canvas.draw()

Redrawing a plot in IPython / matplotlib

I use IPython/Matplotlib, and I want to create functions that can plot various graphs in the same plotting window. However, I have trouble with redrawing. This is my program test_plot_simple.py:
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y2 = (x**2)/(10**2)
ye = (2**x)/(2**10)
fig, ax = plt.subplots()
def p_squared():
ax.plot(x,y2, 'r')
plt.show()
def p_exp():
ax.plot(x,ye, 'r')
plt.show()
I start IPython as $ python --matplotlib
On the IPython command line I do
In [1]: run test_plot_simple.py
In [2]: p_squared()
In [3]: p_exp()
After the second line, the squared graph is shown. But nothing happens after the second. Why is the plt.show() not working here?
It appears as though you call subplots without actually taking advantage of them, namely that you are trying to over plot on the same canvas. See here for a more thorough explanation. That being said, all you need is the following in order to have the functionality I think you want:
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y2 = (x**2)/(10**2)
ye = (2**x)/(2**10)
def p_squared():
plt.plot(x,y2, 'r')
plt.show()
def p_exp():
plt.plot(x,ye, 'r')
plt.show()
Now both the p_squared() and p_exp() calls produce plots. Hope this helps.
After some digging I think I found the right way to go about this. It seems that show() is not really intended for this purpose, but rather draw() is. And if I want to keep it object-oriented, I should draw via my figure or my axis. It seems to me that something like this is the best approach:
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y2 = (x**2)/(10**2)
ye = (2**x)/(2**10)
fig, ax = plt.subplots()
fig.show()
def p_squared():
ax.plot(x,y2, 'r')
fig.canvas.draw()
def p_exp():
ax.plot(x,ye, 'r')
fig.canvas.draw()
I.e., use fig.canvas.draw() in lieu of plt.show() (or fig.show(), for that matter.)
I still need one show() - I chose to do that right away after the figure has been created.

Matplotlib 3D plot doesn't plot correctly

I'm having a problem trying to plot a series of lines in a 3D plot in MatPlotLib.
When I run the code below all the lines are plotted at the last value of y??? Even though y is correctly incremented in the loop.
Any Help understanding this would be appreciated.
Thanks
David
#========== Code Start=================
import numpy as np
import matplotlib
from matplotlib.figure import Figure
import pylab as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)
x=np.arange(5)
y=np.zeros(len(x))
for i in range(1,10):
y.fill(i)
z=plt.randn(len(y))
ax.plot(xs=x, ys=y, zs=z)#, zdir='z', label='ys=0, zdir=z')
plt.draw()
print i,len(y),y,x,z
plt.xlabel('X')
plt.ylabel('Y')
plt.zlabel('Z')
plt.show()
#========== Code End=================
It looks like y might be pointed to by all plots. So you are passing the reference to y when you execute ax.plot. It is the same reference each time, but the values are changed on each pass. When the plt.show() is executed the reference to y is used and it is now set at 9. So, create a different object for y on each pass with the values you want for that pass:
y = np.zeros(len(x))
y.file(i)
There might be a numpy command that fills with the value you want in one go, but you get the picture.

Categories