Search code examples
matplotlibioipywidgetsbytesio

Adding a 'Display all plots' option using ipywidgets and io


I am creating interactive plots using io and ipywidgets. The idea is to be able to select which 'riskdriver' (rd) plot to display. I have the following code which works for each individual plot.

import matplotlib.pyplot as plt
import numpy as np
import io
import base64
from PIL import Image
from ipywidgets import interact

@interact(rd = ['all', 'rd1', 'rd2', 'rd3', 'rd4'])
def display_plot(rd):
  my_results = {}
  for rd in ['rd1', 'rd2', 'rd3', 'rd4']:
    f = io.BytesIO()
    a = np.random.rand(10)
    p = plt.bar(range(len(a)), a)
    plt.savefig(f, format = "png")
    my_results[rd] = f
    plt.close()

  img = Image.open(io.BytesIO(my_results[rd].getvalue()))
  display(img)

As you will notice, the code creates an option 'all', however, I am not sure how to adjust the code to actually display all plots when selecting this option. Can someone please help me with this?


Solution

  • You can use interact (or interactive) to made like this:

    import matplotlib.pyplot as plt
    from ipywidgets import interactive, Output
    
    rds = ['rd1', 'rd2', 'rd3', 'rd4']
    all_outs = []
    my_results = {}
    
    for rd in rds:
        current_out = Output()
        a = np.random.rand(10)
        p = plt.bar(range(len(a)), a)
        with current_out:
            plt.show()
        
        my_results[rd] = current_out
        all_outs.append(current_out)
        plt.close()
    
    def change_image(value): 
        if value != "all":
            display(my_results[value])
        else:
            display(HBox([my_results[img] for img in rds]))
    
    interactive(change_image, value=["all"]+rds)
    

    A picture of four blue graphs in a horizontal line

    But, ipywidgets is more powerful than this, so you can use a widget named Tab with Output, because Tabs only accepts another widgets:

    import matplotlib.pyplot as plt
    from ipywidgets import Output, Tab, HBox
    import numpy as np
    
    rds = ['rd1', 'rd2', 'rd3', 'rd4']
    childrens = []
    
    for rd in rds:
        current_out = Output()
        a = np.random.rand(10)
        p = plt.bar(range(len(a)), a)
        with current_out:
            plt.show()
        
        childrens.append(current_out)
        plt.close()
    
    childrens.insert(0, HBox(*[childrens]))
    tab = Tab(childrens)
    tab.titles = ["all"] + rds
    display(tab)
    

    enter image description here