predict-idlab / plotly-resampler

Visualize large time series data with plotly.py
https://predict-idlab.github.io/plotly-resampler/latest
MIT License
1.02k stars 66 forks source link

[BUG] `renderer="png"` - rendering png images in notebooks - does not work #302

Closed etiennedemontalivet closed 6 months ago

etiennedemontalivet commented 6 months ago

I am trying to replicate some of the basic examples. Especially, I'd like to produce some png figures when I share notebooks with others, but when I use fig.show(renderer="png"), it never returns anything (I waited for up to 20 minutes).

If I use USE_PNG = False, the code works as expected and is super fast.

Here is the code I use:

import numpy as np
import pandas as pd
import plotly.graph_objects as go
from plotly_resampler import register_plotly_resampler, unregister_plotly_resampler

USE_PNG = True  # Set to false to use dynamic plots

n = 20000
x = np.arange(n)
x_time = pd.date_range("2020-01-01", freq="1s", periods=len(x))
noisy_sine = (3 + np.sin(x / 2000) + np.random.randn(n) / 10) * x / (n / 4)

register_plotly_resampler(mode="auto", default_n_shown_samples=4500)

fig = go.Figure()
fig.add_traces(
    [
        {"y": noisy_sine + 2, "name": "yp2", "type": "scattergl"},
        {"y": noisy_sine - 3, "name": "ym1", "type": "scatter"},
    ]
)

if USE_PNG:
    unregister_plotly_resampler()
    go.Figure(fig).show(renderer="png")
else:
    fig.show()

Environment information:

Am I doing something wrong ? Any help would be much appreciated!

jonasvdd commented 6 months ago

Hi @etiennedemontalivet,

