Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jupyter: How can I interactively select series to plot using widgets.SelectMultiple()?

Background:

A similar question has been asked here, but was not very specific and was mostly only answered with references to other sources. My case feels pretty basic, and I'm surprised by how hard it was to find working examples of this.

Goal:

I would just like to be able to select any subset from a pandas dataframe to make a plot like below by using a widget like this:

enter image description here

My attempts:

The widgets.SelectMultiple() widget is briefly described in the docs, and this section describes how you can interactively change values for series in a plot. I've tried to replace the central parts of the latter demonstration with the functionalities of widgets.SelectMultiple(), but with little success.

I think I'm really close to get this working, and I hope all I have to do is to find out what to write under the section marked '# what to do!?' in the snippet below. As the snippet now stands, a widget and chart is produced, but there's no functioning link between them.

Issues that I'm aware of:

My reproduction of the examples provided in the links has some flaws. I think df and widg should be included in the multiplot function. The same goes perhaps for the interactive plot function. I've tried different variations of that too, but with no success.

Snippet (used in a Jupyter Notebook):

# imports
%matplotlib inline

from ipywidgets import interactive
import pandas as pd
import numpy as np
from jupyterthemes import jtplot

# Sample data
np.random.seed(123)
rows = 50
dfx = pd.DataFrame(np.random.randint(90,110,size=(rows, 1)), columns=['Variable X'])
dfy = pd.DataFrame(np.random.randint(25,68,size=(rows, 1)), columns=['Variable Y'])
dfz = pd.DataFrame(np.random.randint(60,70,size=(rows, 1)), columns=['Variable Z'])

df = pd.concat([dfx,dfy,dfz], axis = 1)
#jtplot.style()

import ipywidgets as widgets
from IPython.display import display

def multiplot():
    opts = df.columns.values

    widg = widgets.SelectMultiple(
           options=opts,
           value=[opts[1]],
           rows=len(opts),
           description='Variables',
           disabled=False)

    display(widg)

    # what to do!? 
    df.plot()

    #attempts:
    #df[widg].plot()
    #df[widg.value[0]].plot()

interactive_plot = interactive(multiplot)
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot

Output (flawed):

enter image description here

like image 861
vestland Avatar asked Feb 11 '19 11:02

vestland


People also ask

How do I use Ipywidgets interaction?

At the most basic level, interact autogenerates UI controls for function arguments, and then calls the function with those arguments when you manipulate the controls interactively. To use interact , you need to define a function that you want to explore. Here is a function that returns its only argument x .

Is Bqplot interactive?

bqplot allows anyone to build fully interactive web applications in Python, using surprisingly few lines of code.


2 Answers

Thanks for the clear example. Unfortunately, I am not sure that SelectMultiple can be used in the way you intend.

Generally, for an interact call, you need a function that you pass arguments to. You should not need to create the widget inside the body of the function, the interact call should understand what type of input widget is required from the passed parameter.

See here for some examples where you specify a list of string options (https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html#Widget-abbreviations)

I have made some small alterations to your code to product an interact with a Dropdown selector. I suspect if you want to use a SelectMultiple rather than a Dropdown, this is beyond interact functionality. You might need to create the widget separately and then use observe.

# imports
%matplotlib inline

from ipywidgets import interactive
import pandas as pd
import numpy as np
# from jupyterthemes import jtplot

# Sample data
np.random.seed(123)
rows = 50
dfx = pd.DataFrame(np.random.randint(90,110,size=(rows, 1)), columns=['Variable X'])
dfy = pd.DataFrame(np.random.randint(25,68,size=(rows, 1)), columns=['Variable Y'])
dfz = pd.DataFrame(np.random.randint(60,70,size=(rows, 1)), columns=['Variable Z'])

df = pd.concat([dfx,dfy,dfz], axis = 1)
#jtplot.style()

import ipywidgets as widgets
from IPython.display import display

def multiplot(a):
    opts = df.columns.values
    df.loc[:, a].plot()

interactive_plot = interactive(multiplot, a=['Variable X', 'Variable Y', 'Variable Z'])
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot

enter image description here

And here's a version using observe, a SelectMultiple widget and an Output widget:

# imports
%matplotlib inline

from ipywidgets import interactive
import pandas as pd
import numpy as np
from IPython.display import clear_output
import matplotlib.pyplot as plt

# Sample data
np.random.seed(123)
rows = 50
dfx = pd.DataFrame(np.random.randint(90,110,size=(rows, 1)), columns=['Variable X'])
dfy = pd.DataFrame(np.random.randint(25,68,size=(rows, 1)), columns=['Variable Y'])
dfz = pd.DataFrame(np.random.randint(60,70,size=(rows, 1)), columns=['Variable Z'])

df = pd.concat([dfx,dfy,dfz], axis = 1)
#jtplot.style()

import ipywidgets as widgets
from IPython.display import display

opts = df.columns.values

selector = widgets.SelectMultiple(
options=opts,
value=[opts[1]],
rows=len(opts),
description='Variables',
disabled=False)

output = widgets.Output()

display(selector)
display(output)

def multiplot(widg):
    choices = widg['new']
    data = df.loc[:, choices] if choices else df
    output.clear_output(wait=True)
    with output:
        ax = data.plot()
        plt.show()

selector.observe(multiplot, names='value')

enter image description here

like image 152
ac24 Avatar answered Sep 22 '22 11:09

ac24


The easiest way I have found to use the multipleSelect widget is using the decorator interact.

%matplotlib inline
import numpy as np
import pandas as pd
from ipywidgets.widgets import interact, SelectMultiple

np.random.seed(123)
rows = 50
dfx = pd.DataFrame(np.random.randint(90,110,size=(rows, 1)), columns=['Variable X'])
dfy = pd.DataFrame(np.random.randint(25,68,size=(rows, 1)), columns=['Variable Y'])
dfz = pd.DataFrame(np.random.randint(60,70,size=(rows, 1)), columns=['Variable Z'])

df = pd.concat([dfx,dfy,dfz], axis = 1)

sel_mul = SelectMultiple(description="Variables",options=df.columns,value=['Variable X','Variable Z'],disabled=False)
@interact(variables=sel_mul)
def plot_multiple(variables):
    df[list(variables)].plot()

And this is the result.

like image 36
Escafandra Avatar answered Sep 18 '22 11:09

Escafandra