pyodide / matplotlib-pyodide

HTML5 backends for Matplotlib compatible with Pyodide
Mozilla Public License 2.0
33 stars 9 forks source link

AttributeError: 'TimerWasm' object has no attribute '_timer' #46

Open sadukie opened 10 months ago

sadukie commented 10 months ago

Problem

Another community member and I were trying to see if Matplotlib's animation.FuncAnimation would work in PyScript using this Matplotlib demo.

We ran into the following error:

AttributeError: 'TimerWasm' object has no attribute '_timer'

The code is available here on PyScript.com.

More Details

Here's the stack trace of the error:

Traceback (most recent call last):
  File "/lib/python311.zip/_pyodide/_base.py", line 499, in eval_code
    .run(globals, locals)
     ^^^^^^^^^^^^^^^^^^^^
  File "/lib/python311.zip/_pyodide/_base.py", line 340, in run
    coroutine = eval(self.code, globals, locals)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<exec>", line 78, in <module>
  File "/lib/python3.11/site-packages/matplotlib/animation.py", line 1634, in __init__
    super().__init__(fig, **kwargs)
  File "/lib/python3.11/site-packages/matplotlib/animation.py", line 1395, in __init__
    event_source = fig.canvas.new_timer(interval=self._interval)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/matplotlib_pyodide/browser_backend.py", line 416, in new_timer
    return TimerWasm(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/matplotlib/backend_bases.py", line 1097, in __init__
    self.interval = 1000 if interval is None else interval
    ^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/matplotlib/backend_bases.py", line 1139, in interval
    self._timer_set_interval()
  File "/lib/python3.11/site-packages/matplotlib_pyodide/browser_backend.py", line 510, in _timer_set_interval
    if self._timer is not None:
       ^^^^^^^^^^^
AttributeError: 'TimerWasm' object has no attribute '_timer'
ryanking13 commented 10 months ago

Thanks for the report! It seems like there was a _timer attribute in TimerBase object in old matplotlib versions but it has been removed. So the TimerWasm object would need to be updated to be compatible with newer matplotlib versions.

Currently, no Pyodide maintainers are actively maintaining matplotlib-pyodide project, and AFAIK none of them have deep knowledge of matplotlib. Therefore, it would be great if people with knowledge of matplotlib could help resolve this issue.

sadukie commented 10 months ago

Ah... I see....

ryanking13 commented 10 months ago

Thanks for the check. Maybe we can remove the self._timer attribute from the TimerWasm object, if it is not used in TimerBase at all... but I think we don't have a test case so I am not sure what would be the side effect of it .

jburgy commented 1 day ago

I managed to circumvent the immediate issue by adding

from matplotlib_pyodide.browser_backend import TimerWasm

class Timer(TimerWasm):
    def __init__(self, interval=None):
        self._timer = None
        super().__init__(interval=interval)

and injecting that new implementation to FunctionAnimation via the event_source=Timer(interval=30) parameter. Unfortunately, only the axes and labels render, no animation! You can see the result on PyScript.com

@sadukie @ryanking13 any idea?