5

When creating a plot (QuadMesh) with HoloViews based on xArray data, any missing dimensions will automatically create widgets such as sliders to facilitate data exploration. For example:

hv_ds = hv.Dataset(data)    
plot = hv_ds.to(hv.QuadMesh, kdims=["lon", "lat"], vdims="depth")

Since data contains 12-months worth of data, HoloViews will create the QuadMesh based on lon & lat, using the depth as the value, then providing a slider widget to select the month. It will wrap it all up in a HoloMap that looks like this:

HoloMap containing 12 items of type QuadMesh
--------------------------------------------

Key Dimensions: 
     month: 1.0...12.0 
Deep Dimensions: 
     lon: -280.0...80.0 
     lat: -78.0...-44.6 
     depth: 3.5...4796.6 

Plot generated

I want to retrieve the value of the "month slider widget" to update another plot, but I can't find a way to access it. There's no plot.get_widget_value() or anything like it. Any ideas how I could get a pointer or a handler of it?

Sander van den Oord
  • 10,986
  • 5
  • 51
  • 96

2 Answers2

1

I don't know how to get the current value when you create a widget + plot like that. Maybe someone else knows.

But I do know how to get the current selected value when you create your widget + plot using panel like the example below. If you do it like this can you just use your_selection_widget.value to get the current selected value:

# import libraries
import numpy as np
import pandas as pd

import hvplot
import hvplot.pandas

import holoviews as hv
hv.extension('bokeh', logo=False)

import panel as pn


# create sample data
df = pd.DataFrame({
    'col1': np.random.rand(30),
    'col2': np.random.normal(size=30),
    'category_col': np.random.choice(['category1', 'category2'], size=30)
})

# create widget to select category
category = pn.widgets.Select(options=['category1', 'category2'])

# function that returns a plot depending on the category selected
@pn.depends(category)
def get_plot(category):
    df_selected = df[df['category_col'] == category]
    plot = df_selected.hvplot.scatter(x='col1', y='col2')
    return plot

# show dashboard with selection widget and dynamic plot
pn.Column(
    pn.Row(category),
    get_plot,
)

# get value of current selected category
category.value

You can find more info on how to create an interactive dashboard like this here:
https://panel.pyviz.org/gallery/apis/stocks_hvplot.html#gallery-stocks-hvplot

Sander van den Oord
  • 10,986
  • 5
  • 51
  • 96
  • Thanks Sander, that'll be very helpful when I create my own dashboards and can control the creation of the widget. My problem is still when the widget is "magically" created for me... – user12444217 Nov 27 '19 at 23:26
  • @Sander, I copied what you have done here but from some reason it doesn't update the plot when a different category is selected, would you know what is going on here? – Amen_90 Oct 12 '20 at 16:24
1

[ages later... posting in case of value for anyone else]

Here's one way that works, yet I imagine there are easier ones...

## imports
import pandas as pd
import numpy as np
import xarray as xr

import hvplot.xarray
import panel as pn

## generate an xr.DataArray
start_date = '2021-01-01'
time = pd.date_range(start=start_date, periods=12, freq='M')
x,y = np.ogrid[0:512, 0:512]
data = np.random.randn(time.size, x.size, y.size)
coords = dict(time=time, x=x.ravel(), y=y.ravel())
space_time_xr = xr.DataArray(data, coords=coords, dims=list(coords), name='space_time')

Option A : hvPlot --> Panel

## use hvplot to implicitly generate the widget -- there's an alternative 
space_time_hv = space_time_xr.hvplot(x='x', y='y')

## use panel to access the slider
space_time_pn = pn.panel(space_time_hv)

## a pointer to the slider widget
time_slider_pnw = space_time_pn[1][0][0]

## present the viz+widget
space_time_pn

Option A screenshot

Option B : using the .interactive API

requires hvplot version >= 0.7

## use .interactive API to generate the widget
space_time_pnw = space_time_xr.interactive.sel(time=pn.widgets.DiscreteSlider).hvplot()

## a pointer to the slider widget
time_slider_pnw = space_time_pnw.widgets().objects[0]

## present the viz+widget
space_time_pnw

Play with the slider... Then can read out the current value of the slider:

## get slider current value
current_pnw_value = time_slider_pnw.value

## print the value
print(f'{current_pnw_value}')

For a "live" update as the widget state is being changed, can check, for example panel #Links

(Option C) .interactive + link example : title is updated following the widget state

## use interactive API to generate the widget
time_slider_pnw = pn.widgets.DiscreteSlider(name='time',options=space_time_xr.time.to_series().to_dict())
space_time_pn = space_time_xr.interactive.sel(time=time_slider_pnw).hvplot()

## dynamics markdown
time_md = pn.pane.Markdown(f'## {time_slider_pnw.value:%Y-%m-%d}')

def callback(target, event):
    target.object = f'## {event.new:%Y-%m-%d}'
    
## link
time_slider_pnw.link(time_md, callbacks={'value' : callback} )

## present the time slider value
pn.Column(time_md, space_time_pn.panel(), space_time_pn.widgets())

Option C .interactive + link screenshot

Using versions:

Python version       : 3.7.10

numpy : 1.20.2
xarray: 0.18.0
pandas: 1.2.4

hvplot    : 0.7.1
panel     : 0.11.3
holoviews : 1.14.3
bokeh     : 2.3.1
jupyterlab: 3.0.14
eldad-a
  • 3,051
  • 3
  • 22
  • 25