Clear MatPlotLib figure in Jupyter Python notebook
What you call overhead is the source of the problem. Or in other words: If in each call to the function, a new figure is created, is it surprising that you will end up with a lot of figures?
The idea is of course to draw a single figure. In order to be able to later update the figure the %matplotlib notebook
backend is needed.
The function that gets called when changing the slider will then only need to update the viewing angle and redraw the canvas.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import ipywidgets as widgets
from IPython.display import display
%matplotlib notebook
# generate test data
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, projection='3d')
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
ax.scatter(x, y, z)
ax.view_init(20, 40)
# show plot
plt.show()
def update_plot(angle1 = 20, angle2 = 40):
# set view angle
ax.view_init(angle1, angle2)
fig.canvas.draw_idle()
# prepare widgets
angle1_slider = widgets.IntSlider(20, min = 0, max = 60)
angle1_label = widgets.Label(value = 'Angle 1 value is: ' + str(angle1_slider.value))
display(angle1_slider, angle1_label)
# handle angle 1 update
def update_angle1(value):
update_plot(angle1 = value['new'])
angle1_label.value = 'Angle 1 value is: ' + str(value.new)
angle1_slider.observe(update_angle1, names = 'value')
This is how it would look like:
Pieter
Neurosurgeon, PhD on intraoperative MRI, research on image guided surgery and brain computer interfaces, developer of mobile apps for clinical decision support
Updated on June 14, 2022Comments
-
Pieter almost 2 years
I want a 3D scatter plot in MatPlotLib to be rotated interactively in a Jupyter Python notebook. For that reason I integrated a slider from
ipywidgets
to update the view angle. The test code below shows what I am trying to achieve. The problem is that a new figure is added below the previous one, instead of the current figure cleared. I triedplt.close(fig)
,plt.cla()
andplt.clf()
without success. (further I realize that there is overhead in recreating the figure and axes but that is the lesser part of my current concerns...)Here is the (test) code:
# init import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import ipywidgets as widgets from IPython.display import display # generate test data x = np.random.rand(100) y = np.random.rand(100) z = np.random.rand(100) # prepare plot def draw_plot(angle1 = 20, angle2 = 40): # create figure fig = plt.figure(figsize=(15,10)) ax = fig.add_subplot(111, projection='3d') ax.set_xlabel('X axis') ax.set_ylabel('Y axis') ax.set_zlabel('Z axis') ax.scatter(x, y, z) # set view angle ax.view_init(angle1, angle2) # show plot plt.show() # prepare widgets angle1_slider = widgets.IntSlider(20, min = 0, max = 60) angle1_label = widgets.Label(value = 'Angle 1 value is: ' + str(angle1_slider.value)) display(angle1_slider, angle1_label) # handle angle 1 update def update_angle1(value): draw_plot(angle1 = value['new']) angle1_label.value = 'Angle 1 value is: ' + str(value.new) angle1_slider.observe(update_angle1, names = 'value') # draw initial plot draw_plot()
Any suggestions would be appreciated!
-
Pieter about 7 yearsExcellent! I did not know
fig.canvas.draw_idle()
which solved the issue indeed. And even better, I always used%matplotlib inline
but%matplotlib notebook
is very useful too! Thanks!