Uniquely naming png files in def loop - python

So now I can get unique files, hurrah! but it seems the second file is plotting both the first and the second plot, the third is plotting all three, fourth is plotting all four, etc. here is the new code:
for j in range(2):
dhulist=pyfits.open('test.fits')
row=5
colum=j
ax=[]
val=[]
for i in range(1600,3040):
val.append((dhulist[0].data[i,row,colum]))
ax.append(((((dhulist[0].header['CRPIX3'] -i)*(dhulist[0].header['CDELT3']))+5000)/1000))
plt.plot(ax,val)
#plt.show()
plt.savefig("5_{0}.png".format(j))

the plot function of matplotlib updates the current figure, or creates a new figure if there is no current figure. Here is an example that does a good job of explicitly tracking the figure object from creation to closing.
import numpy as np
from matplotlib import pyplot as plt
x = np.linspace(0, 10)
for j in range(3):
y = x ** j
f = plt.figure()
plt.plot(x, y, figure=f)
f.savefig("test_{}.png".format(j))
plt.close(f)
Notice that every operation that involves a figure, opening, plotting, saving, and closing explicitly references the figure object. IMHO, that's a very nice coding style and very helpful if you ever need to work with multiple figures at once. Matplotlib also lets you work with the "current figure" implicitly, which is fine if you're doing something simple. That would look more like this:
import numpy as np
from matplotlib import pyplot as plt
x = np.linspace(0, 10)
for j in range(3):
y = x ** j
plt.figure()
plt.plot(x, y)
plt.savefig("test2_{}.png".format(j))
plt.close()

Related

Updating plot in real time

I am giving data to a matrix (e.g. with shape 100x100) by the following code:
from random import randint
import matplotlib.pyplot as plt
import numpy as np
import random as rand
tab = np.eye(100, 100)
x = np.arange(0, 100, 1)
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(100):
for j in range(100):
tab[i, j] = rand.randint(0, 254)
line1, = ax.plot(x, tab[i, :], 'r-')
line1.set_ydata(tab[i, j])
fig.canvas.draw()
fig.canvas.flush_events()
ax.lines.remove(line1)
I need to update matrix using loops and upgrade plot in the same time.
When loop with j ends, i-loop want to clear plot and start plotting again. Is it possible?
My result:
What I need:
After reading your comment i think i understood what you where trying to do
the reason you got those horizontal lines was that you're setting ydata again after plotting(to a constant so its like plotting a horizontal line)
consider the code below:
from random import randint
import matplotlib.pyplot as plt
import numpy as np
import random as rand
tab = np.eye(100, 100)
x = np.arange(0, 100, 1)
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(100):
for j in range(100):
tab[i, j] = ((50-i/2)*(50-i/2)-(50-j)*(50-j))/100
for i in range(100):
line1, = ax.plot(x, tab[i, :], 'r-')
fig.canvas.draw()
fig.canvas.flush_events()
ax.lines.remove(line1)
I used another for to instantiate the tab map (since you're using sensor data I guess that is exactly what you're doing in your code because you need to read all of the data (at least the ones for the current cross section) to be able to plot the type of graph you want. this is equivalent to reading all of the data at the beginning and then starting to plot it)
(I also used simulated values instead of random values for the sake of testing)
if you want to draw the data AS THEY COME FROM THE SENSOR then you must define a function to get the data of the current cross section from the sensor and return an array. Idk the library you're using for the sensor but I'm assuming the scan functions are synchronous so the function will return exactly after the input is over making the whole thing pseudo-real time
from random import randint
import matplotlib.pyplot as plt
import numpy as np
import random as rand
x = np.arange(0, 100, 1)
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(100):
data = READ_CURRENT_CROSS_SECTION()
line1, = ax.plot(x, data, 'r-')
fig.canvas.draw()
fig.canvas.flush_events()
ax.lines.remove(line1)
again, if plotting the data as the come from the sensor is your goal here it is going to depend a lot on the library you're using but except for all of that the problem with your code was that it was trying to plot while it was getting the data point by point which gives you insufficient data for plotting a cross section(hence the straight lines) (PS: there actually are some ways to pull it off like this but will be extremely slow!)
So either
write a function to scan the whole 2d area and return the whole map before you start plotting(which will be like my first code and the function i just said will replace lines 11-13). this takes away the real time feature but it will give you a beautiful animated plot in a short time
write a function to scan each cross section and return it as a 100 element array. which makes it kind of real time but i guess is harder to implement. This is like my second code but you have to define READ_CURRENT_CROSS_SECTION yourself

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

Matplotlib multiple lines on graph

