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:
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):
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 .
bqplot allows anyone to build fully interactive web applications in Python, using surprisingly few lines of code.
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
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')
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With