diff --git a/Dockerfile b/Dockerfile index f428390dd..d005c641d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,6 +37,8 @@ COPY babel.config.js lerna.json nx.json tsconfig.json ./ # This requires the Dockerfile to be built in the context of the root of the deephaven-plugins repository # https://stackoverflow.com/a/34300129 COPY plugins plugins +# delete the plotly plugin as it's deprecated +RUN rm -rf plugins/plotly # Build the JS RUN npm run build diff --git a/plugins/plotly-express/src/deephaven/plot/express/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/__init__.py index b04a7a7c8..cca071669 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/__init__.py @@ -4,6 +4,7 @@ from typing import Any from deephaven.plugin.object_type import BidirectionalObjectType, MessageStream +from plotly.graph_objs import Figure from .communication.DeephavenFigureConnection import DeephavenFigureConnection from .deephaven_figure import DeephavenFigure @@ -66,7 +67,8 @@ def name(self) -> str: def is_type(self, obj: Any) -> bool: """ - Check if an object is a DeephavenFigure + Check if an object is a DeephavenFigure or Plotly Figure + Plotly figures are wrapped in DeephavenFigure when sent to the client Args: obj: The object to check @@ -74,7 +76,7 @@ def is_type(self, obj: Any) -> bool: Returns: True if the object is of the correct type, False otherwise """ - return isinstance(obj, DeephavenFigure) + return isinstance(obj, DeephavenFigure) or isinstance(obj, Figure) def create_client_connection( self, obj: DeephavenFigure, connection: MessageStream @@ -90,6 +92,10 @@ def create_client_connection( Returns: The client connection """ + if isinstance(obj, Figure): + # this is a plotly figure, it will never be updated, so wrap once and send + obj = DeephavenFigure(obj, is_plotly_fig=True) + figure_connection = DeephavenFigureConnection(obj, connection) initial_message = json.dumps( { diff --git a/plugins/plotly-express/src/deephaven/plot/express/_register.py b/plugins/plotly-express/src/deephaven/plot/express/_register.py index 34d2383ee..4a2f27bb7 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/_register.py +++ b/plugins/plotly-express/src/deephaven/plot/express/_register.py @@ -1,3 +1,4 @@ +from plotly import io as pio from deephaven.plugin import Registration, Callback from deephaven.plugin.utilities import create_js_plugin, DheSafeCallbackWrapper from . import DeephavenFigureType @@ -24,6 +25,8 @@ def register_into(cls, callback: Callback) -> None: A function to call after registration """ + # Disable default renderer to ignore figure.show() + pio.renderers.default = None callback = DheSafeCallbackWrapper(callback) callback.register(DeephavenFigureType) diff --git a/plugins/plotly-express/src/deephaven/plot/express/deephaven_figure/DeephavenFigure.py b/plugins/plotly-express/src/deephaven/plot/express/deephaven_figure/DeephavenFigure.py index 3166bfdc0..d70828519 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/deephaven_figure/DeephavenFigure.py +++ b/plugins/plotly-express/src/deephaven/plot/express/deephaven_figure/DeephavenFigure.py @@ -394,6 +394,7 @@ def __init__( has_color: bool = False, trace_generator: Generator[dict[str, Any], None, None] | None = None, has_subplots: bool = False, + is_plotly_fig: bool = False, ): """ Create a new DeephavenFigure @@ -407,6 +408,7 @@ def __init__( has_color: If this figure has color trace_generator: The trace generator has_subplots: If this figure has subplots + is_plotly_fig: If this is a plotly figure """ # keep track of function that called this, and it's args self._head_node = DeephavenHeadNode() @@ -428,6 +430,8 @@ def __init__( self._has_subplots = has_subplots + self._is_plotly_fig = is_plotly_fig + self._liveness_scope = LivenessScope() def copy_mappings(self: DeephavenFigure, offset: int = 0) -> list[DataMapping]: @@ -584,6 +588,10 @@ def get_figure(self) -> DeephavenFigure | None: Returns: The figure """ + if self._is_plotly_fig: + # a plotly figure was passed directly + # just return this figure since it will never be updated + return self return self._head_node.get_figure() def get_plotly_fig(self) -> Figure | None: @@ -676,6 +684,7 @@ def copy(self) -> DeephavenFigure: self._has_color, self._trace_generator, self._has_subplots, + self._is_plotly_fig, ) new_figure._head_node = self._head_node.copy_graph() return new_figure diff --git a/plugins/plotly/README.md b/plugins/plotly/README.md index 1befec30d..3d069d4a8 100644 --- a/plugins/plotly/README.md +++ b/plugins/plotly/README.md @@ -1,3 +1,7 @@ +# Deprecated +This plugin is deprecated and will be removed in a future release. +Please use the plotly-express plugin instead, which will render Plotly plots in the same way as this plugin. + # Deephaven Plugin for Plotly The Deephaven Plugin for Plotly. Allows for opening Plotly plots in a Deephaven environment. Any Plotly plot diff --git a/tests/app.d/express.py b/tests/app.d/express.py index 217055b4e..6d46099a5 100644 --- a/tests/app.d/express.py +++ b/tests/app.d/express.py @@ -1,6 +1,7 @@ from deephaven.column import int_col, string_col from deephaven import new_table import deephaven.plot.express as dx +import plotly.express as px express_source = new_table( [ @@ -9,3 +10,5 @@ ] ) express_fig = dx.bar(table=express_source, x="Categories", y="Values") + +plotly_fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16]) diff --git a/tests/express.spec.ts b/tests/express.spec.ts index 6859fdca8..2fbadfeae 100644 --- a/tests/express.spec.ts +++ b/tests/express.spec.ts @@ -6,3 +6,9 @@ test('Express loads', async ({ page }) => { await openPanel(page, 'express_fig', '.js-plotly-plot'); await expect(page.locator('.iris-chart-panel')).toHaveScreenshot(); }); + +test('Plotly loads', async ({ page }) => { + await gotoPage(page, ''); + await openPanel(page, 'plotly_fig', '.js-plotly-plot'); + await expect(page.locator('.iris-chart-panel')).toHaveScreenshot(); +}); \ No newline at end of file diff --git a/tests/express.spec.ts-snapshots/Plotly-loads-1-chromium-linux.png b/tests/express.spec.ts-snapshots/Plotly-loads-1-chromium-linux.png new file mode 100644 index 000000000..bc6a3bf83 Binary files /dev/null and b/tests/express.spec.ts-snapshots/Plotly-loads-1-chromium-linux.png differ diff --git a/tests/express.spec.ts-snapshots/Plotly-loads-1-firefox-linux.png b/tests/express.spec.ts-snapshots/Plotly-loads-1-firefox-linux.png new file mode 100644 index 000000000..6a6fd892c Binary files /dev/null and b/tests/express.spec.ts-snapshots/Plotly-loads-1-firefox-linux.png differ diff --git a/tests/express.spec.ts-snapshots/Plotly-loads-1-webkit-linux.png b/tests/express.spec.ts-snapshots/Plotly-loads-1-webkit-linux.png new file mode 100644 index 000000000..bc49757c3 Binary files /dev/null and b/tests/express.spec.ts-snapshots/Plotly-loads-1-webkit-linux.png differ