I've been having an issue with saving matplotlib graphs as images.
The images are saving differently from what shows up when I call the .show() method on the graph.
An example is here:
http://s1.postimg.org/lbyei5cfz/blue5.png
I'm not sure what else to do. I've spent the past hours trying to figure out what's causing it, but I can't figure it out.
Here is my code in it's entirety.
import matplotlib.pyplot as plt
import random
turn = 1 #for the x values
class Graph():
def __init__(self, name, color):
self.currentValue = 5 #for the y values
self.x = [turn]
self.y = [self.currentValue]
self.name = name
self.color = color
def update(self):
if random.randint(0,1): #just to show if the graph's value goes up or down
self.currentValue += random.randint(0,10)
self.y.append(self.currentValue)
else:
self.currentValue -= random.randint(0,10)
self.y.append(self.currentValue)
self.x.append(turn)
def plot(self):
lines = plt.plot(self.x,self.y)
plt.setp(lines, 'color',self.color)
plt.savefig(self.name + str(turn))
#plt.show() will have a different result from plt.savefig(args)
graphs = [Graph("red",'r'),Graph("blue",'b'),Graph("green",'g')]
for i in range(5):
for i in graphs:
i.update() #changes the x and y value
i.plot() #saves the picture of the graph
turn += 1
Sorry if this is a stupid mistake I'm making, I just find it peculiar how plt.show() and plt.savefig are different.
Thanks for the help.
As stated correctly by David, plt.show() resets current figure. plt.savefig(), however, does not, so you need to reset it explicitly. plt.clf() or plt.figure() are two functions that can do it dor you. Just insert the call right after plt.savefig:
plt.savefig(self.name + str(turn))
plt.clf()
If you want to save the figure after displaying it, you'll need to hold on to the figure instance. The reason that plt.savefig doesn't work after calling show is that the current figure has been reset.
pyplot keeps track of which figures, axes, etc are "current" (i.e. have not yet been displayed with show) behind-the-scenes. gcf and gca get the current figure and current axes instances, respectively. plt.savefig (and essentially any other pyplot method) just does plt.gcf().savefig(...). In other words, get the current figure instance and call its savefig method. Similarly plt.plot basically does plt.gca().plot(...).
After show is called, the list of "current" figures and axes is empty.
In general, you're better off directly using the figure and axes instances to plot/save/show/etc, rather than using plt.plot, etc, to implicitly get the current figure/axes and plot on it. There's nothing wrong with using pyplot for everything (especially interactively), but it makes it easier to shoot yourself in the foot.
Use pyplot for plt.show() and to generate a figure and an axes object(s), but then use the figure or axes methods directly. (e.g. ax.plot(x, y) instead of plt.plot(x, y), etc) The main advantage of this is that it's explicit. You know what objects you're plotting on, and don't have to reason about what the pyplot state-machine does (though it's not that hard to understand the state-machine interface, either).
As an example of the "recommended" way of doing things, do something like:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 100)
y = x**2
fig, ax = plt.subplots()
ax.plot(x, y)
fig.savefig('fig1.pdf')
plt.show()
fig.savefig('fig2.pdf')
If you'd rather use the pyplot interface for everything, then just grab the figure instance before you call show. For example:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 100)
y = x**2
plt.plot(x, y)
fig = plt.gcf()
fig.savefig('fig1.pdf')
plt.show()
fig.savefig('fig2.pdf')
source

Matplotlib pyplot in real time

I have a while function that generates two lists of numbers and at the end I plot them using matplotlib.pyplot.
I'm doing
while True:
#....
plt.plot(list1)
plt.plot(list2)
plt.show()
But in order to see the progression I have to close the plot window.
Is there a way to refresh it with the new data every x seconds?
The most robust way to do what you want is to use matplotlib.animation. Here's an example of animating two lines, one representing sine and one representing cosine.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
sin_l, = ax.plot(np.sin(0))
cos_l, = ax.plot(np.cos(0))
ax.set_ylim(-1, 1)
ax.set_xlim(0, 5)
dx = 0.1
def update(i):
# i is a counter for each frame.
# We'll increment x by dx each frame.
x = np.arange(0, i) * dx
sin_l.set_data(x, np.sin(x))
cos_l.set_data(x, np.cos(x))
return sin_l, cos_l
ani = animation.FuncAnimation(fig, update, frames=51, interval=50)
plt.show()
For your particular example, you would get rid of the while True and put the logic inside that while loop in the update function. Then, you just have to make sure to do set_data instead of making a whole new plt.plot call.
More details can be found in this nice blog post, the animation API, or the animation examples.
I think what you're looking for is the "animation" feature.
Here is an example
This example is a second one.

matplotlib plotting multiple lines in 3D

I am trying to plot multiple lines in a 3D plot using matplotlib. I have 6 datasets with x and y values. What I've tried so far was, to give each point in the data sets a z-value. So all points in data set 1 have z=1 all points of data set 2 have z=2 and so on.
Then I exported them into three files. "X.txt" containing all x-values, "Y.txt" containing all y-values, same for "Z.txt".
Here's the code so far:
#!/usr/bin/python
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
import pylab
xdata = '/X.txt'
ydata = '/Y.txt'
zdata = '/Z.txt'
X = np.loadtxt(xdata)
Y = np.loadtxt(ydata)
Z = np.loadtxt(zdata)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X,Y,Z)
plt.show()
What I get looks pretty close to what I need. But when using wireframe, the first point and the last point of each dataset are connected. How can I change the colour of the line for each data set and how can I remove the connecting lines between the datasets?
Is there a better plotting style then wireframe?
Load the data sets individually, and then plot each one individually.
I don't know what formats you have, but you want something like this
from mpl_toolkits.mplot3d.axes3d import Axes3D
import matplotlib.pyplot as plt
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
datasets = [{"x":[1,2,3], "y":[1,4,9], "z":[0,0,0], "colour": "red"} for _ in range(6)]
for dataset in datasets:
ax.plot(dataset["x"], dataset["y"], dataset["z"], color=dataset["colour"])
plt.show()
Each time you call plot (or plot_wireframe but i don't know what you need that) on an axes object, it will add the data as a new series. If you leave out the color argument matplotlib will choose them for you, but it's not too smart and after you add too many series' it will loop around and start using the same colours again.
n.b. i haven't tested this - can't remember if color is the correct argument. Pretty sure it is though.

Categories