dataframe_image icon indicating copy to clipboard operation
dataframe_image copied to clipboard

Unable to save png on a headless server

Open Jbiloki opened this issue 3 years ago • 12 comments

Hello when attempting to save a dataframe as such:

import dataframe_image as dfi
from IPython.display import display, HTML
...

        percent_columns = ['Precision', 'Recall', 'F-1']
        print('INTENT ARGS EVAL:')
        output = pd.DataFrame(exp_intent_args['accuracy'] - prod_intent_args['accuracy'])
        output = output.style.applymap(lambda x: 'color : green' if x>=0 else 'color : red')
        display(output)
        output.export_png('intent_args_diff.png')

I get the following error only on my server:

Traceback (most recent call last):
  File "./utterance_understanding/eval/run_evaluation.py", line 279, in <module>
    main()
  File "./utterance_understanding/eval/run_evaluation.py", line 115, in main
    get_baseline_diff(args.baseline_path, os.path.join(evaluation_output_dir, 'debug'))
  File "./utterance_understanding/eval/run_evaluation.py", line 142, in get_baseline_diff
    get_exp_diff(exp_intent, exp_intent_args, prod_intent, prod_intent_args)
  File "./utterance_understanding/eval/run_evaluation.py", line 124, in get_exp_diff
    output.export_png('intent_args_diff.png')
  File "/miniconda/lib/python3.7/site-packages/dataframe_image/_pandas_accessor.py", line 24, in export
    return _export(obj, filename, fontsize, max_rows, max_cols, table_conversion, chrome_path)
  File "/miniconda/lib/python3.7/site-packages/dataframe_image/_pandas_accessor.py", line 73, in _export
    img_str = converter(html)
  File "/miniconda/lib/python3.7/site-packages/dataframe_image/_screenshot.py", line 167, in run
    img = self.take_screenshot()
  File "/miniconda/lib/python3.7/site-packages/dataframe_image/_screenshot.py", line 119, in take_screenshot
    img = mimage.imread(buffer)
  File "/miniconda/lib/python3.7/site-packages/matplotlib/image.py", line 1490, in imread
    with img_open(fname) as image:
  File "/miniconda/lib/python3.7/site-packages/PIL/ImageFile.py", line 121, in __init__
    self._open()
  File "/miniconda/lib/python3.7/site-packages/PIL/PngImagePlugin.py", line 676, in _open
    raise SyntaxError("not a PNG file")
