Skip to content

DO NOT MERGE: Patch WebAgg backend for pyodide #29568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ianthomas23
Copy link
Member

This is the branch used to prepare pyodide PR pyodide/pyodide#5398 to patch the Matplotlib webagg backend for use in pyodide. It is here in the form of a (never to be merged) PR so that it is easy to look at the differences in a split view. Note most of the changes are removals, followed by mock websockets on both the Python and JavaScript sides.

import tornado.web
import tornado.ioloop
import tornado.websocket
from js import document

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't support matplotlib in Node.js anyways, but importing document in Node.js or other Node.js-like environments will fail.

def open(self, fignum):
self.js_web_socket.open(create_proxy(self.on_message)) # should destroy proxy on close/exit?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it is better to destroy the proxy after use to prevent memory leaks. However, it should be ensured that the destroyed proxy is not accessed after its destruction.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, so:

Suggested change
self.js_web_socket.open(create_proxy(self.on_message)) # should destroy proxy on close/exit?
self.on_message_proxy = create_proxy(self.on_message)
self.js_web_socket.open(self.on_message_proxy) # should destroy proxy on close/exit?

and then presumably in on_close we'd add self.on_message_proxy.destroy().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 55117ee.


WebAggApplication.start()
js_fig = run_js(js_code)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


def on_close(self):
self.manager.remove_web_socket(self)

def on_message(self, message):
message = json.loads(message)
message = message.as_py_json()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, assuming that we get a JavaScript JSON object (mix of arrays, objects, numbers, strings, and bools) as input.

Comment on lines +294 to +304
element.setAttribute(
"href",
"data:{};base64,{}".format(
mimetype, base64.b64encode(data.getvalue()).decode("ascii")
),
)
element.setAttribute("download", f"plot{figure_id}.{format}")
element.style.display = "none"
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have sworn there was a better way to do this by now. But maybe not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied this from matplotlib-pyodide. There must be a better way, I need to investigate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't found a better way of doing this yet, so I am leaving it as it is for the moment.

Comment on lines 32 to 33
content = content.toJs();
blob = new Blob([content]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's probably a way to do this with fewer copies.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a better way using content.getBuffer() in 55117ee.

@ianthomas23
Copy link
Member Author

Thanks for the comments @ryanking13 and @hoodmane. I'm concluding that there isn't anything fundamentally wrong here and I will continue to work on it next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants