diff --git a/panel/pane/plotly.py b/panel/pane/plotly.py index 6624d835ed..42363957a1 100644 --- a/panel/pane/plotly.py +++ b/panel/pane/plotly.py @@ -250,28 +250,34 @@ def _update_data_sources(self, cds, trace): return update_sources @staticmethod - def _plotly_json_wrapper(fig): + def _convert_trace(trace): + trace = dict(trace) + for key in trace: + if not isdatetime(trace[key]): + continue + arr = trace[key] + if isinstance(arr, np.ndarray): + arr = arr.astype(str) + elif isinstance(arr, datetime_types): + arr = str(arr) + else: + arr = [str(v) for v in arr] + trace[key] = arr + return trace + + @classmethod + def _plotly_json_wrapper(cls, fig): """Wraps around to_plotly_json and applies necessary fixes. For #382: Map datetime elements to strings. """ - json = fig.to_plotly_json() - layout = json['layout'] - data = json['data'] - shapes = layout.get('shapes', []) - for trace in data+shapes: - for key in trace: - if not isdatetime(trace[key]): - continue - arr = trace[key] - if isinstance(arr, np.ndarray): - arr = arr.astype(str) - elif isinstance(arr, datetime_types): - arr = str(arr) - else: - arr = [str(v) for v in arr] - trace[key] = arr - return json + layout = dict(fig._layout) + data = [cls._convert_trace(trace) for trace in fig._data] + if 'shapes' in layout: + layout['shapes'] = [ + cls._convert_trace(shape) for shape in layout['shapes'] + ] + return {'data': data, 'layout': layout} def _init_params(self): viewport_params = [p for p in self.param if 'viewport' in p] diff --git a/panel/tests/pane/test_plotly.py b/panel/tests/pane/test_plotly.py index cb40d7b7b5..058dd5711a 100644 --- a/panel/tests/pane/test_plotly.py +++ b/panel/tests/pane/test_plotly.py @@ -191,11 +191,11 @@ def test_plotly_autosize(document, comm): @plotly_available def test_clean_relayout_data(): relayout_data = { - "mapbox.center": {"lon": -73.59183434290809, "lat": 45.52341668343991}, - "mapbox.zoom": 10, - "mapbox.bearing": 0, - "mapbox.pitch": 0, - "mapbox._derived": { + "map.center": {"lon": -73.59183434290809, "lat": 45.52341668343991}, + "map.zoom": 10, + "map.bearing": 0, + "map.pitch": 0, + "map._derived": { "coordinates": [ [-73.92279747767401, 45.597934047192865], [-73.26087120814279, 45.597934047192865], @@ -206,10 +206,10 @@ def test_clean_relayout_data(): } result = Plotly._clean_relayout_data(relayout_data) assert result == { - "mapbox.center": {"lon": -73.59183434290809, "lat": 45.52341668343991}, - "mapbox.zoom": 10, - "mapbox.bearing": 0, - "mapbox.pitch": 0, + "map.center": {"lon": -73.59183434290809, "lat": 45.52341668343991}, + "map.zoom": 10, + "map.bearing": 0, + "map.pitch": 0, } @@ -276,7 +276,7 @@ def test_plotly_datetime_converted_2d_array(document, comm): 'longitude': np.cumsum(np.random.randn(n_points) * 0.01) + 4.8952, # Centered around Amsterdam }) - fig = px.scatter_mapbox(data, lon='longitude', lat='latitude', custom_data='timestamp') + fig = px.scatter_map(data, lon='longitude', lat='latitude', custom_data='timestamp') p = Plotly(fig) diff --git a/pyproject.toml b/pyproject.toml index 06b2f6976f..f3c23341a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -228,6 +228,8 @@ filterwarnings = [ # 2024-11 "ignore:websockets.legacy is deprecated:DeprecationWarning", # https://github.com/encode/uvicorn/issues/1908 "ignore:websockets.server.WebSocketServerProtocol is deprecated:DeprecationWarning", # https://github.com/encode/uvicorn/issues/1908 + # 2025-01 `plotly` 6.0 triggers warnings + "ignore:\\*scattermapbox\\* is deprecated! Use \\*scattermap\\* instead" # https://github.com/plotly/plotly.py/issues/4997 ] [tool.mypy]