I tried to reproduce your issue, but was not able to achieve your outcome. The screenshot below demonstrates both approaches I tried (on the 0.9.2. tag of plotly resampler in vscode, and creating a new python 3.10 virtualenv in which I install kaleido, plotly-resampler, jupyter, and ipykernel.

image

As I could not reproduce your error I hope that my tests may help you further with resolving it! And please let me know when you've found the cause of your issue.

Kind regards, Jonas

etiennedemontalivet commented 6 months ago

Thanks for your quick answer, I'll investigate in more details tomorrow and let you know.

etiennedemontalivet commented 6 months ago

Hi @jonasvdd , I investigated in multiple clean environments but sill have the issue... Here is what I tried:

conda-based environment with python 3.10 ![resampler_issue0](https://github.com/predict-idlab/plotly-resampler/assets/7569375/f747c1f6-7a5b-4204-99e6-341628badbc2) ![resampler_issue1](https://github.com/predict-idlab/plotly-resampler/assets/7569375/ef0fbc01-d3d6-4f34-8645-99985bfa45de)
Then I updated the plotly-resampler to get the latset version 0.9.2 ![resampler_issue2](https://github.com/predict-idlab/plotly-resampler/assets/7569375/ab09af8d-2147-46e0-b1d3-f94fc96d4554) ![resampler_issue3](https://github.com/predict-idlab/plotly-resampler/assets/7569375/b4a907ec-58b5-44f0-84fe-05b4e98a5a66)
Then I tried in an environment created with python venv and install the 4 packages with pip install ![resampler_issue4](https://github.com/predict-idlab/plotly-resampler/assets/7569375/548d62b6-80fb-489a-a7c2-519bd3f6f4f2) ![resampler_issue5](https://github.com/predict-idlab/plotly-resampler/assets/7569375/d8cacb47-7372-4542-b140-8d55174fe864)
Lastly I tried in jupyter notebook with the 4 packages matching the versions of your screenshot ![resampler_issue6](https://github.com/predict-idlab/plotly-resampler/assets/7569375/4f5f436f-6ea0-4c1c-9891-b6b864609b2c)

Can you please tell me what plotly version you're using ?
Do you have any idea what might cause the bug on my side ? Best,

etiennedemontalivet commented 6 months ago

Maybe related to this issue: Kaleido fails to save image with fig.write_image()

etiennedemontalivet commented 6 months ago

Different error on a Linux machine:

conda create -n "tmpenv" python=3.10 plotly-resampler jupyter python-kaleido ipykernel

Error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[2], line 31
     29 if USE_PNG:
     30     unregister_plotly_resampler()
---> 31     go.Figure(fig).show(renderer="png")
     32 else:
     33     fig.show()

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/plotly/basedatatypes.py:3410, in BaseFigure.show(self, *args, **kwargs)
   3377 """
   3378 Show a figure using either the default renderer(s) or the renderer(s)
   3379 specified by the renderer argument
   (...)
   3406 None
   3407 """
   3408 import plotly.io as pio
-> 3410 return pio.show(self, *args, **kwargs)

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/plotly/io/_renderers.py:386, in show(fig, renderer, validate, **kwargs)
    383 fig_dict = validate_coerce_fig_to_dict(fig, validate)
    385 # Mimetype renderers
--> 386 bundle = renderers._build_mime_bundle(fig_dict, renderers_string=renderer, **kwargs)
    387 if bundle:
    388     if not ipython_display:

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/plotly/io/_renderers.py:294, in RenderersConfig._build_mime_bundle(self, fig_dict, renderers_string, **kwargs)
    291             if hasattr(renderer, k):
    292                 setattr(renderer, k, v)
--> 294         bundle.update(renderer.to_mimebundle(fig_dict))
    296 return bundle

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/plotly/io/_base_renderers.py:126, in ImageRenderer.to_mimebundle(self, fig_dict)
    125 def to_mimebundle(self, fig_dict):
--> 126     image_bytes = to_image(
    127         fig_dict,
    128         format=self.format,
    129         width=self.width,
    130         height=self.height,
    131         scale=self.scale,
    132         validate=False,
    133         engine=self.engine,
    134     )
    136     if self.b64_encode:
    137         image_str = base64.b64encode(image_bytes).decode("utf8")

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/plotly/io/_kaleido.py:143, in to_image(fig, format, width, height, scale, validate, engine)
    140 # Validate figure
    141 # ---------------
    142 fig_dict = validate_coerce_fig_to_dict(fig, validate)
--> 143 img_bytes = scope.transform(
    144     fig_dict, format=format, width=width, height=height, scale=scale
    145 )
    147 return img_bytes

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/kaleido/scopes/plotly.py:153, in PlotlyScope.transform(self, figure, format, width, height, scale)
    142     raise ValueError(
    143         "Invalid format '{original_format}'.\n"
    144         "    Supported formats: {supported_formats_str}"
   (...)
    148         )
    149     )
    151 # Transform in using _perform_transform rather than superclass so we can access the full
    152 # response dict, including error codes.
--> 153 response = self._perform_transform(
    154     figure, format=format, width=width, height=height, scale=scale
    155 )
    157 # Check for export error, later can customize error messages for plotly Python users
    158 code = response.get("code", 0)

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/kaleido/scopes/base.py:293, in BaseScope._perform_transform(self, data, **kwargs)
    284 """
    285 Transform input data using the current scope, returning dict response with error code
    286 whether successful or not.
   (...)
    290 :return: Dict of response from Kaleido executable, whether successful or not
    291 """
    292 # Ensure that kaleido subprocess is running
--> 293 self._ensure_kaleido()
    295 # Perform export
    296 export_spec = self._json_dumps(dict(kwargs, data=data)).encode('utf-8')

File ~/miniconda3/envs/tmpenv/lib/python3.10/site-packages/kaleido/scopes/base.py:198, in BaseScope._ensure_kaleido(self)
    193 if not startup_response_string:
    194     message = (
    195         "Failed to start Kaleido subprocess. Error stream:\n\n" +
    196         self._get_decoded_std_error()
    197     )
--> 198     raise ValueError(message)
    199 else:
    200     startup_response = json.loads(startup_response_string)

ValueError: Failed to start Kaleido subprocess. Error stream:

[0314/105741.965509:WARNING:resource_bundle.cc(431)] locale_file_path.empty() for locale 
[0314/105741.970501:WARNING:resource_bundle.cc(431)] locale_file_path.empty() for locale 
[0314/105741.970500:WARNING:resource_bundle.cc(431)] locale_file_path.empty() for locale 
Received signal 7 BUS_ADRERR 7f754d365000
#0 0x55e707b9dd79 base::debug::CollectStackTrace()
#1 0x55e707b1b633 base::debug::StackTrace::StackTrace()
#2 0x55e707b9d95b base::debug::(anonymous namespace)::StackDumpSignalHandler()
#3 0x7f7550813520 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x4251f)
#4 0x55e705d07f47 FT_Stream_ReadULong
#5 0x55e705d3921b sfnt_open_font
#6 0x55e705d34990 sfnt_init_face
#7 0x55e705d43079 tt_face_init
#8 0x55e705d08bbb open_face
#9 0x55e705d03b23 ft_open_face_internal
#10 0x55e705d03950 FT_New_Face
#11 0x55e70814959c IA__FcFreeTypeQueryAll
#12 0x55e70814667d FcFileScanConfig
#13 0x55e7081469b6 FcDirScanConfig
#14 0x55e708146afa FcDirCacheScan
#15 0x55e708146bae IA__FcDirCacheRead
#16 0x55e70813d027 FcConfigAddDirList
#17 0x55e70813cf67 FcConfigBuildFonts
#18 0x55e70814ac81 IA__FcInitLoadConfigAndFonts
#19 0x55e70813c422 FcConfigInit
#20 0x55e708445287 gfx::GetGlobalFontConfig()
#21 0x55e7065336f5 content::BrowserMainRunnerImpl::Initialize()
#22 0x55e7090057b7 headless::HeadlessContentMainDelegate::RunProcess()
#23 0x55e707884f3e content::ContentMainRunnerImpl::RunServiceManager()
#24 0x55e707884b76 content::ContentMainRunnerImpl::Run()
#25 0x55e707882374 content::RunContentProcess()
#26 0x55e707882cfc content::ContentMain()
#27 0x55e7078d4182 headless::(anonymous namespace)::RunContentMain()
#28 0x55e7078d4025 headless::HeadlessBrowserMain()
#29 0x55e7058f2fa8 main
#30 0x7f75507fad90 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
#31 0x7f75507fae40 __libc_start_main
#32 0x55e7058ec3ea _start
  r8: 0000000000000000  r9: 0000000000000000 r10: 0000000000000002 r11: 0000000000000293
 r12: 00002d471de8e800 r13: 0000000000000000 r14: 00007fffab65e0d4 r15: 00007f754d365000
  di: 00002d471df20eb0  si: 0000000000000000  bp: 00007fffab65ded0  bx: 00002d471df20eb0
  dx: 00007fffab65e1b8  ax: 0000000000000000  cx: 00007fffab65e178  sp: 00007fffab65deb0
  ip: 000055e705d07f47 efl: 0000000000010206 cgf: 002b000000000033 erf: 0000000000000004
 trp: 000000000000000e msk: 0000000000000000 cr2: 00007f754d365000
[end of stack trace]
Calling _exit(1). Core file will not be generated.

But this is purely related to kaleido, I'll open an issue in their github repo

etiennedemontalivet commented 6 months ago

The bug was coming from kaleido. They have many open issues such as this one or this one. At the end, reverting kaleido to version 0.1.0.post1 fixed my issue:

pip install "kaleido==0.1.0.post1"

Everything from plotly-resampler works now as expected. Thanks for the support @jonasvdd !