I am trying to make a histogram that will change as a function of ipywidgets sliders. Unfortunately there is no equivalent of set_data
for a histogram so I am attempting to roll my own by manipulating the the patches of the axis. Unfortunately I don’t seem to always remove all of the pre-existing patches, resulting in a ghosting effect. My current approach is that on every update of the slider I:
- remove all the patches from the
axis
object - compute new heights and bins
- create new
Rectangle
patches and add them to object fig.canvas.draw()
Am I missing an important step in removing patches from an axis? Any help in eliminating this ghosting would be much appreciated. (A minimal, hopefully working, example follows the gif)
Code to reproduce:
In a jupyter notebok or jupyterlab run
%matplotlib ipympl
import ipywidgets as widgets
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np
plt.ioff()
fig, ax = plt.subplots()
plt.ion()
def f(loc, scale):
return np.random.randn(10000)*scale + loc
tops, bins, patches = ax.hist(f(0,1.5), bins='auto')
def update_plot(change):
for p in ax.patches:
p.set_visible(False)
p.remove()
arr = f(loc_slider.value, scale_slider.value)
heights, bins = np.histogram(arr, bins='auto')
width = bins[1]-bins[0]
for i in range(len(heights)):
p = Rectangle((bins[i],0), width=width, height=heights[i])
ax.add_patch(p)
fig.canvas.draw()
loc_slider = widgets.FloatSlider(min=-10,max=10,description='loc')
scale_slider = widgets.FloatSlider(min=.1,max=10,value=1.5,description='scale')
loc_slider.observe(update_plot, names=['value'])
scale_slider.observe(update_plot, names=['value'])
ax.set_xlim([-12.5,12.5])
display(loc_slider)
display(scale_slider)
display(fig.canvas)
I don’t think this is a jupyter problem as I see the same if I set the backend to qt with %matplotlib qt
I’m also pretty sure this isn’t a bug and instead is me not doing something I should. If this is a bug I’m happy to open a bug report.
A few notes:
- Using fewer points (10000 -> 1000) does not help
- I can’t use something like
cla
because that would remove other content such as lines - eventually I will not remove all the patches, instead I will keep track of the histogram patches and replace them
- Updating the existing patches works better, but is not a solution as I may want to be able to change the number of bins.
- I tried putting an extra
fig.canvas.draw
earlier, sadly this did not help
Versions:
ipympl: master
ipywidgets: 7.5.1
matplotlib: 3.2.2
jupyterlab: 2.2.2
Thanks,
Ian