Matplotpib figure in a loop not responding - python

Python 2.7.11, Win 7, x64, Numpy 1.10.4, matplotlib 1.5.1
I ran the following script from an iPython console after entering %matplotlib qt at the command line
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
number = input("Number: ")
coords = np.array(np.random.randint(0, number, (number, 3)))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(coords[:,0], coords[:,1], coords[:,2])
plt.show()
It plots a random scatter in 3D. So I thought it would be a trivial matter to just pop it into a while loop & get a new figure on each iteration.
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
s = True
while s:
number = input("Number: ")
coords = np.array(np.random.randint(0, number, (number, 3)))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(coords[:,0], coords[:,1], coords[:,2])
plt.show()
cont = input("Continue? (y/n)")
if cont == 'n':
s = False
...but the figures are just blank & unresponsive until I enter an input for cont then I get,
NameError: name 'y' is not defined
...and the whole thing crashes.
So what am I missing here?
EDIT: Taking into account Aquatically challenged's answer below. The figures still hang until the loop is exited, then they are all plotted at the same time. Anybody know why the plots are not done within the loop?

input tries to eval the string you type in, treating it as though it is Python code, then returns the result of the evaluation. For example, if result = input() and I type in 2 + abs(-3) then result will be equal to 5.
When you enter the string y this is treated as a variable name. Since you haven't defined any variable named y you will get a NameError. Instead of input you want to use raw_input, which just returns the input string without trying to evaluate it.
In order to get your figures to display within the while loop you need to insert a short pause to allow the contents of the figure to be drawn before you continue executing your while loop. You could use plt.pause, which also takes care of updating the active figure.
s = True
while s:
number = input("Number: ")
coords = np.array(np.random.randint(0, number, (number, 3)))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(coords[:,0], coords[:,1], coords[:,2])
plt.pause(0.1)
cont = raw_input("Continue? (y/n)")
if cont == 'n':
s = False

I haven't replicated but when you input the 'y' or 'n'. try to put the single (or double quotes) are the y or n
to input strings without quotes. Use raw_input instead of input
as described here Python 2.7 getting user input and manipulating as string without quotations

Related

How to save multiple figure objects without knowing their variable names beforehand [duplicate]

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()))

How can i have my code print more than one graph at a time?

I am quite new to python so please bear with me.
My code is below:
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
df = pd.read_csv(r"/Users/aaronhuang/Desktop/ffp/exfileCLEAN2.csv", skiprows=[1])
magnitudes = df['Magnitude '].values
times = df['Time '].values
zscores = np.abs(stats.zscore(magnitudes, ddof=1))
outlier_indicies = np.argwhere(zscores > 3).flatten()
print(times[outlier_indicies])
window = 10
num = 1
x = times[outlier_indicies[num]-window:outlier_indicies[num]+window+1]
y = magnitudes[outlier_indicies[num]-window:outlier_indicies[num]+window+1]
plt.plot(x, y)
plt.xlabel('Time (units)')
plt.ylabel('Magnitude (units)')
plt.show()
fig = plt.figure()
fig.savefig("/Users/aaronhuang/Downloads")
Is there a way I can print all the graphs separately once?. Deleting num has not worked.
Thank you in advance.
You can put the plots inside a for loop, and repeat as many times as you like, with different variables for each step if needed. Most software will show the plots either in multiple plot windows, or output them in a long strip you can scroll through. If you use Spyder however, they will play back to back, with each plot being a frame.
Also, if you want to print multiple plots, you have to put the plt.show() inside the loop as well, putting it after the loop will show all the values on a single plot.
For example:
import matplotlib.pyplot as plt
x_values = [1,2,3,4,5,6,7]
for x in x_values:
y = x**2
plt.plot(x,y,"o")
plt.axis([0,50, 0,50])
plt.show()

multiple interactive matplotlib behave differently in python 2.7 vs 3.6

