Skip to content

Instantly share code, notes, and snippets.

@martindurant
Last active May 14, 2019 14:19
Show Gist options
  • Save martindurant/bf03efd1979e308014adb1be0af9f355 to your computer and use it in GitHub Desktop.
Save martindurant/bf03efd1979e308014adb1be0af9f355 to your computer and use it in GitHub Desktop.
panel funs
import inspect
import panel
import hvplot.pandas
from hvplot import hvPlot
from hvplot.converter import HoloViewsConverter
plot_types = list(_ for _ in dir(hvPlot) if not _.startswith('_'))
plots_needs = {
k: set(inspect.signature(getattr(hvPlot, k)).parameters) - {'self', 'kwds'}
for k in plot_types
}
fields = ['x', 'y', 'z', 'text', 'bands', 'by', 'C']
others = {'colorbar': bool, 'stacked': bool, 'where': ['pre', 'mid', 'post'],
'columns': 'columns'}
class FieldSelectors(object):
def __init__(self, df):
self.df = df
self.fields = list(df.columns)
self.plot_type = panel.widgets.Select(
name='Plot Type', options=plot_types)
self.fieldset = panel.layout.Column(background=(200, 200, 200))
self.opts = panel.layout.Column()
self.widget = panel.layout.Column(
self.plot_type, self.fieldset, self.opts,
background=(230, 230, 230)
)
self.outer = panel.layout.Row(self.widget, panel.layout.Row())
self.refresh()
self.plot_type.param.watch(self.refresh, 'value', onlychanged=True)
def refresh(self, *args):
args = self.args # current values
needs = plots_needs[self.plot_type.value]
self.fieldset.clear()
for field in fields:
if field in needs:
if len(self.fieldset) == 0:
self.fieldset.append(panel.widgets.StaticText(value='Fields'))
s = panel.widgets.Select(options=self.fields, name=field,
value=args.get(field, None))
self.fieldset.append(s)
s.param.watch(self.draw, 'value', onlychanged=True)
self.opts.clear()
for field in others:
if field in needs:
if len(self.opts) == 0:
self.opts.append(panel.widgets.StaticText(value='Options'))
if others.get(field, None) is bool:
s = panel.widgets.Checkbox(name=field)
elif isinstance(others.get(field, None), list):
s = panel.widgets.Select(name=field, options=others[field])
elif field == 'columns':
s = panel.widgets.MultiSelect(name=field, value=self.fields,
options=self.fields)
if field in args:
s.value = args[field]
self.opts.append(s)
s.param.watch(self.draw, 'value', onlychanged=True)
self.draw()
@property
def args(self):
args = {'kind': self.plot_type.value}
for s in self.fieldset[1:]:
args[s.name] = s.value
for s in self.opts[1:]:
args[s.name] = s.value
return args
def draw(self, *args):
# TODO: presumably only some changes need a complete redraw
plot = self.df.hvplot(**self.args)
self.outer[1] = panel.pane.HoloViews(plot)
if __name__ == '__main__':
import pandas as pd
import numpy as np
df = pd.DataFrame({
'a': range(100),
'b': np.random.rand(100),
'c': np.random.randn(100),
'd': np.random.choice(['A', 'B', 'C'], size=100)
})
widget = FieldSelectors(df)
widget.outer.show()
@martindurant
Copy link
Author

@jsignell , I thought you might enjoy this - more old-style bad GUI programming from me!

@jsignell
Copy link

Oh I do like this! Seems like a pretty good solution to me. Hvplot just need to be a little more specific about what options are allowed on which kinds of plots.

@martindurant
Copy link
Author

Yep, I just took the specs from the hvPlot method definitions; but I see that HoloViewsConverter actually has a pretty concrete definition of what goes where, as class attributes.

@martindurant
Copy link
Author

@philippjfr
Copy link

This looks like a great start, definitely further than I had gotten on this. I think hvPlot should work on exposing the plot definitions and valid values in some easily consumable format to make this kind of thing easier.

@martindurant
Copy link
Author

I'll continue to develop this in a more rigorous manner at https://github.com/martindurant/dfviz/blob/master/dfviz/widget.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment