def test_simple_element(self): # Build Holoviews Elements scatter = Scatter([0, 0]) # Convert to Dash components = to_dash(self.app, [scatter]) # Check returned components self.assertIsInstance(components, DashComponents) self.assertEqual(len(components.graphs), 1) self.assertEqual(len(components.kdims), 0) self.assertIsInstance(components.store, Store) self.assertEqual(len(components.resets), 0) callback_fn = self.app.callback.return_value.call_args[0][0] # Check registered callbacks self.assertEqual(self.app.callback.call_count, 1) self.assertEqual(self.decorator.call_count, 1) store_value = encode_store_data({}) with patch.object(CallbackContext, "triggered", []): [fig, new_store] = callback_fn({}, store_value) # Check figure returned by callback self.assertEqual(len(fig["data"]), 1) self.assertEqual(fig["data"][0]["type"], "scatter")
def test_kdims_dynamic_map(self): # Dynamic map with two key dimensions dmap = DynamicMap(lambda kdim1: Scatter([kdim1, kdim1]), kdims=["kdim1"]).redim.values(kdim1=[1, 2, 3, 4]) # Convert to Dash components = to_dash(self.app, [dmap]) # Check returned components self.assertIsInstance(components, DashComponents) self.assertEqual(len(components.graphs), 1) self.assertEqual(len(components.kdims), 1) self.assertIsInstance(components.store, Store) self.assertEqual(len(components.resets), 0) # Get arguments passed to @app.callback decorator decorator_args = list(self.app.callback.call_args_list[0])[0] outputs, inputs, states = decorator_args # Check outputs expected_outputs = [(g.id, "figure") for g in components.graphs] + \ [(components.store.id, "data")] self.assertEqual([(output.component_id, output.component_property) for output in outputs], expected_outputs) # Check inputs expected_inputs = [ (g.id, prop) for g in components.graphs for prop in ["selectedData", "relayoutData"] ] + [(list(components.kdims.values())[0].children[1].id, 'value')] self.assertEqual( [(ip.component_id, ip.component_property) for ip in inputs], expected_inputs, ) # Check State expected_state = [(components.store.id, "data")] self.assertEqual( [(state.component_id, state.component_property) for state in states], expected_state, ) # Get callback function callback_fn = self.decorator.call_args_list[0][0][0] # mimic initial callback invocation store_value = encode_store_data({"streams": {}}) with patch.object(CallbackContext, "triggered", []): [fig, new_store] = callback_fn({}, {}, 3, None, store_value) # First figure is the scatter trace self.assertEqual(fig["data"][0]["type"], "scatter") self.assertEqual(list(fig["data"][0]["x"]), [0, 1]) self.assertEqual(list(fig["data"][0]["y"]), [3, 3])
def test_simple_element(self): # Build Holoviews Elements scatter = Scatter([0, 0]) # Convert to Dash components = to_dash(self.app, [scatter]) # Check returned components self.assertIsInstance(components, DashComponents) self.assertEqual(len(components.graphs), 1) self.assertEqual(len(components.kdims), 0) self.assertIsInstance(components.store, Store) self.assertEqual(len(components.resets), 0) # Check initial figure fig = components.graphs[0].figure self.assertEqual(len(fig["data"]), 1) self.assertEqual(fig["data"][0]["type"], "scatter")
np.random.multivariate_normal((0, 0), [[1, 0.1], [0.1, 1]], (1000, ))) points2 = hv.Points( np.random.multivariate_normal((3, 3), [[1, 0.1], [0.1, 1]], (1000, ))) # Declare two selection streams and set points and points2 as the source of each sel1 = streams.Selection1D(source=points) sel2 = streams.Selection1D(source=points2) # Declare DynamicMaps to show mean y-value of selection as HLine hline1 = hv.DynamicMap(lambda index: hv.HLine(points['y'][index].mean() if index else -10), streams=[sel1]) hline2 = hv.DynamicMap(lambda index: hv.HLine(points2['y'][index].mean() if index else -10), streams=[sel2]) # Combine points and dynamic HLines layout = (points * points2 * hline1 * hline2).opts( opts.Points(height=400, width=400)) # Create App app = dash.Dash(__name__) # Dash display components = to_dash(app, [layout], reset_button=True) app.layout = html.Div(components.children) if __name__ == '__main__': app.run_server(debug=True)
# Build HoloViews Dataset from large Pandas DataFrame import holoviews as hv from holoviews.plotting.plotly.dash import to_dash dataset = hv.Dataset(df) # Build Datashaded Scatter and Histogram HoloViews Elements, and side-by-side layout from holoviews.operation.datashader import datashade scatter = datashade( hv.Scatter(dataset, kdims=["sepal_length"], vdims=["sepal_width"])) hist = hv.operation.histogram(dataset, dimension="petal_width", normed=False) row = scatter + hist # Link selections across subplots linked_row = hv.selection.link_selections(row) # Set plot title linked_row.opts(title="Datashader with %d points" % len(dataset)) # Build Dash app import dash app = dash.Dash(__name__) components = to_dash(app, [linked_row], reset_button=True) # Build Dash layout import dash_html_components as html app.layout = html.Div(components.children) if __name__ == "__main__": app.run_server(debug=True)
import dash import dash_html_components as html from plotly.data import iris import holoviews as hv from holoviews.plotting.plotly.dash import to_dash from holoviews.operation.datashader import datashade import numpy as np import pandas as pd # Load iris dataset and replicate with noise to create large dataset df_original = iris()[["sepal_length", "sepal_width", "petal_length", "petal_width"]] df = pd.concat([ df_original + np.random.randn(*df_original.shape) * 0.1 for i in range(10000) ]) dataset = hv.Dataset(df) scatter = datashade( hv.Scatter(dataset, kdims=['sepal_length'], vdims=['sepal_width']) ).opts(width=600).opts(title="Datashader with %d points" % len(dataset)) app = dash.Dash(__name__) components = to_dash(app, [scatter], reset_button=True) app.layout = html.Div(components.children) if __name__ == '__main__': app.run_server(debug=True)
# -*- coding: utf-8 -*- import dash import dash_html_components as html from plotly.data import iris import holoviews as hv from holoviews.plotting.plotly.dash import to_dash # Load dataset df = iris() dataset = hv.Dataset(df) scatter = hv.Scatter(dataset, kdims=["sepal_length"], vdims=["sepal_width"]) hist = hv.operation.histogram(dataset, dimension="petal_width", normed=False) app = dash.Dash(__name__) components = to_dash(app, [scatter, hist]) app.layout = html.Div(components.children) if __name__ == "__main__": app.run_server(debug=True)
import dash import dash_html_components as html import holoviews as hv from holoviews.plotting.plotly.dash import to_dash from holoviews.element.tiles import CartoDark from plotly.data import carshare # Convert from lon/lat to web-mercator easting/northing coordinates df = carshare() df["easting"], df["northing"] = hv.Tiles.lon_lat_to_easting_northing( df["centroid_lon"], df["centroid_lat"]) points = hv.Points(df, ["easting", "northing"]).opts(color="crimson") tiles = CartoDark() overlay = tiles * points app = dash.Dash(__name__) components = to_dash(app, [overlay]) app.layout = html.Div(components.children) if __name__ == '__main__': app.run_server(debug=True)
from plotly.data import iris df = iris() # Build HoloViews Dataset from Pandas DataFrame import holoviews as hv dataset = hv.Dataset(df) # Build HoloViews Elements scatter = hv.Scatter(dataset, kdims=["sepal_length"], vdims=["sepal_width"]) hist = hv.operation.histogram( dataset, dimension="petal_width", normed=False ) # Build side-by-side subplot of scatter and histogram row = scatter + hist # Build Dash app import dash app = dash.Dash(__name__) # Build Dash components from HoloViews row Layout from holoviews.plotting.plotly.dash import to_dash components = to_dash(app, [row]) # Build Dash layout import dash_html_components as html app.layout = html.Div(components.children) if __name__ == "__main__": app.run_server(debug=True)
# -*- coding: utf-8 -*- import dash import dash_html_components as html from plotly.data import iris import holoviews as hv from holoviews.plotting.plotly.dash import to_dash # Load dataset df = iris() dataset = hv.Dataset(df) scatter = hv.Scatter(dataset, kdims=["sepal_length"], vdims=["sepal_width"]) # Set scatter size and color using options system scatter.opts(size=15, color="purple") # Set default drag mode to pan using a plot hook def hook(plot, element): fig = plot.state fig["layout"]["dragmode"] = "pan" scatter.opts(hooks=[hook]) app = dash.Dash(__name__) components = to_dash(app, [scatter]) app.layout = html.Div(components.children) if __name__ == "__main__": app.run_server(debug=True)
y=(bounds[1], bounds[3])), streams=[box]) # Compute histograms of selection along x-axis and y-axis yhist = hv.operation.histogram(dmap, bin_range=points.range('y'), dimension='y', dynamic=True, normed=False) xhist = hv.operation.histogram(dmap, bin_range=points.range('x'), dimension='x', dynamic=True, normed=False) layout = datashade(points).opts( opts.Points(size=6)) * mean_sel * bounds << yhist << xhist # Create App app = dash.Dash(__name__) components = to_dash( app, [layout], reset_button=True, use_ranges=False, ) app.layout = html.Div(components.children) if __name__ == "__main__": app.run_server(debug=True)
def test_boundsxy_dynamic_map(self): # Build Holoviews Elements scatter = Scatter([0, 0]) boundsxy = BoundsXY(source=scatter) dmap = DynamicMap(lambda bounds: Bounds(bounds) if bounds is not None else Bounds((0, 0, 0, 0)), streams=[boundsxy]) # Convert to Dash components = to_dash(self.app, [scatter, dmap], reset_button=True) # Check returned components self.assertIsInstance(components, DashComponents) self.assertEqual(len(components.graphs), 2) self.assertEqual(len(components.kdims), 0) self.assertIsInstance(components.store, Store) self.assertEqual(len(components.resets), 1) # Get arguments passed to @app.callback decorator decorator_args = list(self.app.callback.call_args_list[0])[0] outputs, inputs, states = decorator_args # Check outputs expected_outputs = [(g.id, "figure") for g in components.graphs] + \ [(components.store.id, "data")] self.assertEqual([(output.component_id, output.component_property) for output in outputs], expected_outputs) # Check inputs expected_inputs = [(g.id, prop) for g in components.graphs for prop in ["selectedData", "relayoutData"] ] + [(components.resets[0].id, "n_clicks")] self.assertEqual( [(ip.component_id, ip.component_property) for ip in inputs], expected_inputs, ) # Check State expected_state = [(components.store.id, "data")] self.assertEqual( [(state.component_id, state.component_property) for state in states], expected_state, ) # Check initial figures fig1 = components.graphs[0].figure fig2 = components.graphs[1].figure self.assertEqual(fig1["data"][0]["type"], "scatter") # Second figure holds the bounds element self.assertEqual(len(fig2["data"]), 0) self.assertEqual(len(fig2["layout"]["shapes"]), 1) self.assertEqual(fig2["layout"]["shapes"][0]["path"], "M0 0L0 0L0 0L0 0L0 0Z") # Get callback function callback_fn = self.app.callback.return_value.call_args[0][0] # # mimic initial callback invocation store_value = encode_store_data( {"streams": { id(boundsxy): boundsxy.contents }}) # Update store, then mimic a box selection on scatter figure # store_value = new_store with patch.object( CallbackContext, "triggered", [{ "prop_id": inputs[0].component_id + ".selectedData" }]): [fig1, fig2, new_store] = callback_fn({"range": { "x": [1, 2], "y": [3, 4] }}, {}, {}, {}, 0, store_value) # First figure is the scatter trace self.assertEqual(fig1["data"][0]["type"], "scatter") # Second figure holds the bounds element self.assertEqual(len(fig2["data"]), 0) self.assertEqual(len(fig2["layout"]["shapes"]), 1) self.assertEqual( fig2["layout"]["shapes"][0]["path"], "M1 3L1 4L2 4L2 3L1 3Z", ) # Check that store was updated self.assertEqual(decode_store_data(new_store), { "streams": { id(boundsxy): { "bounds": (1, 3, 2, 4) } }, "kdims": {} }) # Click reset button with patch.object(CallbackContext, "triggered", [{ "prop_id": components.resets[0].id + ".n_clicks" }]): [fig1, fig2, new_store] = callback_fn({"range": { "x": [1, 2], "y": [3, 4] }}, {}, {}, {}, 1, store_value) # First figure is the scatter trace self.assertEqual(fig1["data"][0]["type"], "scatter") # Second figure holds reset bounds elemnt self.assertEqual(len(fig2["data"]), 0) self.assertEqual(len(fig2["layout"]["shapes"]), 1) self.assertEqual(fig2["layout"]["shapes"][0]["path"], "M0 0L0 0L0 0L0 0L0 0Z") # Reset button should clear bounds in store self.assertEqual( decode_store_data(new_store), { "streams": { id(boundsxy): { "bounds": None } }, "reset_nclicks": 1, "kdims": {} })
def test_selection1d_dynamic_map(self): # Create dynamic map that inputs selection1d, returns overlay of scatter on # selected points scatter = Scatter([[0, 0], [1, 1], [2, 2]]) selection1d = Selection1D(source=scatter) dmap = DynamicMap( lambda index: scatter.iloc[index].opts(size=len(index) + 1), streams=[selection1d]) # Convert to Dash components = to_dash(self.app, [scatter, dmap], reset_button=True) # Check returned components self.assertIsInstance(components, DashComponents) self.assertEqual(len(components.graphs), 2) self.assertEqual(len(components.kdims), 0) self.assertIsInstance(components.store, Store) self.assertEqual(len(components.resets), 1) # Get arguments passed to @app.callback decorator decorator_args = list(self.app.callback.call_args_list[0])[0] outputs, inputs, states = decorator_args # Check outputs expected_outputs = [(g.id, "figure") for g in components.graphs] + \ [(components.store.id, "data")] self.assertEqual([(output.component_id, output.component_property) for output in outputs], expected_outputs) # Check inputs expected_inputs = [(g.id, prop) for g in components.graphs for prop in ["selectedData", "relayoutData"] ] + [(components.resets[0].id, "n_clicks")] self.assertEqual( [(ip.component_id, ip.component_property) for ip in inputs], expected_inputs, ) # Check State expected_state = [(components.store.id, "data")] self.assertEqual( [(state.component_id, state.component_property) for state in states], expected_state, ) # Check initial figures fig1 = components.graphs[0].figure fig2 = components.graphs[1].figure # Figure holds the scatter trace self.assertEqual(len(fig2["data"]), 1) # Check expected marker size self.assertEqual(fig2["data"][0]["marker"]["size"], 1) self.assertEqual(list(fig2["data"][0]["x"]), []) self.assertEqual(list(fig2["data"][0]["y"]), []) # Get callback function callback_fn = self.app.callback.return_value.call_args[0][0] # mimic initial callback invocation store_value = encode_store_data( {"streams": { id(selection1d): selection1d.contents }}) # Update store, then mimick a selection on scatter figure # store_value = new_store with patch.object( CallbackContext, "triggered", [{ "prop_id": inputs[0].component_id + ".selectedData" }]): [fig1, fig2, new_store] = callback_fn( { "points": [{ "curveNumber": 0, "pointNumber": 0, "pointIndex": 0, }, { "curveNumber": 0, "pointNumber": 2, "pointIndex": 2, }] }, {}, 0, store_value) # Figure holds the scatter trace self.assertEqual(len(fig2["data"]), 1) # Check expected marker size self.assertEqual(fig2["data"][0]["marker"]["size"], 3) self.assertEqual(list(fig2["data"][0]["x"]), [0, 2]) self.assertEqual(list(fig2["data"][0]["y"]), [0, 2]) # Check that store was updated self.assertEqual(decode_store_data(new_store), { "streams": { id(selection1d): { "index": [0, 2] } }, "kdims": {} }) # Click reset button store = new_store with patch.object(CallbackContext, "triggered", [{ "prop_id": components.resets[0].id + ".n_clicks" }]): [fig1, fig2, new_store] = callback_fn({}, {}, 1, store) # Figure holds the scatter trace self.assertEqual(len(fig2["data"]), 1) # Check expected marker size self.assertEqual(fig2["data"][0]["marker"]["size"], 1) self.assertEqual(list(fig2["data"][0]["x"]), []) self.assertEqual(list(fig2["data"][0]["y"]), []) # Check that store was updated self.assertEqual( decode_store_data(new_store), { "streams": { id(selection1d): { "index": [] } }, 'reset_nclicks': 1, "kdims": {} }, )
def test_rangexy_dynamic_map(self): # Create dynamic map that inputs rangexy, returns scatter on bounds scatter = Scatter([[0, 1], [0, 1]], kdims=["x"], vdims=["y"]) rangexy = RangeXY(source=scatter) def dmap_fn(x_range, y_range): x_range = (0, 1) if x_range is None else x_range y_range = (0, 1) if y_range is None else y_range return Scatter( [[x_range[0], y_range[0]], [x_range[1], y_range[1]]], kdims=["x1"], vdims=["y1"]) dmap = DynamicMap(dmap_fn, streams=[rangexy]) # Convert to Dash components = to_dash(self.app, [scatter, dmap], reset_button=True) # Check returned components self.assertIsInstance(components, DashComponents) self.assertEqual(len(components.graphs), 2) self.assertEqual(len(components.kdims), 0) self.assertIsInstance(components.store, Store) self.assertEqual(len(components.resets), 1) # Get arguments passed to @app.callback decorator decorator_args = list(self.app.callback.call_args_list[0])[0] outputs, inputs, states = decorator_args # Check outputs expected_outputs = [(g.id, "figure") for g in components.graphs] + \ [(components.store.id, "data")] self.assertEqual([(output.component_id, output.component_property) for output in outputs], expected_outputs) # Check inputs expected_inputs = [(g.id, prop) for g in components.graphs for prop in ["selectedData", "relayoutData"] ] + [(components.resets[0].id, "n_clicks")] self.assertEqual( [(ip.component_id, ip.component_property) for ip in inputs], expected_inputs, ) # Check State expected_state = [(components.store.id, "data")] self.assertEqual( [(state.component_id, state.component_property) for state in states], expected_state, ) # Get callback function callback_fn = self.app.callback.return_value.call_args[0][0] # mimic initial callback invocation store_value = encode_store_data( {"streams": { id(rangexy): rangexy.contents }}) with patch.object( CallbackContext, "triggered", [{ "prop_id": components.graphs[0].id + ".relayoutData" }]): [fig1, fig2, new_store] = callback_fn({}, { "xaxis.range[0]": 1, "xaxis.range[1]": 3, "yaxis.range[0]": 2, "yaxis.range[1]": 4 }, {}, {}, None, store_value) # First figure is the scatter trace self.assertEqual(fig1["data"][0]["type"], "scatter") # Second figure holds the bounds element self.assertEqual(len(fig2["data"]), 1) self.assertEqual(list(fig2["data"][0]["x"]), [1, 3]) self.assertEqual(list(fig2["data"][0]["y"]), [2, 4]) # Check updated store self.assertEqual( decode_store_data(new_store), { "streams": { id(rangexy): { 'x_range': (1, 3), 'y_range': (2, 4) } }, "kdims": {} })
linked_hist.opts(hv.opts.Histogram(hooks=[set_dragmode])) # Set plot margins, ordered (left, bottom, right, top) linked_hist.opts(margins=(60, 40, 30, 30)) linked_map_overlay.opts(margins=(30, 30, 30, 30)) # Build Dash app app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) server = app.server # Build Dash components from multiple HoloViews Elements components = to_dash( app, [linked_map_overlay, linked_hist], reset_button=True, button_class=dbc.Button, ) # Build Dash layout using Dash Bootstrap Components app.layout = dbc.Container([ html.H1("NYC Taxi Demo", style={"padding-top": 40}), html. H3("Crossfiltering 10 million trips with Dash, Datashader, and HoloViews"), html.Hr(), dbc.Row([ dbc.Col(children=[ dbc.Card([ dbc.CardHeader("Drop off locations"), dbc.CardBody(children=[ components.graphs[0],
# -*- coding: utf-8 -*- import dash import dash_html_components as html import numpy as np import holoviews as hv from holoviews.plotting.plotly.dash import to_dash frequencies = [0.5, 0.75, 1.0, 1.25] def sine_curve(phase, freq): xvals = [0.1 * i for i in range(100)] return hv.Curve((xvals, [np.sin(phase + freq * x) for x in xvals])) # When run live, this cell's output should match the behavior of the GIF below dmap = hv.DynamicMap(sine_curve, kdims=['phase', 'frequency']) dmap = dmap.redim.range(phase=(0.5, 1), frequency=(0.5, 1.25)) # Create App app = dash.Dash(__name__) # Dash display components = to_dash(app, [dmap]) app.layout = html.Div(components.children) if __name__ == '__main__': app.run_server(debug=True)