quarto-ext / shinylive

Quarto extension to embed Shinylive for Python applications
https://quarto-ext.github.io/shinylive/
MIT License
141 stars 7 forks source link

Problem importing opencv in shinylive inside quarto document #14

Open aarontovars opened 1 year ago

aarontovars commented 1 year ago

I am trying to import a package supported by pyodide in shinylive under a quarto document. The main reason is I want to load an image using opencv. Firstly, this code:

#| standalone: true
#| viewerHeight: 420
from shiny import App, render, ui
import numpy as np
import matplotlib.pyplot as plt
import cv2

gives me the following error:

Error starting app! Traceback (most recent call last): File "", line 202, in _start_app File "/lib/python3.10/importlib/init.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1053, in _gcd_import File "", line 1030, in _find_and_load File "", line 1009, in _find_and_load_unlocked File "", line 688, in _load_unlocked File "", line 883, in exec_module File "", line 241, in _call_with_frames_removed File "/home/pyodide/app_4mr6ploxwzzzk07rc0d4/app.py", line 2, in import cv2 ModuleNotFoundError: The module 'opencv-python' is included in the Pyodide distribution, but it is not installed. You can install it by calling: await micropip.install("opencv-python") in Python, or await pyodide.loadPackage("opencv-python") in JavaScript See https://pyodide.org/en/stable/usage/loading-packages.html for more details.

I also tried:

#| standalone: true
#| viewerHeight: 420
from shiny import App, render, ui
import numpy as np
import matplotlib.pyplot as plt
import pyodide_js
await pyodide_js.loadPackage('opencv-python')
import cv2

but this gives me the following error:

Traceback (most recent call last): File "", line 202, in _start_app File "/lib/python3.10/importlib/init.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1053, in _gcd_import File "", line 1030, in _find_and_load File "", line 1009, in _find_and_load_unlocked File "", line 688, in _load_unlocked File "", line 879, in exec_module File "", line 1017, in get_code File "", line 947, in source_to_code File "", line 241, in _call_with_frames_removed File "/home/pyodide/app_4mr6ploxwzzzk07rc0d4/app.py", line 3 await pyodide_js.loadPackage('opencv-python') ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: 'await' outside function

Any hint on how could I successfully load supported packages?

wch commented 1 year ago

Normally shinylive will only copy over the packages needed to run an app, but for some reason it's not detecting that it needs to copy the opencv_python wheel file to the destination directory. If you run

ls docs/site_libs/quarto-contrib/shinylive-0.1.3/shinylive/pyodide/

You'll see that the file is not present there. Even when I add it to a requirements.txt file, it still doesn't copy the wheel file over. I'll look into why this is happening.

wch commented 1 year ago

I merged a fix in the py-shinylive repository. Can you try it out? You can install it with:

pip install https://github.com/rstudio/py-shinylive/tarball/main
aarontovars commented 1 year ago

I still get the exact same error. Which code should I try to make sure it works?

wch commented 1 year ago

Sorry, I wrote a long comment about this yesterday but I must have forgotten to click the "Comment" button.

In summary, the gdal that Pyodide includes is just the compiled C++ library, not the GDAL package (https://pypi.org/project/GDAL/). Pyodide's gdal is a .zip file containing just the gdal.so file; there is no GDAL wheel file.

Pyodide comes with geopandas, which imports fiona, which in turn makes use of the gdal.so library. However, as far as I can tell, it's not possible with Pyodide to install the GDAL python package because there is no wheel file available.

Also, confusingly, the osgeo module is what gets installed when you do pip install GDAL (with normal Python, not Pyodide). Because it's not possible to install GDAL on Pyodide, the osgeo module can't be used.

I suggest filing an issue with Pyodide to see if you can convince them to port it over.

wch commented 1 year ago

Oh man, sorry, my previous comment is about another issue. Disregard, please.

wch commented 1 year ago

I still get the exact same error. Which code should I try to make sure it works?

I tested it locally using a .qmd file that had import cv2, and it worked for me after making the changes

Are you sure that Quarto is using the correct copy of the shinylive python package?

aarontovars commented 1 year ago

Could you please share the .qmd you are using? I am still getting the same error with the new version of shinylive installed using your suggestion: pip install https://github.com/rstudio/py-shinylive/tarball/main

aarontovars commented 1 year ago

Sorry for the misunderstanding. I needed to uninstall the previous version. Now is working perfectly! However, I still have one more doubt.

I am using opencv to read an image (or the moment). However, I cannot directly read the image using im = cv2.imread(path). How can I handle paths using shinylive in quarto?

wch commented 1 year ago

Hi, I added an example that shows three ways of adding data files to a Shinylive app in a Quarto doc.

Live page: https://quarto-ext.github.io/shinylive/load_file.html

Source: https://github.com/quarto-ext/shinylive/blob/main/load_file.qmd

Also see #13, which has a function that makes it easier to embed a directory of files in the Quarto document.

aarontovars commented 1 year ago

I tried the examples you mentioned but I am not able to make it work on my example: I want to plot using matplotlib a .jpeg image located in the same folder as the quarto document. Any suggestion? I would like this code to be as pythonic as possible, since later I want to add more complex features to the app.

aarontovars commented 1 year ago

Any suggestion that can help me? I would really appreciate it. Thanks in advance!