I wanted to make an animation in spyder but i just get a static plot. this is the code.
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
plt.axis([-10,10,-10,10])
n=10
pos=(20*np.random.sample(n*2)-10).reshape(n,2)
vel=(0.3*np.random.normal(size=n*2)).reshape(n,2)
sizes=100*np.random.sample(n)+100
colors=np.random.sample([n,4]
circles=plt.scatter(pos[:,0], pos[:,1], marker='o', s=sizes, c=colors)
for i in range(100):
pos=pos+vel
bounce=abs(pos)>10
vel[bounce] = -vel[bounce]
circles.set_offsets(pos)
plt.draw()
plt.show()
this is what i get, I've tried with %matplotlib qt5 but it doesn't change the output and the stays still1]1
There are two things you need to do to make the animation work.
First, is that you need to show the figure once the animation made, so plt.show() should get out of the for loop.
Also to be able to see the frames, you need to put a small amount of time between them, which an be achieved by adding, for example, plt.pause(t) (t in seconds) in between the frames.
The code shown below is the edited code generating an animated plot.
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
plt.axis([-10,10,-10,10])
n=10
pos=(20*np.random.sample(n*2)-10).reshape(n,2)
vel=(0.3*np.random.normal(size=n*2)).reshape(n,2)
sizes=100*np.random.sample(n)+100
colors=np.random.sample([n,4])
circles=plt.scatter(pos[:,0], pos[:,1], marker='o', s=sizes, c=colors)
for i in range(100):
pos=pos+vel
bounce=abs(pos)>10
vel[bounce] = -vel[bounce]
circles.set_offsets(pos)
plt.draw()
plt.pause(0.05)
plt.show()
Related
I am trying to create a real-time colour map. I want to continuously change slightly the RGB values of some elements in the matrix to make up my colour map. I read data from an excel file and a part of my data looks like this
Then I want to show the colour change in my colour map in one figure like a video. I tried this code:
df=pd.read_excel(r"G:\3Y_individualProject\Crop_color_data.xlsx", usecols="C:E")
color_data_2d=np.array(df.iloc[0:101])
color_data_1d=np.reshape(color_data_2d,(300))
color_data=color_data_1d.reshape(5,20,3)
for x in range(5):
fig, ax = plt.subplots()
ax.imshow(color_data)
ax.set_aspect("equal")
plt.pause(0.05)
for i in range(3):
color_data[0,1,i]=color_data[0,1,i]+0.1
color_data[1,1,i]=color_data[1,1,i]+0.2
color_data[2,1,i]=color_data[1,1,i]+0.25
print(color_data)
But it plots many different figures instead of showing them in a figure as I expected. I've also just tried to learn and use matplotlib.animation. I have tried the code below:
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
from matplotlib import cm
from matplotlib.animation import FuncAnimation
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import itertools
def changeColor(x):
fig, ax = plt.subplots()
ax.imshow(color_data)
ax.set_aspect("equal")
for i in range(3):
color_data[0,1,i]=color_data[0,1,i]+0.1
color_data[1,1,i]=color_data[1,1,i]+0.2
color_data[2,1,i]=color_data[1,1,i]+0.25
results=FuncAnimation(plt.gcf(), changeColor, interval=5)
plt.tight_layout()
plt.show()
But with that code, my figure doesn't even display anything. As said I am quite new to matplotlib.animation so can anyone show me how to use matplotlib.animation or any other way to plot a real-time color map in my case, please? Thank you so much!
TL;DR: I cannot remove or adjust xticks from inset_axis.
I was trying to prepare a zoom-in plot, where a box will display a zoomed version of the plot. However, the x-ticks of the zoomed in plot were too entangled and I decided to manually assign them.
This is a snip from the original plot.
So I tried the following lines:
inset_axe.set_xticks([])
inset_axe.set_yticks([])
It indeed removed the yticks, but xticks are not affected.
Here is a minimum working example. The issue persists in the MWE as well.
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np
import matplotlib.pyplot as plt
#####Just creating random N,Q function
a=0.1
Q=np.linspace(-5,4,1000)
M=a*np.ones(2000)
P=1.4**4*np.ones(2000)+a
N=[1.4**(x)+a for x in Q]
N=np.asarray(list(M)+N+list(P))
Q=np.logspace(-9,6,5000)
####################################
g, axes = plt.subplots(1)
inset_axe = inset_axes(axes,width="60%", height="25%", loc='lower left',
bbox_to_anchor=(0.6,0.15,0.7,.7), bbox_transform=axes.transAxes)
inset_axe.semilogx(Q[2200:2400],N[2200:2400])
inset_axe.set_yticks([])
inset_axe.set_xticks([])
axes.semilogx(Q,N)
plt.show()
Is this a bug or do I have a small mistake that I cannot see? Is there a way around this?
If it helps, I use Microsoft VS and matplotlib version is 3.3.3.
Most of your ticks are minor.
You may also want to use the more lightweight axes.inset_axes:
import numpy as np
import matplotlib.pyplot as plt
#####Just creating random N,Q function
a=0.1
Q=np.linspace(-5,4,1000)
M=a*np.ones(2000)
P=1.4**4*np.ones(2000)+a
N=[1.4**(x)+a for x in Q]
N=np.asarray(list(M)+N+list(P))
Q=np.logspace(-9,6,5000)
####################################
g, ax = plt.subplots(1)
inset_axe = ax.inset_axes([0.6, 0.2, 0.2, 0.2], transform=ax.transAxes)
inset_axe.semilogx(Q[2200:2400], N[2200:2400])
inset_axe.set_yticks([])
#################
inset_axe.set_xticks([], minor=True)
#################
inset_axe.set_xticks([])
ax.semilogx(Q,N)
ax.set_xticks([])
plt.show()
If I run the following code:
import matplotlib.pyplot as plt
import numpy as np
#plt.ion()
while True:
print('loop')
x = range(10)
y = np.random.rand(10)
plt.scatter(x, y)
plt.show()
Then I see a scatter plot displayed on my screen. Then each time I close the window for the plot, it displays a new plot with new data.
However, if I uncomment the line plt.ion(), nothing is displayed at all. There is no window created, and the program just continues through the loop, printing out 'loop'.
I want to be able to display a graph, and then return to the code automatically, with the graph still displayed. How can I do this?
If you want to plot on top of the same figure window, rather than generating a new window at every iteration the following will work:
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
fig, ax = plt.subplots(1, 1)
while True:
# If wanting to see an "animation" of points added, add a pause to allow the plotting to take place
plt.pause(1)
x = range(10)
y = np.random.rand(10)
ax.scatter(x, y)
The result you see will depend on the which matplotlib backend you are using. If you're wanting to see the new points being added you should use Qt4 or Qt5
Some seaborn methods like JointPlot create new figures on each call. This makes it impossible to create a simple animation like in matplotlib where iterative calls to plt.cla() or plt.clf() allow to update the contents of a figure without closing/opening the window each time.
The only solution I currently see is:
for t in range(iterations):
# .. update your data ..
if 'jp' in locals():
plt.close(jp.fig)
jp = sns.jointplot(x=data[0], y=data[1])
plt.pause(0.01)
This works because we close the previous window right before creating a new one. But of course, this is far from ideal.
Is there a better way? Can the plot somehow be done directly on a previously generated Figure object? Or is there a way to prevent these methods to generate new figures on each call?
sns.jointplot creates a figure by itself. In order to animate the jointplot, one might therefore reuse this created figure instead of recreating a new one in each iteration.
jointplot internally creates a JointGrid, so it makes sense to directly use this and plot the joint axes and the marginals individually. In each step of the animation one would then update the data, clear the axes and set them up just as during creation of the grid. Unfortunately, this last step involves a lot of code lines.
The final code may then look like:
import matplotlib.pyplot as plt
import matplotlib.animation
import seaborn as sns
import numpy as np
def get_data(i=0):
x,y = np.random.normal(loc=i,scale=3,size=(2, 260))
return x,y
x,y = get_data()
g = sns.JointGrid(x=x, y=y, size=4)
lim = (-10,10)
def prep_axes(g, xlim, ylim):
g.ax_joint.clear()
g.ax_joint.set_xlim(xlim)
g.ax_joint.set_ylim(ylim)
g.ax_marg_x.clear()
g.ax_marg_x.set_xlim(xlim)
g.ax_marg_y.clear()
g.ax_marg_y.set_ylim(ylim)
plt.setp(g.ax_marg_x.get_xticklabels(), visible=False)
plt.setp(g.ax_marg_y.get_yticklabels(), visible=False)
plt.setp(g.ax_marg_x.yaxis.get_majorticklines(), visible=False)
plt.setp(g.ax_marg_x.yaxis.get_minorticklines(), visible=False)
plt.setp(g.ax_marg_y.xaxis.get_majorticklines(), visible=False)
plt.setp(g.ax_marg_y.xaxis.get_minorticklines(), visible=False)
plt.setp(g.ax_marg_x.get_yticklabels(), visible=False)
plt.setp(g.ax_marg_y.get_xticklabels(), visible=False)
def animate(i):
g.x, g.y = get_data(i)
prep_axes(g, lim, lim)
g.plot_joint(sns.kdeplot, cmap="Purples_d")
g.plot_marginals(sns.kdeplot, color="m", shade=True)
frames=np.sin(np.linspace(0,2*np.pi,17))*5
ani = matplotlib.animation.FuncAnimation(g.fig, animate, frames=frames, repeat=True)
plt.show()
using the celluloid package (https://github.com/jwkvam/celluloid) I was able to animate seaborn plots without much hassle:
import numpy as np
from celluloid import Camera
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
fig = plt.figure()
camera = Camera(fig)
# animation draws one data point at a time
for i in range(0, data.shape[0]):
plot = sns.scatterplot(x=data.x[:i], y=data.y[:i])
camera.snap()
anim = camera.animate(blit=False)
anim.save('animation.mp4')
I'm sure similar code could be written for jointplots
I am plotting and saving thousands of files for later animation in a loop like so:
import matplotlib.pyplot as plt
for result in results:
plt.figure()
plt.plot(result) # this changes
plt.xlabel('xlabel') # this doesn't change
plt.ylabel('ylabel') # this doesn't change
plt.title('title') # this changes
plt.ylim([0,1]) # this doesn't change
plt.grid(True) # this doesn't change
plt.savefig(location, bbox_inches=0) # this changes
When I run this with a lot of results, it crashes after several thousand plots are saved. I think what I want to do is reuse my axes like in this answer: https://stackoverflow.com/a/11688881/354979 but I don't understand how. How can I optimize it?
I would create a single figure and clear the figure each time (use .clf).
import matplotlib.pyplot as plt
fig = plt.figure()
for result in results:
fig.clf() # Clears the current figure
...
You are running out of memory since each call to plt.figure creates a new figure object. Per #tcaswell's comment, I think this would be faster than .close. The differences are explained in:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
Although this question is old, the answer would be:
import matplotlib.pyplot as plt
fig = plt.figure()
plot = plt.plot(results[0])
title = plt.title('title')
plt.xlabel('xlabel')
plt.ylabel('ylabel')
plt.ylim([0,1])
plt.grid(True)
for i in range(1,len(results)):
plot.set_data(results[i])
title.set_text('new title')
plt.savefig(location[i], bbox_inches=0)
plt.close('all')