I have a python script that loops continuously with user input directing it to get data from a file then plots it using matplotlib. My hope is to have the plots show up and stick around (and continue to be interactive) while the script continues on in the console asking for the next round of user input and plotting. So the user might end up with a few plot windows open in the end that are all functional.
I actually have it working in my python 2.7 anaconda build with the following example code that just plots a random dataset each loop.
import sys
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
print('matplotlib version: '+matplotlib.__version__)
version = sys.version_info[0]
def plot_data(data):
fig = plt.figure(figsize=(6,6))
plt.plot(data)
plt.ion()
plt.show()
plt.pause(0.001)
while True:
if version < 3:
option = raw_input('type (1) to plot next data, (q) to quit\n')
else:
option = input('type (1) to plot next data, (q) to quit\n')
if option == '1':
data = np.random.choice(1000,100, replace = False)
plot_data(data)
elif option == 'q':
break
Running the code with my python 3.6 build, the plot shows up but is frozen in a non-responding state until I go back to the console and type in q to quit my user input loop. In python 2.7 the plot windows are fully functional through multiple input loops and plot calls. So I'm hoping someone knows what difference here. I'm printing the matplotlib version and it seems like both my 2.7 and 3.6 environments are using the same matplotlib 2.0.2 so maybe it's in the GUI handler?
I'm not sure if the setup from the question using a while loop and plt.ion() is actually supposed to work. At least for me using python 2.7 and matplotlib 2.1 it doesn't.
I would have though that this is to be expected, because the application freezes and becomes unresponsive as long as it waits for user input.
In any case, since it is always a bit delicate to mix the console and a GUI application, I would choose to work completely inside the event loop of the GUI.
You may connect "key_press_event"s to the "1" and "q" key and show new data inside the open matplotlib window.
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(6,6))
ax = plt.subplot(111)
def plot_data(ax, data):
ax.clear()
ax.plot(data)
ax.figure.canvas.draw_idle()
def press(event=None):
if event:
if event.key == "1":
data = np.random.choice(1000,100, replace = False)
plot_data(ax, data)
elif event.key == "q":
plt.close()
cid= fig.canvas.mpl_connect("key_press_event", press)
plt.show()
In case you want to create several figures, this would look like
import matplotlib.pyplot as plt
import numpy as np
def create_figure(data):
fig, ax = plt.subplots(figsize=(6,6))
ax.plot(data)
cid = fig.canvas.mpl_connect("key_press_event", press)
fig.show()
def plot_data():
data = np.random.choice(1000,100, replace = False)
create_figure(data)
def press(event=None):
if event:
if event.key == "1":
plot_data()
elif event.key == "q":
plt.close("all")
else:
plot_data()
press()
plt.show()
For more complicated input, you may create a small GUI, which collects the input and calls the function for plotting. As an example, one may use Tkinter for that purpose.
from Tkinter import * # use from tkinter import * if using python3
import matplotlib.pyplot as plt
import numpy as np
def create_figure(data):
fig, ax = plt.subplots(figsize=(6,6))
ax.plot(data)
fig.show()
def plot_data(n, amp):
try:
n = int(n)
amp = float(amp)
data = amp*np.random.rand(n)
create_figure(data)
except:
pass
def closeall():
for i in plt.get_fignums():
plt.close(i)
def create_input():
root = Tk()
Label(text="Number of datapoints").grid(row=1,column=0, sticky=W)
Label(text="Amplitude").grid(row=2,column=0, sticky=W)
tb1=Entry(root,textvariable=StringVar(root, value='24'))
tb1.grid(row=1,column=1, sticky=W+E)
tb2=Entry(root,textvariable=StringVar(root, value='6'))
tb2.grid(row=2,column=1, sticky=W+E)
b1=Button(root,text=" Plot ",command= lambda : plot_data(tb1.get(),tb2.get()))
b1.grid(row=4,column=1, sticky=W+E)
b2=Button(root,text="Close All",command=closeall)
b2.grid(row=5,column=1, sticky=W+E)
root.mainloop()
create_input()

Can I generate and show a different image during each loop with Matplotlib?