SyntaxError: not a PNG file```

Jbiloki avatar Feb 03 '21 22:02 Jbiloki

Did you fix it yet? Have the same problem

QuatschFisch avatar Apr 12 '21 12:04 QuatschFisch

Here is the monkey patch to get it to work

import dataframe_image as dfi
from dataframe_image._screenshot import Screenshot

import subprocess
import io
from pathlib import Path
from tempfile import TemporaryDirectory
from matplotlib import image as mimage

def take_screenshot_override (self):
    temp_dir = TemporaryDirectory()
    temp_html = Path(temp_dir.name) / "temp.html"
    temp_img = Path(temp_dir.name) / "temp.png"
    with open(temp_html, "w") as f:
        f.write(self.html)

    with open(temp_img, "wb") as f:
        args = [
            "--enable-logging",
            "--disable-gpu",
            "--headless",
            "--no-sandbox"
            ]

        if self.ss_width and self.ss_height:
            args.append(f"--window-size={self.ss_width},{self.ss_height}")

        args += [
            "--hide-scrollbars",
            f"--screenshot={str(temp_img)}",
            str(temp_html)
            ]

        subprocess.run(executable=self.chrome_path, args=args)

    with open(temp_img, 'rb') as f:
        img_bytes = f.read()

    buffer = io.BytesIO(img_bytes)
    img = mimage.imread(buffer)
    return self.possibly_enlarge(img)

Screenshot.take_screenshot = take_screenshot_override

This argument needed to be added "--no-sandbox"

zer0blockchain avatar Apr 29 '21 21:04 zer0blockchain

which file exactly?

QuatschFisch avatar Apr 30 '21 13:04 QuatschFisch

this is a monkey patch, you just need to run this before you call the export function. it's patching the take_screenshot function of Screenshot

from dataframe_image._screenshot import Screenshot - I am hesitant to commit this change back to the library but if a contributor wants to more deeply understand the --no-sandbox flag please feel free

zer0blockchain avatar Apr 30 '21 14:04 zer0blockchain

@zer0blockchain can you please make this commit to the main repo? Doing a monkey patch is messy and I am trying not to clutter my code a lot

taharushain avatar Jun 13 '21 09:06 taharushain

What worked for me on a ubuntu container was to install chrome, I had installed chromium before which is a requirement for PIL but that didn't solve the problem, having the official chrome package worked.

wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

taharushain avatar Jun 13 '21 09:06 taharushain

There is no official chrome for arm devices. So it wouldnt work on my Raspberry Pi 4

QuatschFisch avatar Jun 13 '21 09:06 QuatschFisch

Here's what I did to fix on ubuntu...Already mentioned here but i'll provide more steps.

install latest version of chrome - https://tecadmin.net/install-google-chrome-in-ubuntu/

image Then do there here to your chrome - vi usr/bin/google-chrome-stable - to get there and edit

You should be able to open chrome now on ubuntu...

Now it ran without an issue - dfi.export(df, "df_styled.png")

andrewkenreich avatar Jul 09 '21 03:07 andrewkenreich

@zer0blockchain can you please make this commit to the main repo? Doing a monkey patch is messy and I am trying not to clutter my code a lot

@zer0blockchain , Is there a simpler approach to get dfi.export(pandas_dataframe, table_conversion='chrome') working on ubuntu/docker? (This is the last piece that I need for the app I'm building...)

GitHunter0 avatar Aug 25 '21 03:08 GitHunter0

Running as root without --no-sandbox is not supported. So, try to add this argument to function which calling chrome.

sulaxd avatar May 25 '22 15:05 sulaxd

any update on this? facing same issue with docker!

dharmendrakariya avatar Jul 18 '22 17:07 dharmendrakariya

Hi, Facing the same problem when running the program using the ubuntu systemd service

can you help me out with the issue?

Vedvund avatar Aug 24 '22 04:08 Vedvund

Looks like @zer0blockchain's patch has been added to master:

https://github.com/dexplo/dataframe_image/blob/ff1fa4853c480cda1021229e009cdd6e0740c915/dataframe_image/_screenshot.py#L110-L130

Works for me on headless Ubuntu 22.04LTS

g-simmons avatar Dec 03 '22 00:12 g-simmons

What worked for me on a ubuntu container was to install chrome, I had installed chromium before which is a requirement for PIL but that didn't solve the problem, having the official chrome package worked.

wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

Thanks, this helped me too on ubuntu

jekeam avatar Dec 16 '22 15:12 jekeam

resolved by update dataframe-image-0.1.1 to dataframe-image-0.1.5

ATcn avatar Jan 16 '23 02:01 ATcn

@Jbiloki @PaleNeutron

This issue can be closed, right? --no-sandbox has already been merged and deployed.

buckyster avatar Jan 18 '23 17:01 buckyster

I do not know why but --no-sandbox has been commented out https://github.com/dexplo/dataframe_image/commit/40f0d8f18e4ce3e6012682ff8120b566aeca059c. I am facing the same issue with dataframe-image==0.1.11.

muupan avatar Aug 01 '23 08:08 muupan

@muupan See https://github.com/dexplo/dataframe_image/blob/f4787e1676145f8eb47dd299dc2a0104b64b4058/dataframe_image/_screenshot.py#L130-L131 , --no-sandbox is added only with root. Normal user do not need this and will lead to problem.

PaleNeutron avatar Aug 06 '23 01:08 PaleNeutron

@PaleNeutron

I missed that conditional --no-sandbox, thanks. Now I understand why it has been commented out.

However, I still needed --no-sandbox to make it work as a non-root user when I used the library inside a kubernetes container. I guess that is because it is inside a container as explained in https://docs.travis-ci.com/user/chrome#sandboxing. If always adding --no-sandbox is not a good idea, how about adding an option to force --no-sandbox or an additional condition that checks if it is inside a container?

muupan avatar Aug 06 '23 02:08 muupan

@muupan , maybe you could use root user in container to avoid this problem now, and I'll consider how to deal with this problem.

PaleNeutron avatar Aug 09 '23 09:08 PaleNeutron

@PaleNeutron Thanks! My workaround for now is to make an executable shell script like google-chrome --no-sandbox "$@" and specify the chrome_path argument of dataframe_image.export to it.

muupan avatar Aug 09 '23 10:08 muupan