Problem converting plotly to word due to subprocess Kaleido

Which tool versions are you using?

SDK: v14
Platform: v2023.04.3
Python: v3.10
Isolation mode: venv

Current Behavior

Most apps have a report downoad option to Word. Using plotly go.Figure objects.
Plotly uses Kaleido as engine to convert object to image.
However in one application:

Method 1 (full report) works on my pc, doesn’t work on staging, doesn’t work on pc of a collegue
Method 2 (see snippit) works on my pc, works on staging, doesn’t work on pc of a collegue

We both have windows laptops.
The code stops running when writing to a buffer or at the downloadresult, adding it to word doens’t give a problem.

Most sipmlistic method that doesn’t work:

    def download_word_report_2(self, **kwargs) -> DownloadResult:
        progress_message("Word rapport wordt aangemaakt en gedownload...")
        doc = PileReport(template_word_path=WORD_EMPTY_TEMPLATE_PATH, name="project_name", app_version=VERSION)
        _fig = go.Figure(data=
        go.Contour(
            z=[[10, 10.625, 12.5, 15.625, 20],
               [5.625, 6.25, 8.125, 11.25, 15.625],
               [2.5, 3.125, 5., 8.125, 12.5],
               [0.625, 1.25, 3.125, 6.25, 10.625],
               [0, 0.625, 2.5, 5.625, 10]]
        ))

        cur_par = doc.add_pile_group_internal_forces_plotly(
            cur_par=doc.cur_par,
            name="pg.name",
            fig_internal_forces=_fig
        )
        progress_message("Report has been created")
        return DownloadResult(file_content=doc.get_report_as_file, file_name=f"{55}.docx")

Error message:

Expected Behavior

Plotly figures shouldn’t give problems when downloading.
No idea why it works for most apps using plotly, why it always work on the development env of my laptop. But doesn’t work for this specific app/method, while it never works for my collegue

Any suggestions?

Johan,

I’m having a hard time assessing what the problem is here as I don’t know what your PileReport object looks like or how the add_pile_group_internal_forces_plotly method processes the figure. So if you could present a basic example detailing how the figure is processed between the generation up to including it into the report and through to how the report is processed into the DownloadResult I can hopefully help you a bit further along.

p.s. please try not to include personal information in posts (e.g. the paths in the snippet of your error message)

Thanks for the tip. I’ll edit the post.

Here is a more isolated version. Just adding an empty template.docx file next to it.
The error is the same for my collegue, but it works for me. So apperently it isn’t a problem of Viktor, but it is a problem of the server hosting the application, as it seems unable to start the Kaleido subprocess, however the requirements include the package.

from io import BytesIO
from pathlib import Path

from docx import Document
from docx.document import _Body
from docx.text.paragraph import Paragraph
from plotly import graph_objs as go

path_template = Path(__file__).parent / "template.docx"
doc = Document(docx=str(path_template))
body: _Body = doc._body  # pylint: disable=protected-access
cur_par: Paragraph = body.paragraphs[-1]

_fig = go.Figure(data=
go.Contour(
    z=[[10, 10.625, 12.5, 15.625, 20],
       [5.625, 6.25, 8.125, 11.25, 15.625],
       [2.5, 3.125, 5., 8.125, 12.5],
       [0.625, 1.25, 3.125, 6.25, 10.625],
       [0, 0.625, 2.5, 5.625, 10]]
))

cur_par.add_run().add_picture(image_path_or_stream=BytesIO(_fig.to_image(format="png")))
doc.save("New file.docx")

If you have any idea that would be great, otherwise we will stick to our matplotlib version, it is just unreliable to use plotly to word this way, while it is a great way to visualise within the UI and a conversion to word (as in a lot of other apps is done)

Thanks for the elaboration. If I save the document to a BytesIO object first in your example I am able to download the file just fine. Would that be a possible solution for your case as well?

    @staticmethod
    def get_word_report(params, **kwargs):
        path_template = Path(__file__).parent / "template.docx"
        doc = Document(docx=str(path_template))
        body: _Body = doc._body  # pylint: disable=protected-access
        cur_par: Paragraph = body.paragraphs[-1]

        _fig = go.Figure(data=
        go.Contour(
            z=[[10, 10.625, 12.5, 15.625, 20],
               [5.625, 6.25, 8.125, 11.25, 15.625],
               [2.5, 3.125, 5., 8.125, 12.5],
               [0.625, 1.25, 3.125, 6.25, 10.625],
               [0, 0.625, 2.5, 5.625, 10]]
        ))

        cur_par.add_run().add_picture(image_path_or_stream=BytesIO(_fig.to_image(format="png")))

        document = BytesIO()
        doc.save(document)

        return DownloadResult(file_content=document, file_name=f"document.docx")

I asked four collegues, this example works for 3 our of 4 collegues using the same venv and requirements.txt file. But for 1 collegue it doesn’t work.
The same counts for the applications. 5/6 using this logic work just fine, just a single one that doesn’t.

As it seems to be a kaleido/plotly issue, I will ask it on Stackoverflow instead.

Thanks for thinking/helping Daniël!

1 Like