def setUp(self): self.path1 = Path([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-0.3, 0.4)]) self.path2 = Path([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-3, 4)]) self.contours1 = Contours([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-0.3, 0.4)], level=1) self.contours2 = Contours([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-3, 4)], level=1) self.contours3 = Contours([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-0.3, 0.4)], level=2) self.bounds1 = Bounds(0.3) self.bounds2 = Bounds(0.4) self.box1 = Box(-0.25, 0.3, 0.3) self.box2 = Box(-0.25, 0.3, 0.4) self.ellipse1 = Ellipse(-0.25, 0.3, 0.3) self.ellipse2 = Ellipse(-0.25, 0.3, 0.4)
def setUp(self): self.path1 = Path([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-0.3, 0.4)]) self.path2 = Path([(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4), (-3, 4)]) self.contours1 = Contours([(-0.3, 0.4, 1), (-0.3, 0.3, 1), (-0.2, 0.3, 1), (-0.2, 0.4, 1), (-0.3, 0.4, 1)], vdims='Level') self.contours2 = Contours([(-0.3, 0.4, 1), (-0.3, 0.3, 1), (-0.2, 0.3, 1), (-0.2, 0.4, 1), (-3, 4, 1)], vdims='Level') self.contours3 = Contours([(-0.3, 0.4, 2), (-0.3, 0.3, 2), (-0.2, 0.3, 2), (-0.2, 0.4, 2), (-0.3, 0.4, 2)], vdims='Level') self.bounds1 = Bounds(0.3) self.bounds2 = Bounds(0.4) self.box1 = Box(-0.25, 0.3, 0.3) self.box2 = Box(-0.25, 0.3, 0.4) self.ellipse1 = Ellipse(-0.25, 0.3, 0.3) self.ellipse2 = Ellipse(-0.25, 0.3, 0.4)
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": {} })