class Aggregate(DataOperator): dimensions = List(ColumnLabel) stat = Instance(Stat, default=Count()) agg_column = String() def __init__(self, **properties): stat = properties.pop('stat') if stat is not None and isinstance(stat, str): properties['stat'] = stats[stat]() col = properties.pop('columns') if col is not None: properties['columns'] = [col] super(Aggregate, self).__init__(**properties) def apply(self, data): data_copy = copy(data) if self.columns is None: self.stat = stats['count']() stat = self.stat agg_name = '' if self.columns is not None: agg_name += self.columns[0] + '_' agg_name += self.stat.__class__.__name__ self.agg_column = agg_name if self.columns is None: col = data_copy.columns[0] else: col = self.columns[0] # Add agg value to each row of group def stat_func(group): stat.set_data(group[col]) group[agg_name] = stat.value return group # create groupby gb = data_copy.groupby(self.dimensions) # apply stat function to groups agg = gb.apply(stat_func) return agg
class PointGlyph(XyGlyph): """A set of glyphs placed in x,y coordinates with the same attributes.""" fill_color = Override(default=DEFAULT_PALETTE[1]) fill_alpha = Override(default=0.7) marker = String(default='circle') size = Float(default=8) def __init__(self, x=None, y=None, color=None, line_color=None, fill_color=None, marker=None, size=None, **kwargs): kwargs['x'] = x kwargs['y'] = y if marker is not None: kwargs['marker'] = marker if size is not None: kwargs['size'] = size if color: line_color = color fill_color = color kwargs['line_color'] = line_color kwargs['fill_color'] = fill_color super(PointGlyph, self).__init__(**kwargs) self.setup() def get_glyph(self): return marker_types[self.marker] def build_renderers(self): glyph_type = self.get_glyph() glyph = glyph_type(x='x_values', y='y_values', line_color=self.line_color, fill_color=self.fill_color, size=self.size, fill_alpha=self.fill_alpha, line_alpha=self.line_alpha) yield GlyphRenderer(glyph=glyph)
class HistogramCDS(ColumnarDataSource): __implementation__ = "HistogramCDS.ts" # Below are all the "properties" for this model. Bokeh properties are # class attributes that define the fields (and their types) that can be # communicated automatically between Python and the browser. Properties # also support type validation. More information about properties in # can be found here: # # https://docs.bokeh.org/en/latest/docs/reference/core/properties.html#bokeh-core-properties source = Instance(ColumnarDataSource) view = List(Int) sample = String weights = String(default=None) nbins = Int range = List(Float) print("x", __implementation__)
class DisabledSelect(InputWidget): ''' Single-select widget. ''' __js_implementation__ = 'disabled_select.ts' options = List(Either(String, Tuple(String, Bool)), help=""" Available selection options. Options may be provided either as a list of possible string values, or as a list of tuples, each of the form ``(value, disabled)``. """) value = String(default="", help=""" Initial or selected value. """) callback = Instance(Callback, help=""" A callback to run in the browser whenever the current Select dropdown value changes. """)
class VTKPlot(HTMLBox): """ A Bokeh model that wraps around a vtk-js library and renders it inside a Bokeh plot. """ __javascript__ = [vtk_cdn] __js_skip__ = {'vtk': [vtk_cdn]} __js_require__ = { "paths": { "vtk": vtk_cdn[:-3] }, "exports": { "vtk": None }, "shim": { "vtk": { "exports": "vtk" } } } append = Bool(default=False) data = String(help="""The serialized vtk.js data""") camera = Dict(String, Any) axes = Instance(VTKAxes) enable_keybindings = Bool(default=False) orientation_widget = Bool(default=False) renderer_el = Any(readonly=True) height = Override(default=300) width = Override(default=300)
class SingleSelect(InputWidget): ''' Single-select widget. ''' options = List(Either(String, Tuple(String, String)), help=""" Available selection options. Options may be provided either as a list of possible string values, or as a list of tuples, each of the form ``(value, label)``. In the latter case, the visible widget text for each value will be corresponding given label. """) value = String(help="Initial or selected value.") size = Int(default=4, help=""" The number of visible options in the dropdown list. (This uses the ``select`` HTML element's ``size`` attribute. Some browsers might not show less than 3 options.) """)
class PCPMultiSelect(InputWidget): ''' Multi-select widget. ''' searchbox = Bool(default=True) selectall = Bool(default=True) options = List(Either(String, Tuple(String, String)), help=""" Available selection options. Options may be provided either as a list of possible string values, or as a list of tuples, each of the form ``(value, label)``. In the latter case, the visible widget text for each value will be corresponding given label. """) value = List(String, help=""" Initial or selected values. """) theme = String(default="light")
class BoxPlotBuilder(BarBuilder): """Produces Box Glyphs for groups of data. Handles box plot options to produce one to many boxes, which are used to describe the distribution of a variable. """ # ToDo: Support easier adding of one attr without reimplementation default_attributes = { 'label': CatAttr(), 'color': ColorAttr(default='DimGrey'), 'outlier_fill_color': ColorAttr(default='red'), 'outlier_line_color': ColorAttr(default='red'), 'whisker_color': ColorAttr(default='black'), 'line_color': ColorAttr(default='black'), 'stack': CatAttr(), 'group': CatAttr() } # TODO: (bev) should be an enumeration marker = String(help=""" The marker type to use (e.g., ``circle``) if outliers=True. """) outliers = Bool(default=True, help=""" Whether to display markers for any outliers. """) glyph = BoxGlyph def setup(self): if self.ylabel is None: self.ylabel = self.values.selected_title if self.xlabel is None: self.xlabel = title_from_columns(self.attributes['label'].columns)
class VTKPlot(HTMLBox): """ A Bokeh model that wraps around a vtk-js library and renders it inside a Bokeh plot. """ __javascript__ = [vtk_cdn] __js_require__ = {"paths": {"vtk": vtk_cdn[:-3]}, "shim": {"vtk": {"exports": "vtk"}}} __implementation__ = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'vtk.ts') append = Bool(default=False) data = String(help="""The serialized vtk.js data""") camera = Dict(String, Any) enable_keybindings = Bool(default=False) height = Override(default=300) width = Override(default=300)
class IncludeDefaultsKwargsTest(HasProps): x = Int(12) y = String("hello")
class Readonly(HasProps): x = Int(12, readonly=True) # with default y = Nullable(Int(), readonly=True) # without default z = String("hello")
class NotSerialized(HasProps): x = Int(12, serialized=False) y = String("hello")
class SomeModel(Model): a = Int(12) b = String("hello") c = List(Int, [1, 2, 3])
class BinGlyph(XyGlyph): """Represents a group of data that was aggregated and is represented by a glyph. """ bins = Instance(Bins) column = String() stat = String() glyph_name = String() width = Float() height = Float() def __init__(self, x, y, values, column=None, stat='count', glyph='rect', width=1, height=1, **kwargs): df = pd.DataFrame(dict(x_vals=x, y_vals=y, values_vals=values)) df.drop_duplicates(inplace=True) kwargs['x'] = df.x_vals kwargs['y'] = df.y_vals kwargs['values'] = df.values_vals kwargs['column'] = column kwargs['stat'] = stat kwargs['glyph_name'] = glyph kwargs['height'] = height kwargs['width'] = width if 'glyphs' not in kwargs: kwargs['glyphs'] = {'rect': Rect} super(XyGlyph, self).__init__(**kwargs) self.setup() def build_source(self): return {'x': self.x, 'y': self.y, 'values': self.values} def build_renderers(self): glyph_class = self.glyphs[self.glyph_name] glyph = glyph_class(x='x', y='y', height=self.height, width=self.width, fill_color=self.fill_color, line_color=self.line_color, dilate=True) yield GlyphRenderer(glyph=glyph) @property def x_max(self): return self.get_data_range('x')[1] + self.width / 2.0 @property def x_min(self): return self.get_data_range('x')[0] - self.width / 2.0 @property def y_max(self): return self.get_data_range('y')[1] + self.height / 2.0 @property def y_min(self): return self.get_data_range('y')[0] - self.height / 2.0 def get_data_range(self, col): data = self.source.data[col] if ChartDataSource.is_number(data): return min(data), max(data) else: return 1, len(data.drop_duplicates())
class Foo(HasProps): x = Int(12) y = String("hello") z = List(Int, [1, 2, 3]) zz = Dict(String, Int) s = Nullable(String(None))
class IncludeDefaultsSetToSameTest(HasProps): x = Int(12) y = String("hello")
class AcePlot(HTMLBox): """ A Bokeh model that wraps around a Ace editor and renders it inside a Bokeh plot. """ __javascript_raw__ = [ 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ace.js', 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-language_tools.js', 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-modelist.js' ] __tarball__ = { 'tar': 'https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.11.tgz', 'src': 'package/src-min/', 'dest': 'ajax/libs/1.4.11', 'exclude': ['snippets'] } @classproperty def __javascript__(cls): return bundled_files(cls) @classproperty def __js_skip__(cls): return {'ace': cls.__javascript__} __js_require__ = { 'paths': { ('ace', ('ace/ace', 'ace/ext-language_tools')): '//cdnjs.cloudflare.com/ajax/libs/ace/1.4.7' }, 'exports': { 'ace': 'ace' }, 'shim': { 'ace/ext-language_tools': { 'deps': ["ace/ace"] }, 'ace/ext-modelist': { 'deps': ["ace/ace"] } } } code = String() theme = Enum(ace_themes, default='chrome') filename = String() language = String() annotations = List(Dict(String, Any), default=[]) readonly = Bool(default=False) print_margin = Bool(default=False) height = Override(default=300) width = Override(default=300)
def test_String(self, detail): p = String() with pytest.raises(ValueError) as e: p.validate(10, detail) assert str(e).endswith("ValueError") == (not detail)
def test_String(self): p = String() with pytest.raises(ValueError) as e: p.validate(10) assert not str(e).endswith("ValueError")
class HP(HasProps): foo = Int(default=10) bar = String()
class FooUnrelated(HasProps): x = Int(12) y = String("hello") z = List(Int, [1, 2, 3])
class VTKVolumePlot(HTMLBox): """ A Bokeh model that wraps around a vtk-js library and renders it inside a Bokeh plot. """ __javascript__ = [vtk_cdn] __js_skip__ = {'vtk': [vtk_cdn]} __js_require__ = { "paths": { "vtk": vtk_cdn[:-3] }, "exports": { "vtk": None }, "shim": { "vtk": { "exports": "vtk" } } } data = Dict(String, Any) colormap = String(help="Colormap Name") rescale = Bool(default=False) shadow = Bool(default=True) sampling = Float(default=0.4) edge_gradient = Float(default=0.2) ambient = Float(default=0.2) diffuse = Float(default=0.7) specular = Float(default=0.3) specular_power = Float(default=8.) slice_i = Int(default=0) slice_j = Int(default=0) slice_k = Int(default=0) display_volume = Bool(default=True) display_slices = Bool(default=False) render_background = String(default='#52576e') interpolation = Enum(enumeration('fast_linear', 'linear', 'nearest')) height = Override(default=300) width = Override(default=300)
class FunctionPlotter(Figure): __view_model__ = "Plot" #__subtype__ = "FunctionPlotter" __subtype__ = "FunctionPlotter" # needs to be in bokeh.plotting source = Instance(ColumnDataSource) function = String(default="") start = Float(default=10) end = Float(default=-10) points = Int(default=1000) def __init__(self, **kwargs): super(self.__class__, self).__init__(**kwargs) self.source = ColumnDataSource(data={'x':[],'y':[]}) self.update() #self.__class__ = Figure #self.line(x='x',y='y',source=self.source) def change_function(self,function): self.function=function self.update() def change_limits(self,start,end): self.start = float(start) self.end = float(end) self.update() def update(self): if self.function != "": print ("Update to function '{}' from {} to {}.".format(self.function,self.start,self.end)) func = self.__string2func(self.function) x = np.linspace(self.start, self.end, self.points) self.source = ColumnDataSource(data={'x':x,'y':func(x)}) self.line(x='x',y='y',source=self.source) #self.source.data={'x':x,'y':func(x)} else: print("No update, function empty!") def plot(self): return super(self.__class__, self) def __replacements(self): return { 'sin' : 'np.sin', 'cos' : 'np.cos', 'tan' : 'np.tan', 'exp': 'np.exp', 'sqrt': 'np.sqrt', '^': '**', } def __allowed_words(self): return [ 'x', 'sin', 'tan', 'cos', 'sqrt', 'exp', ] def __string2func(self,string): ''' evaluates the string and returns a function of x ''' # find all words and check if all are allowed: for word in re.findall('[a-zA-Z_]+', string): if word not in self.__allowed_words(): raise ValueError( '"{}" is forbidden to use in math expression'.format(word) ) for old, new in self.__replacements().items(): string = string.replace(old, new) def func(x): try: return eval(string) except: print("Evaluation of '{}' did not work.".format(string)) return eval("x") return func
class AggregateGlyph(NestedCompositeGlyph): """A base composite glyph for aggregating an array. Implements default stacking and dodging behavior that other composite glyphs can inherit. """ x_label = String() x_label_value = Any() stack_label = String() stack_shift = Float(default=0.0) dodge_label = String( help="""Where on the scale the glyph should be placed.""") dodge_shift = Float(default=None) agg = Instance(Stat, default=Sum()) span = Float(help="""The range of values represented by the aggregate.""") def __init__(self, x_label=None, **kwargs): label = kwargs.get('label') if x_label is not None: kwargs['x_label_value'] = x_label if not isinstance(x_label, str): x_label = str(x_label) kwargs['x_label'] = x_label elif label is not None: kwargs['x_label'] = str(label) super(AggregateGlyph, self).__init__(**kwargs) def get_dodge_label(self, shift=0.0): """Generate the label defining an offset in relation to a position on a scale.""" if self.dodge_shift is None: shift_str = ':' + str(0.5 + shift) elif self.dodge_shift is not None: shift_str = ':' + str(self.dodge_shift + shift) else: shift_str = '' return str(label_from_index_dict(self.x_label)) + shift_str def filter_glyphs(self, glyphs): """Return only the glyphs that are of the same class.""" return [glyph for glyph in glyphs if isinstance(glyph, self.__class__)] @staticmethod def groupby(glyphs, prop): """Returns a dict of `CompositeGlyph`s, grouped by unique values of prop. For example, if all glyphs had a value of 'a' or 'b' for glyph.prop, the dict would contain two keys, 'a' and 'b', where each value is a list of the glyphs that had each of the values. """ grouped = defaultdict(list) labels = [getattr(glyph, prop) for glyph in glyphs] labels = [ tuple(label.values()) if isinstance(label, dict) else label for label in labels ] [grouped[label].append(glyph) for label, glyph in zip(labels, glyphs)] labels = pd.Series(labels).drop_duplicates().values return labels, grouped def __stack__(self, glyphs): """Apply relative shifts to the composite glyphs for stacking.""" filtered_glyphs = self.filter_glyphs(glyphs) labels, grouped = self.groupby(filtered_glyphs, 'x_label') for label in labels: group = grouped[label] # separate the negative and positive aggregates into separate groups neg_group = [glyph for glyph in group if glyph.span < 0] pos_group = [glyph for glyph in group if glyph.span >= 0] # apply stacking to each group separately for group in [neg_group, pos_group]: shift = [] for i, glyph in enumerate(group): # save off the top of each rect's height shift.append(glyph.span) if i > 0: glyph.stack_shift = sum(shift[0:i]) glyph.refresh() def __dodge__(self, glyphs): """Apply relative shifts to the composite glyphs for dodging.""" if self.dodge_label is not None: filtered_glyphs = self.filter_glyphs(glyphs) labels, grouped = self.groupby(filtered_glyphs, 'dodge_label') # calculate transformations step = np.linspace(0, 1.0, len(grouped.keys()) + 1, endpoint=False) width = min(0.2, (1. / len(grouped.keys()))**1.1) # set bar attributes and re-aggregate for i, label in enumerate(labels): group = grouped[label] for glyph in group: glyph.dodge_shift = step[i + 1] glyph.width = width glyph.refresh()
class ModelThatOverridesName(Model): name = String()
class ThemedModel(Model): number = Int(42) string = String("hello")
class BoxGlyph(AggregateGlyph): """Summarizes the distribution with a collection of glyphs. A box glyph produces one "box" for a given array of vales. The box is made up of multiple other child composite glyphs (intervals, scatter) and directly produces glyph renderers for the whiskers, as well. """ q1 = Float(help="""Derived value for 25% of all values.""") q2 = Float(help="""Derived value for 50% of all values.""") q3 = Float(help="""Derived value for 75% of all values.""") iqr = Float() w0 = Float(help='Lower whisker') w1 = Float(help='Upper whisker') q2_glyph = Instance(QuartileGlyph) q3_glyph = Instance(QuartileGlyph) whisker_glyph = Instance(GlyphRenderer) outliers = Either(Bool, Instance(PointGlyph)) marker = String(default='circle') whisker_width = Float(default=0.3) whisker_line_width = Float(default=2) whisker_span_line_width = Float(default=2) whisker_color = String(default='black') outlier_fill_color = String(default='red') outlier_line_color = String(default='red') outlier_size = Float(default=5) bar_color = String(default='DimGrey') def __init__(self, label, values, outliers=True, **kwargs): width = kwargs.pop('width', None) bar_color = kwargs.pop('color', None) or kwargs.get( 'bar_color') or self.lookup('bar_color').class_default() kwargs['outliers'] = kwargs.pop('outliers', None) or outliers kwargs['label'] = label kwargs['values'] = values x_label = kwargs.get('x_label') kwargs['q2_glyph'] = QuartileGlyph(label=label, x_label=x_label, values=values, interval1=0.25, interval2=0.5, width=width, color=bar_color) kwargs['q3_glyph'] = QuartileGlyph(label=label, x_label=x_label, values=values, interval1=0.5, interval2=0.75, width=width, color=bar_color) super(BoxGlyph, self).__init__(**kwargs) self.setup() def build_renderers(self): """Yields all renderers that make up the BoxGlyph.""" self.calc_quartiles() outlier_values = self.values[((self.values < self.w0) | (self.values > self.w1))] self.whisker_glyph = GlyphRenderer( glyph=Segment(x0='x0s', y0='y0s', x1='x1s', y1='y1s', line_width=self.whisker_line_width, line_color=self.whisker_color)) if len(outlier_values) > 0 and self.outliers: self.outliers = PointGlyph(label=self.label, y=outlier_values, x=[self.get_dodge_label()] * len(outlier_values), line_color=self.outlier_line_color, fill_color=self.outlier_fill_color, size=self.outlier_size, marker=self.marker) for comp_glyph in self.composite_glyphs: for renderer in comp_glyph.renderers: yield renderer yield self.whisker_glyph def calc_quartiles(self): """Sets all derived stat properties of the BoxGlyph.""" self.q1 = self.q2_glyph.start self.q2 = self.q2_glyph.end self.q3 = self.q3_glyph.end self.iqr = self.q3 - self.q1 mx = Max() mx.set_data(self.values) mn = Min() mn.set_data(self.values) self.w0 = max(self.q1 - (1.5 * self.iqr), mn.value) self.w1 = min(self.q3 + (1.5 * self.iqr), mx.value) def build_source(self): """Calculate stats and builds and returns source for whiskers.""" self.calc_quartiles() x_label = self.get_dodge_label() x_w0_label = self.get_dodge_label(shift=(self.whisker_width / 2.0)) x_w1_label = self.get_dodge_label(shift=-(self.whisker_width / 2.0)) # span0, whisker bar0, span1, whisker bar1 x0s = [x_label, x_w0_label, x_label, x_w0_label] y0s = [self.w0, self.w0, self.q3, self.w1] x1s = [x_label, x_w1_label, x_label, x_w1_label] y1s = [self.q1, self.w0, self.w1, self.w1] return dict(x0s=x0s, y0s=y0s, x1s=x1s, y1s=y1s) def _set_sources(self): """Set the column data source on the whisker glyphs.""" self.whisker_glyph.data_source = self.source def get_extent(self, func, prop_name): return func([ getattr(renderer, prop_name) for renderer in self.composite_glyphs ]) @property def composite_glyphs(self): """Returns list of composite glyphs, excluding the regular glyph renderers.""" comp_glyphs = [self.q2_glyph, self.q3_glyph] if isinstance(self.outliers, PointGlyph): comp_glyphs.append(self.outliers) return comp_glyphs @property def x_max(self): return self.get_extent(max, 'x_max') + self.right_buffer @property def x_min(self): return self.get_extent(min, 'x_min') - self.left_buffer @property def y_max(self): return max(self.w1, self.get_extent(max, 'y_max')) + self.top_buffer @property def y_min(self): return min(self.w0, self.get_extent(min, 'y_min')) - self.bottom_buffer
class SomeModelToJson(Model): child = Instance(Model) foo = Int() bar = String()
class SubOfThemedModel(ThemedModel): another_string = String("world")
class Base(HasProps): x = Int(12) y = String("hello")
class EmbedTestUtilModel(Model): a = Int(12) b = String("hello") c = List(Int, [1, 2, 3])
class Foo(HasProps): x = Int(12) y = Enum("red", "blue", "green") z = String("blah")