I am new to Matplotlib and Python. I mostly use Matlab. Currently, I am working with a Python code where I want to run a loop. In each loop, I will do some data processing and then show an image based on the processed data. When I go to the next loop, I want the previously stored image to be closed and generate a new image based on the latest data.
In other words, I want a python code equivalent to the following Matlab code:
x = [1 2 3];
for loop = 1:3
close all;
y = loop * x;
figure(1);
plot(x,y)
pause(2)
end
I tried the following python code to achieve my goal:
import numpy as np
import matplotlib
import matplotlib.lib as plt
from array import array
from time import sleep
if __name__ == '__main__':
x = [1, 2, 3]
for loop in range(0,3):
y = numpy.dot(x,loop)
plt.plot(x,y)
plt.waitforbuttonpress
plt.show()
This code puts all plots superimposed in the same figure. If I put the plt.show() command inside the for loop, only the first image is shown. Therefore, I could not replicate my Matlab code in Python.
try this:
import numpy
from matplotlib import pyplot as plt
if __name__ == '__main__':
x = [1, 2, 3]
plt.ion() # turn on interactive mode
for loop in range(0,3):
y = numpy.dot(x, loop)
plt.figure()
plt.plot(x,y)
plt.show()
_ = input("Press [enter] to continue.")
if you want to close the previous plot, before showing the next one:
import numpy
from matplotlib import pyplot as plt
if __name__ == '__main__':
x = [1, 2, 3]
plt.ion() # turn on interactive mode, non-blocking `show`
for loop in range(0,3):
y = numpy.dot(x, loop)
plt.figure() # create a new figure
plt.plot(x,y) # plot the figure
plt.show() # show the figure, non-blocking
_ = input("Press [enter] to continue.") # wait for input from the user
plt.close() # close the figure to show the next one.
plt.ion() turns on interactive mode making plt.show non-blocking.
and heres is a duplicate of your matlab code:
import numpy
import time
from matplotlib import pyplot as plt
if __name__ == '__main__':
x = [1, 2, 3]
plt.ion()
for loop in xrange(1, 4):
y = numpy.dot(loop, x)
plt.close()
plt.figure()
plt.plot(x,y)
plt.draw()
time.sleep(2)

matplotlib weirdness, it's not drawing my graph

What happened is I followed this demo, I modified it to suit my needs had it working, changed it to use a function to draw two graphs but now it doesn't work at all using plt.show() or plt.savefig()
here's my code
import csv
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
# I converted excel to a csv file
data = [x for x in csv.reader(open('ASS1_Q1.csv'))]
question1 = {}
question1['males'] = []
question1['females'] = []
for x in data:
if x[0].lower() == "male":
question1["males"].append(float(x[1]))
elif x[0].lower() == "female":
question1['females'].append(float(x[1]))
else:
print "Not a valid dataline", x
def plot_graph(data, filename):
fig = plt.figure()
ax = fig.add_subplot(111)
n, bins, patches = ax.hist(np.array(data), bins=13, align='mid', facecolor='#888888')
ax.set_xlabel('Speed in kph')
ax.set_ylabel('Amount of Females')
ax.set_xlim(min(data, max(data)))
# plt.savefig(filename)
plt.show()
plot_graph(question1['males'], "ASS1Q1-males.eps")
#plot_graph(question1['females'], "ASSQ2-females.eps")
print summary(question1['males'])
print summary(question1['females'])
Can someone explain why this is happening? what am I doing wrong?
Try removing
import matplotlib
matplotlib.use('Agg')
The command
python -c 'import matplotlib; matplotlib.use("")'
will show you the valid string arguments that can be sent to matplotlib.use.
On my machine, 'Agg' is listed as valid, though I get no output when this is set. If you are curious, you could just keep trying various options until you find one that works.
When you find the one that your prefer, you may also find it more convenient to set something like
backend : GtkAgg
in your ~/.matplotlib/matplotlibrc instead of using matplotlib.use(...).

Categories