Last active
July 27, 2017 01:40
-
-
Save rothnic/1f40945a6cf2816530b6 to your computer and use it in GitHub Desktop.
Modeling chart properties
This file contains 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
from bokeh.properties import HasProps, List, String, Either, Instance, Bool | |
from bokeh.models.widgets import Select, Widget, Toggle | |
import pandas as pd | |
from blaze.interactive import InteractiveSymbol, Data | |
from odo import odo | |
from bokeh.io import vform | |
from bokeh.plotting import output_file, show | |
from bokeh.plotting import figure, Figure | |
class Constraint(HasProps): | |
name = String | |
IS_NOT_CONSTANT = Constraint(name='IS_NOT_CONSTANT') | |
IS_LOGICAL = Constraint(name='IS_LOGICAL') | |
# Models | |
class Column(HasProps): | |
"""A column option used to model input to Charts.""" | |
name = String | |
alt_names = List(String) | |
valid_types = List(Instance(Constraint)) | |
widget = Instance(Widget, default=Select()) | |
selection = String | |
type = String | |
class BoolOption(HasProps): | |
name = String | |
widget = Instance(Widget, default=Toggle()) | |
def __nonzero__(self): | |
if self.widget: | |
return True | |
else: | |
return False | |
class DataResource(HasProps): | |
"""Model for a blaze data source.""" | |
source = String | |
#tables = List | |
#columns = List | |
#symbol = Any | |
def __init__(self, **properties): | |
source = properties.get('source') | |
if isinstance(source, str): | |
#properties['symbol'] = Data(source) | |
pass | |
elif isinstance(source, pd.DataFrame): | |
#properties['symbol'] = Data(source) | |
properties['source'] = 'DataFrame' | |
super(DataResource, self).__init__(**properties) | |
@property | |
def df(self): | |
return odo(self.symbol, pd.DataFrame) | |
class Chart(Widget): | |
"""A generic plot for table-like data.""" | |
data = Instance(DataResource) | |
options = List(Either(Instance(Column), Bool)) | |
fig = Instance(Figure) | |
def __init__(self, **properties): | |
properties['data'] = DataResource(source=properties.get('data')) | |
super(Chart, self).__init__(**properties) | |
for option in self.options: | |
option.widget.on_change('value', self, 'plot') | |
def plot(self): | |
raise NotImplementedError | |
# My Unique Chart | |
class MyChart(Chart): | |
x = Column(name='x', valid_types=[IS_NOT_CONSTANT]) | |
y = Column(name='x', valid_types=[IS_NOT_CONSTANT]) | |
flip = BoolOption(name='flip') | |
options = [x, y, flip] | |
def plot(self): | |
if self.flip: | |
self.fig = figure(plot_width=400, plot_height=400) | |
self.fig.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5) | |
return self.fig | |
else: | |
self.fig = figure(plot_width=400, plot_height=400) | |
self.fig.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="green", alpha=0.5) | |
return self.fig | |
def interact(chart): | |
output_file("test.html") | |
widgets = [] | |
for option in chart.options: | |
widgets.append(option.widget) | |
widgets.append(chart.plot()) | |
show(vform(*widgets)) | |
if __name__ == '__main__': | |
df = pd.DataFrame(dict(x=[1,2,3], y=[2,3,4])) | |
c = MyChart() | |
print c.properties_with_values() | |
print MyChart.options | |
# DataResource takes anything blaze takes | |
dr = DataResource(source=df) | |
print dr.properties_with_values() | |
dr = DataResource(source='sqlite:///C:\Users\Nick\Downloads\lahman2013.sqlite') | |
print dr.properties_with_values() | |
# create special chart | |
c = MyChart(data='sqlite:///C:\Users\Nick\Downloads\lahman2013.sqlite') | |
print c.properties_with_values() | |
# end goal is interactive chart with simple command | |
interact(c) |
Output of this script looks something like this:
{'data': <__main__.DataResource object at 0x000000001718F208>, 'options': [<__main__.Column object at 0x000000001718F080>, <__main__.BoolOption object at 0x000000001718F0B8>]}
[<__main__.Column object at 0x000000001718F080>, <__main__.BoolOption object at 0x000000001718F0B8>]
{'source': 'DataFrame', 'symbol': x y
0 1 2
1 2 3
2 3 4}
{'source': 'sqlite:///C:\\Users\\Nick\\Downloads\\lahman2013.sqlite', 'symbol': Data: Engine(sqlite:///C:\Users\Nick\Downloads\lahman2013.sqlite)
DataShape: {
AllstarFull: var * {
playerID: ?string,
yearID: ?int32,
gameNum: ?int32,
gameID: ?string,
teamID: ?string,
...}
{'data': <__main__.DataResource object at 0x0000000017347B38>, 'options': [<__main__.Column object at 0x000000001718F080>, <__main__.BoolOption object at 0x000000001718F0B8>]}
Latest update produces the output I'd want to see, just isn't interactive yet (not on server).
This produces the output below, when called by interact(chart)
class MyChart(Chart):
x = Column(name='x', valid_types=[IS_NOT_CONSTANT])
y = Column(name='x', valid_types=[IS_NOT_CONSTANT])
flip = BoolOption(name='flip')
options = [x, y, flip]
def plot(self):
self.fig = figure(plot_width=400, plot_height=400)
self.fig.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
return self.fig
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated to include blaze data model