Last active
May 14, 2019 14:19
-
-
Save martindurant/bf03efd1979e308014adb1be0af9f355 to your computer and use it in GitHub Desktop.
panel funs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
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.
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.
cc @philippjfr
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.
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
@jsignell , I thought you might enjoy this - more old-style bad GUI programming from me!