Related
I am working on some project where I want to compare two different solution of some equation I am solving.
I have some data that are time and Space (x,y) dependent. which means I have for every time step T a data file T.dat which contains the x y and Z values of my equation I am solving.
When I plot the solutions of the equation individually everything works fine.
as soon as i try to make a loop to iterate over some time steps I get the problem that my Color bar doesn't get remove in the second iteration. for the first Plot it works fine but after the second one Colorbars keeps adding up in the plot.
thats how it looks like.
After four Itteration
Here is a Sample of my Code.
First I imported my Libraries.
import numpy as np
import glob
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib import animation
import scipy as sp
from IPython.display import set_matplotlib_formats
set_matplotlib_formats('jpg')
from mpl_toolkits.mplot3d import Axes3D
#%matplotlib qt
import animatplot as amp
from sklearn.preprocessing import StandardScaler
Secondly I start Importing my Datas in Dataframes (Some specifics my change but it is not relevant for my problem) (Note that the Path are mostly all the same because i wanted to test the plot function first. if this works I will put the Datas for it )
path_nonoise = r'Thesis/NCKSM/FieldData/'
path_noise_additive = r'Thesis/NCKSM/FieldData/'
path_noise_multiplicative = r'Thesis/NCKSM/FieldData/'
path_params_nonoise = r'Thesis/NCKSM/ParameterData/'
path_params_additive = r'Thesis/NCKSM/ParameterData/'
path_params_multiplicative= r'Thesis/NCKSM/ParameterData/'
all_files = len( sorted (glob.glob(path_nonoise + "/*.dat"))) #patern for the files
params_nonoise= pd.read_table(path_params_nonoise+'0'+'.dat',sep=':',names=['Params', 'Value',] )
params_Names_nonoise= np.asarray(params_nonoise['Params'].values.tolist())
params_Values_nonoise= np.asarray(params_nonoise['Value'].values.tolist())
quantum= int(params_Values_nonoise[3])
numberofdatas = np.arange(0,all_files)
#creat a list of the names
timesteps = np.arange(0,all_files*quantum,quantum )
nameofdata = [str(timesteps) for timesteps in timesteps]
# use your path
dfs_nonoise=[]
dfs_noise_additive=[]
dfs_noise_multiplicative=[]
for filename in nameofdata:
foo1=pd.read_table(path_nonoise+filename+'.dat',sep='\s+',names=['X', 'Y','C','Rho'] )
foo2=pd.read_table(path_noise_additive+filename+'.dat',sep='\s+',names=['X', 'Y','C','Rho'] )
foo3=pd.read_table(path_noise_multiplicative+filename+'.dat',sep='\s+',names=['X', 'Y','C','Rho'] )
dfs_nonoise.append(foo1)
dfs_noise_additive.append(foo2)
dfs_noise_multiplicative.append(foo3)
so far so good. Now here is how i defined my Ploting function and that's where I think the problems starts to occur. I Think that my Problemes lies in how i defined my colorbar in the function.
def plotgradient(fig,ax,X,Y,Z ,title ):
nbins= params_Values_nonoise[1] #this creats the gridpoints
X_0= np.asarray(X.values.tolist())
Y_0= np.asarray(Y.values.tolist())
xi, yi = np.mgrid[X_0.min():X_0.max():nbins*1j, Y_0.min():Y_0.max():nbins*1j] #rearange the arrays
zi = np.asarray(Z.values.tolist()) #datas you need
t= ax.pcolormesh(xi, yi, zi.reshape(xi.shape), cmap='jet') #plottingfunction
CS=ax.contour(xi, yi, zi.reshape(xi.shape) )
ax.clabel(CS, inline=1, fontsize=10)
colorbar=plt.colorbar(t, ax=ax, shrink=0.5, aspect=5) # colorbar
ax.set_xlabel('x') #labels
ax.set_ylabel('y')
ax.set_title(title) #title
ax.grid()
now if i want to plot my datas thats what i have done. i just made a for Loop.
Fig, axes = plt.subplots(ncols=2,nrows=1,figsize=(20,15))
my_path=r'/home/belkadi/Thesis/Plots/Plots27.01/additiveandnonoise/'
Ax1,Ax2=axes.flatten()
test=[0,1,2,3,4,5]
for i,j in zip(test,nameofdata[0:5]):
f1=plotgradient(Fig, Ax1,dfs_nonoise[i]['X'],dfs_nonoise[i]['Y'], dfs_nonoise[i]['Rho'],'Density Gradient without noise' )
f2=plotgradient(Fig, Ax2,dfs_nonoise[i]['X'],dfs_nonoise[i]['Y'], dfs_nonoise[i]['Rho'],'Density with noise' )
plt.savefig(my_path+j+".png")
So. I have tried to use plt.clf() Fig.clf() plt.close() at the end of the loop.
My idea was that Python doesn't delete the previous colourbar and thats why I tried to tell python he should clear clear the figure after every plot what it does is that i just delets the figure completly and i get two blank plot.
Like this [Plots after plt.clf()]
then i thought maybe i could clear the axis with Ax1.cla() this also didnt work.
thanks in advance for the help.
And i apologize for my physicist spaghetti code.
Greetings Zino
I solved my problem.
Basically the problem was on how I defined my Plot function.
def plotgradient_double(fig,ax1,ax2,X,Y,Z1,Z2 ,title1, title2 ):
nbins= params_Values[1] #this creats t'he gridpoints
axes= [ax1,ax2]
xi, yi = np.mgrid[X.values.min():X.values.max():nbins*1j, Y.values.min():Y.values.max():nbins*1j] #rearange the arrays
#datas you need
t1= ax1.pcolormesh(xi, yi, Z1.values.reshape(int(nbins),int(nbins)), cmap='jet',vmax=1.)
t2= ax2.pcolormesh(xi, yi, Z2.values.reshape(int(nbins),int(nbins)), cmap='jet',vmin=0,vmax=1. ) #plottingfunction
#CS1=ax1.contour(xi, yi, Z1.values.reshape(int(nbins),int(nbins)) )
#CS2=ax2.contour(xi, yi, Z2.values.reshape(int(nbins),int(nbins)) )
#ax1.clabel(CS1, inline=1, fontsize=10)
#ax2.clabel(CS2, inline=1, fontsize=10)
#colorbar=fig.colorbar(T, ax=axc, shrink=0.5, aspect=5)
for ax in axes:
ax.set_xlabel('x',fontsize=15) #labels
ax.set_ylabel('y',fontsize=15)
#title
#ax.grid()
ax1.set_title(title1,fontsize=15)
ax2.set_title(title2,fontsize=15)
return t1,t2
Afterwards I can creat a colorbar in the for loop to plot multiple data and delete it after every iteration.
with colorbar.remove()
I am trying to plot figures in real time using a for loop. I have the following simple code:
import matplotlib.pyplot as plt
plt.ion()
plt.figure()
for i in range(100):
plt.plot([i], [i], 'o')
plt.draw()
plt.pause(0.0001)
This code does not show the figure until it has finished computing, which I don't want. I want it to draw the figure after every loop. If I replace plt.draw() with plt.show, multiple figures are output in real time, but I want them all to appear in the same figure. Any ideas?
EDIT:
I downloaded PyCharm with Anaconda and everything works fine. I guess it's a problem with Spyder since I tried a few different versions of it without success. If anyone has any clue what is causing this problem in Spyder, let me know!
Adapted for your case from : Python realtime plotting
import matplotlib.pyplot as plt
import numpy as np
import time
fig = plt.figure()
ax = fig.add_subplot(111)
# some X and Y data
x = [0]
y = [0]
li, = ax.plot(x, y,'o')
# draw and show it
fig.canvas.draw()
plt.show(block=False)
# loop to update the data
for i in range(100):
try:
x.append(i)
y.append(i)
# set the new data
li.set_xdata(x)
li.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
time.sleep(0.01)
except KeyboardInterrupt:
plt.close('all')
break
This solution example has worked for me on multiple machines. Try adjusting plt.pause(...)
import matplotlib.pyplot as plt
import numpy as np
F = lambda x: np.sin(2*x)
plt.ion()
x = np.linspace(0, 1, 200)
plt.plot(x, F(x))
for i in range(100):
if 'ax' in globals(): ax.remove()
newx = np.random.choice(x, size = 10)
ax = plt.scatter(newx, F(newx))
plt.pause(0.05)
plt.ioff()
plt.show()
Hey I was having the same problem, I checked other questions and my issue was solved when I plugged a pause into my solution. Here's some example code that worked for me.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.arange(0, 4*np.pi, 0.1)
y = [np.sin(i) for i in x]
plt.plot(x, y, 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2 for i in y], 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2*i+0.25 for i in y], 'r-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
The solution was posted here:
Matplotlib ion() and subprocesses
The problem - and the solution - is highly dependent on the plot.draw() function within the Python environment and back end, and may even vary in different product releases. It manifests itself in different ways depending on the environment. The problem shows up in many places on stackoverflow with some solutions working for some people and not for others.
The gold standard on my Windows laptop is running the Python from the command line - no IDE, just plain vanilla Python3. draw() as shown in the example always works fine there.
If I try it in Jupyter notebook on the same machine, no amount of draw(), plot.pause(), plot.show(), or any other suggestion works. I tried %matplotlib with notebook, widget and ipympl. Nothing gets drawn until complete end of cell code execution.
Some other sources on stackoverflow suggested using figure.canvas.flush_events(). I had some success with that and investigated further.
The best solution turned out to be to run the draw() at the figure.canvas level instead of the axes or plot level.
You can get the figure by creating your plot with command:
fig, graph, = plt.subplots()
or, if you've already created the plot, as in the code at the top of the ticket, put the following outside the loop:
fig = plt.gcf() #get current figure
Inside the loop, instead of plt.draw(), use
fig.canvas.draw()
It's proven reliable in my Jupyter Notebook environment even when running multiple axes/plots across multiple figures. I can drop in sleep() statements and everything appears when expected.
Your mileage may vary.
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()
I am fairly new in python, and I am trying to have a plot, based on data stored in a file. This file may be updated at any time, so I am trying to make the drawing updated every 3 seconds (so I don't use all the CPU). My problem is that the GUI freezes after the lunch.
#!/usr/bin/python
# _*_ coding: utf8 _*_
import matplotlib.pyplot as plt
import numpy as np
import time
plt.ion()
plt.figure()
i=0
while 1:
taille=0
fichier=np.loadtxt('data/US.SAVE')
fichier1=np.loadtxt('data/cond.SAVE')
taille1=np.size(fichier1[:,1])
taille=np.size(fichier[:,1])
min=min(fichier[0,0],fichier1[0,0]);
fichier[:,0]=fichier[:,0]-min
fichier1[:,0]=fichier1[:,0]-min
if (taille != taille1) :
printErrors("TAILLE DE FICHIERS DIFFERENTES")
nb_chunks=np.size(fichier1[1,:])
nb_inputs=np.size(fichier[1,:])
plt.subplot(3,1,1)
plt.bar(fichier[:,0],fichier[:,1],align='center',width=0.0001, facecolor='b', label="US")
x1,x2,y1,y2 = plt.axis()
x1=x1-0.0001
plt.axis([x1, x2, y1, 1.2])
plt.legend(ncol=3,prop={'size':9})
plt.title("US ")
plt.ylabel('Activation')
plt.xlabel('Time')
plt.subplot(3,1,2)
plt.bar(fichier1[:,0],fichier1[:,1],align='center',width=0.0001, facecolor='b', label="response")
plt.axis([x1, x2, y1, 1.2])
plt.legend(ncol=3,prop={'size':9})
plt.title("Response ")
plt.ylabel('Activation')
plt.xlabel('Time')
plt.subplot(3,1,3)
plt.bar(fichier[:,0]-fichier1[:,0],fichier1[:,1],align='center',width=0.0001, facecolor='b', label="Error")
plt.axis([x1, x2, y1, 1.2])
plt.legend(ncol=3,prop={'size':9})
plt.title("Error")
plt.ylabel('Activation')
plt.xlabel('Time')
plt.draw()
name1='data/Conditionnement.eps'
plt.savefig(name1,dpi=256)
plt.draw()
del fichier,fichier1,min
i=i+1
time.sleep(3)
plt.show()
I did not find any other topic on a file based drawing.
You want to use the plt.pause(3) function instead of time.sleep(). pause includes the necessary calls to the gui main loop to cause the figure to re-draw.
also see: Python- 1 second plots continous presentation, matplotlib real-time linear line, pylab.ion() in python 2, matplotlib 1.1.1 and updating of the plot while the program runs,
On top of the answer of #tcaswell (that solve the problem), I suggest to rethink the script in a more OO way.
I have tried this:
plt.ion()
plt.figure()
plt.show()
while True:
x=np.arange(10)
y=np.random.rand(10)
plt.subplot(121)
plt.plot(x,y)
plt.subplot(122)
plt.plot(x,2*y)
plt.draw()
plt.pause(3)
but it does not work (it looks like it opens a gui at plt.figure and then at each loop.
A solution like this:
plt.ion()
fig, ax = plt.subplots(nrows=2, ncols=1)
plt.show()
while True:
x=np.arange(10)
y=np.random.rand(10)
ax[0].plot(x,y)
ax[1].plot(x,2*y)
plt.draw()
plt.pause(3)
is much more efficient (axes are created only once), neater (at the end matplotlib is OO) and potentially less prone to memory leaks.
Besides, from your most I gather that at each loop you read in the files again and then plot the new lines. If this is the case, you want to clear first the content of the axes before redrawing. In my simple case you can clear the axes with
for a in ax:
a.clear()
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.