I am using the Ipython notebook, pandas library, and the bokeh plotting library and I have a function that generates a gridplot. I am trying to set up some checkboxes, with each checkbox corresponding to one of those plots and then update the gridplot with only the plots that have their corresponding checkboxes selected. There does not seem to be much support for the ipywidgets libray. This is my attempt so far; I am not sure how to pass the checkboxes I created to my function to update my gridplot though, so any help will be much appreciated. Thanks.
attributes = df.columns.tolist()
from ipywidgets import Checkbox, interact
from IPython.display import display
chk = [Checkbox(description=attributes[i]) for i in range(len(attributes))]
#this displays the checkboxes I created correctly
display(*chk)
#update plot takes in the names of the columns to be displayed and returns
#a gridplot containing all corresponding plots
#not sure about the part below though
interact(updatePlot,args=chk)
This displays the checkboxes and calls the updatePlot function as they're changed:
from ipywidgets import Checkbox, interact
from IPython.display import display
l = ["Dog", "Cat", "Mouse"]
chk = [Checkbox(description=a) for a in l]
def updatePlot(**kwargs):
print([(k,v) for k, v in kwargs.items()])
interact(updatePlot, **{c.description: c.value for c in chk})
Related
I am wondering if it is possible to dynamically change which column from a GeoPandas GeoDataFrame is shown in a geoplot. For example, if I have a GeoDataFrame with different columns representing Global data on different dates, how could I have an interactive slider which allows me to show data for a specific date in a geoplot? I see matplotlib.widgets has a slider, but I cannot figure out how to apply that to a GeoDataFrame and geoplot.
The ipywidgets.interact decorator is useful for quickly turning a function into an interactive widget
from ipywidgets import interact
# plot some GeoDataFrame, e.g. states
#interact(x=states.columns)
def on_trait_change(x):
states.plot(x)
I found it convenient to use interact to set up interactive widgets in combination with a function modifying the data/plot based on the parameters selected in the widgets. For demonstration I implemented a slider widget and a drop down menu widget. Dependent on your use case, you might need only one.
# import relevant modules
import geopandas as gpd
import ipywidgets
import numpy as np
# load a sample data set
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
# set seed for reproducability
np.random.seed(0)
# generate 3 artifical columns: random proportions of the gdp_md_est column (logarithmized)
for date in ['date1', 'date2', 'date3']:
world[date] = np.log(world.gdp_md_est*np.random.rand(len(world)))
# function defining what should happen if the user selects a specific date and continent
def on_trait_change(date, continent):
df=world[world['continent'] == continent] # sub set data
df.plot(f'date{date}') # to plot for example column'date2'
# generating the interactive plot with two widgets
interact(on_trait_change, date=ipywidgets.widgets.IntSlider(min=1, max=3, value=2), continent=list(set(world.continent)))
Sorry if this is a basic question, but I haven't been able to find an answer in the bokeh documentation. I want to be able to plot a bokeh plot without the long GlyphRenderer list displaying.
I have tried saving the p.hexbin line to a variable called 'test'. However, this new 'test' variable is being saved as a tuple and can no longer be used with the 'show()' function to display a bokeh plot. The example code I am using here is straight from the bokeh documentation site.
import numpy as np
from bokeh.models import HoverTool
from bokeh.plotting import figure, show
x = 2 + 2*np.random.standard_normal(500)
y = 2 + 2*np.random.standard_normal(500)
p = figure(match_aspect=True, tools="wheel_zoom,reset")
p.background_fill_color = '#440154'
p.grid.visible = False
p.hexbin(x, y, size=0.5, hover_color="pink", hover_alpha=0.8)
hover = HoverTool(tooltips=[("count", "#c"), ("(q,r)", "(#q, #r)")])
p.add_tools(hover)
show(p)
I only want the hexbin plot to display when I run the code, not the Glyph tuple.
I have tried saving the p.hexbin line to a variable called 'test'. However, this new 'test' variable is being saved as a tuple and can no longer be used with the 'show()' function to display a bokeh plot.
Printing outputs is standard Python behavior, there is nothing we can do about that. The function returns a list, so Python will print a list. The only thing to suppress that behavior, as you have noted, is to assign the output to a variable. However, since you don't care about its value, it can/should be ignored. There is no reason to pass it to show, you should continue to call show, on p, exactly the way you have been without any change:
rs = p.hexbin(x, y, size=0.5, hover_color="pink", hover_alpha=0.8)
show(p)
I am trying to make a interactive function where I can control the input with 2 widgets for the same variable. I Trying this because I want to have the option to slider the values (for a quick view) and also pick one specific (typing one value). I tried this linking the widgets with the ipywidget.jslink. I guessed once the widgets where linked I could input the values in any of them to pass to the variable. However, it is not what happens: below, only the values I set in the Slider updates the function (in other words, typing a value in the widget doesn't update the output). Why doesn't jslink work? In this link I found that substituting ipw.jslink for traitlets.linkworks fine.
import ipywidgets as ipw
from IPython.display import display
def f(x):
return x**2
a=ipw.IntSlider(min=-10,max=20,step=1,value=10)
b=ipw.IntText(min=-10,max=20,step=1,value=10)
ipw.jslink((a,'value'),(b,'value'))
wid=ipw.interactive(f, x=a)
display(wid,b)
If the issue is the Python objects not updating on the backend, it is probably because you are using jslink instead of link [ref]. Otherwise, I think this is an old issue with a previous version. I recreated with captured output and both the slider and Text call the function f(x):
from IPython.display import display
output = ipw.Output()
#output.capture()
def f(x):
print(x**2)
return x**2
a=ipw.IntSlider(min=-10,max=20,step=1,value=10)
b=ipw.IntText(min=-10,max=20,step=1,value=10)
ipw.jslink((a,'value'),(b,'value'))
wid=ipw.interactive(f, x=a)
display(wid,b)
display(output)
I'm wondering if it's possible to clear the widget area of a cell in a Jupyter notebook from the notebook side (ie within Python). IPython.display.clear_output() only clears the cell's output area not the widget area.
Update: this still seems to be a problem in latest Notebook and ipywidgets. Here are two minimal examples illustrating the problem I'm struggling with. The widget output that I'm trying to clear in particular are the data frames rendered by qgrid. In both cases, despite trying to clear the previous widget output, subsequent selections cause a table to be appended after the previous one. Each new table is appended as a div with the class p-Widget.
import pandas as pd
import numpy as np
import qgrid
from ipywidgets import interact
from IPython.display import display, clear_output
import notebook
import ipywidgets
print('Jupyter Notebook version: {}'.format(notebook.__version__))
print('ipywidgets version: {}'.format(ipywidgets.__version__))
max_columns = 10
max_rows = 10
col_opts = list(range(1, max_columns + 1))
row_opts = list(range(1, max_rows + 1))
First attempt using interact:
#interact(columns=col_opts, rows=row_opts)
def submit(columns, rows):
df = pd.DataFrame(np.random.randint(0, 100, size=(rows, columns)))
clear_output()
display(qgrid.QGridWidget(df=df)
Second attempt using the Output widget:
output = ipywidgets.Output()
display(output)
def submit2(change):
rows = row_input.value
columns = col_input.value
df = pd.DataFrame(np.random.randint(0, 100, size=(rows, columns)))
with output:
output.clear_output()
display(qgrid.QGridWidget(df=df))
col_input = ipywidgets.Dropdown(options=col_opts)
row_input = ipywidgets.Dropdown(options=row_opts)
col_input.observe(submit2, 'value')
row_input.observe(submit2, 'value')
display(col_input)
display(row_input)
From ipywidgets version 7.0 onwards, widgets are considered like any other output. To prevent the widgets from clearing(but clearing the text output) when you do clear_output(), use the Output widget.
Something like this :
from IPython.display import display, clear_output
import ipywidgets as widgets
import random
b = widgets.Button(
description='Show Random',
disabled=False,
button_style='info',
tooltip='Click me',
icon='check'
)
display(b)
out = widgets.Output()
display(out)
def on_button_clicked(b):
with out:
clear_output()
print("New hello from each button click!. This hello from {}.".format(random.choice(list(range(100)))))
b.on_click(on_button_clicked)
It is! It's IPython.display.clear_output():
from IPython.display import clear_output
for i in range(10):
clear_output()
print(i)
http://ipython.org/ipython-doc/dev/api/generated/IPython.display.html#IPython.display.clear_output
UPDATE:
from IPython.display import clear_output
from ipywidgets import widgets
widgets.IntSlider(1)
clear_output()
# Note that `clear_output` will not clear widgets displayed using `display(widgets.IntSlider(1))`
widgets.IntSlider(100)
From Jupyter notebook you can clear all the info (text and widgets) doing "Cell/Current Outputs/Clear".
If you want to do it programatically you have to do a clear_output() in order to clear text and w.close() (being w a widget) in every widget you created. More info here ("Closing widgets"):
http://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Basics.html
In your example (in your second attempt at least), yo need to add:
col_input.close()
row_input.close()
I have tested it with these versions:
Jupyter Notebook version: 5.0.0
ipywidgets version: 6.0.0
Since ipywidgets 7.0 the widgets are rendered in the same way as any other output. As a consequence clear_output() will clear all the output of cell including widgets.
Widgets are now displayed in the output area in the classic notebook and are treated as any other output. This allows the widgets to work more naturally with other cell output. To delete a widget, clear the output from the cell. Output from functions triggered by a widget view is appended to the output area that contains the widget view. This means that printed text will be appended to the output, and calling clear_output() will delete the entire output, including the widget view. (#1274, #1353)
Source: ipywidgets changelog
I am trying to make interactive sliders with ipywidgets on jupyter notebook to change the data of a plot when a user changes a slider Widget, which is simple and we can find example codes easily. The problem that I have is twofold: 1) when there are many parameters (= variables,sliders) in my function to be displayed, sliders are vertically arranged so that it is getting hard to control them without scrolling the jupyter page. Is there any way to arrange sliders as I wish like m by n grid? 2) To pass a large number of integer-/float-valued sliders, I made a single dictionary to be passed to the function interactive. Here, the key (=slider/variable/parameter) names are displayed seemingly in random order. I tried to pass the dictionary after sorting by the key names beforehand, but it does not still resolve the issue.
I'd appreciate it if you can share any ideas.
def myfun(**var_dict):
v = [value for value in var_dict.values()]
return np.sum(v)
var_dict = {'var1':1,'var2':2,'var3':3,'var4':4}
w = interactive(myfun,**var_dict)
display(w)
ipywidgets interactive sliders
You will not be able to solve this using **kwargs. As stated in PEP468
"The only reason they [keyword arguments] don't work is because the interpreter throws that ordering information away."
"Starting in version 3.5 Python will preserve the order of keyword arguments as passed to a function"
So if you want to get this behavior you should either:
name your arguments when you use 'interactive':
from ipywidgets import interactive
from IPython.display import display
import numpy as np
def myfun(**kwargs):
return np.sum(list(kwargs.itervalues()))
w=interactive(myfun,var1=1,var2=2,var3=3,var4=4)
display(w)
or, if you really want to use a dict, as far as I know, the best is to build the widgets yourself, without the use of 'interactive'.
You could do this this way:
from IPython.display import display,clear_output
from ipywidgets import widgets
from collections import OrderedDict
var_dict = OrderedDict([('var1',1),('var2',2),('var3',3),('var4',4)])
def myfct(change,list_widgets):
clear_output()
print np.sum([widget.value for widget in list_widgets])
list_widgets=[]
# create the widgets
for name,value in var_dict.iteritems():
list_widgets.append(widgets.IntSlider(value=value,min=value-2,max=value+2,description=name))
# link the widgets with the function
for widget in list_widgets:
widget.observe(lambda change:myfct(change,list_widgets),names='value',type='change')
# group the widgets into a FlexBox
w = widgets.VBox(children=list_widgets)
# display the widgets
display(w)
Enjoy :-)