0

How can I efficiently display similar plots with ipywidgets using Jupyter Notebook?

I wish to plot interactively a heavy plot (heavy in the sense that it has lots of data points and takes some time to plot it) and modify a single element of it using interact from ipywidgets without replotting all the complicated plot. Is there a builtin functionality to do this?

basically what I'm trying to do is

import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact
import matplotlib.patches as patches
%matplotlib inline #ideally nbagg

def complicated plot(t):
    plt.plot(HEAVY_DATA_SET)
    ax = plt.gca()
    p = patches.Rectangle(something_that_depends_on_t)
    ax.add_patch(p)

interact(complicatedplot, t=(1, 100));

Right now it takes up to 2 seconds for each replot. I expect there are ways to keep the figure there and just replace that rectangle.

A hack would be to create a figure of the constant part, make it background to the plot and just plot the rectangle part. but the sounds too dirty

Thank you

gota
  • 2,338
  • 4
  • 25
  • 45
  • Can you add more details about what you really want to do? In scatter plots for example, if your plot is referenced in the `p` variable, you could just do `p.set_offsets` to redefine the data. Maybe you can do something like `ax.get_children()` and modify one of those objects. And for the widgets, I think ipywidgets have an `observe` method where you can define a function to update, in your case you can define the function to modify your plot – PerroNoob Jul 22 '16 at 14:11
  • I want to show 100 line plots (plt.plot(HEAVY_DATA_SET)) and then just add a vertical rectangle on top of those lines.. – gota Jul 22 '16 at 14:13
  • Maybe you can remove the rectangle from `ax.get_children()` and just redraw the rectangle? For example, if you call `ax.get_children()`, you will see in the list some ` – PerroNoob Jul 22 '16 at 14:26
  • 1
    Even better, you can do `p=patches.Rectangle(something_that_depends_on_t)` and then `p.xy=(new coordinates)` to change the rectangle coordinates – PerroNoob Jul 22 '16 at 14:29
  • I'm going to try it! If it works, please make it an answer so that I can accept it! – gota Jul 22 '16 at 14:31
  • it almost perfectly works!!! – gota Jul 22 '16 at 14:59

1 Answers1

1

This is an rough example of an interactive way to change a rectangle width (I'm assuming you are in an IPython or Jupyter notebook):

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches

import ipywidgets
from IPython.display import display

%matplotlib nbagg

f = plt.figure()
ax = plt.gca()

ax.add_patch(
    patches.Rectangle(
        (0.1, 0.1),   # (x,y)
        0.5,          # width
        0.5,          # height
    )
)

# There must be an easier way to reference the rectangle
rect = ax.get_children()[0]

# Create a slider widget
my_widget = ipywidgets.FloatSlider(value=0.5, min=0.1, max=1, step=0.1, description=('Slider'))

# This function will be called when the slider changes
# It takes the current value of the slider
def change_rectangle_width():
    rect.set_width(my_widget.value)
    plt.draw()

# Now define what is called when the slider changes
my_widget.on_trait_change(change_rectangle_width)

# Show the slider
display(my_widget)

Then if you move the slider, the width of the rectangle will change. I'll try to tidy up the code, but you may have the idea. To change the coordinates, you have to do rect.xy = (x0, y0), where x0 and y0 are new coordinates.

PerroNoob
  • 843
  • 2
  • 16
  • 36