Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 25 additions & 55 deletions examples/rendercanvas.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,13 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"id": "e4f9f67d",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f13251ba883843a39be8a9a6b4e76970",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"RFBOutputContext()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "fecfdbe30cef480da747f15986df29da",
"version_major": 2,
"version_minor": 0
},
"text/html": [
"<div class='snapshot-fecfdbe30cef480da747f15986df29da' style='position:relative;'><img src='data:image/png;base64,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' style='width:640.0px;height:480.0px;' /><div style='position: absolute; top:0; left:0; padding:1px 3px; background: #777; color:#fff; font-size: 90%; font-family:sans-serif; '>snapshot</div></div>"
],
"text/plain": [
"JupyterRenderCanvas(css_height='480.0px', css_width='640.0px')"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"from rendercanvas.utils.cube import setup_drawing_sync\n",
"from rendercanvas.auto import RenderCanvas\n",
"from rendercanvas.jupyter import RenderCanvas\n",
"\n",
"canvas = RenderCanvas(update_mode=\"continuous\")\n",
"draw_frame = setup_drawing_sync(canvas)\n",
Expand All @@ -66,6 +33,17 @@
"canvas"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e9945cb-4541-4df9-968b-ed50b8465e5b",
"metadata": {},
"outputs": [],
"source": [
"# Set title to non-empty string to show the title bar\n",
"canvas.set_title(\"Rotating cube\")"
]
},
{
"cell_type": "markdown",
"id": "749ffb40",
Expand All @@ -76,26 +54,10 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "6d0e64b7-a208-4be6-99eb-9f666ab8c2ae",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "d4b7240a4cbf4b5686ab11c6c1c480eb",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Textarea(value='', rows=10)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"import ipywidgets\n",
"\n",
Expand All @@ -110,6 +72,14 @@
"\n",
"out"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "65f86895-9e9a-4c22-8a54-919bd70fd80b",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand All @@ -128,7 +98,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
"version": "3.14.0"
}
},
"nbformat": 4,
Expand Down
19 changes: 14 additions & 5 deletions rendercanvas/auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
import importlib
from typing import cast
import __main__ as main_module

from .core.coreutils import (
logger,
Expand Down Expand Up @@ -88,8 +89,8 @@ def backends_generator():
"""Generator that iterates over all sub-generators."""
for gen in [
backends_by_env_vars,
backends_by_browser,
backends_by_jupyter,
backends_by_pyodide,
backends_by_notebook,
backends_by_imported_modules,
backends_by_trying_in_order,
]:
Expand Down Expand Up @@ -129,8 +130,16 @@ def get_env_var(*varnames):
yield backend_name, f"{varname} is set"


def backends_by_jupyter():
def backends_by_notebook():
"""Generate backend names that are appropriate for the current Jupyter session (if any)."""

# Detect Marimo: https://github.com/marimo-team/marimo/discussions/8865
try:
_ = main_module.__marimo__
yield "jupyter", "running in Marimo"
except AttributeError:
pass

try:
ip = get_ipython() # type: ignore
except NameError:
Expand Down Expand Up @@ -212,8 +221,8 @@ def backends_by_trying_in_order():
yield backend_name, f"{libname} can be imported"


def backends_by_browser():
"""If python runs in a web browser, we use the pyodide backend."""
def backends_by_pyodide():
"""If python runs inside a web browser, we use the pyodide backend."""
# https://pyodide.org/en/stable/usage/faq.html#how-to-detect-that-code-is-run-with-pyodide
# Technically, we could also be in microPython/RustPython/etc. For now, we only target Pyodide.
if sys.platform == "emscripten":
Expand Down
30 changes: 20 additions & 10 deletions rendercanvas/jupyter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ class JupyterRenderCanvas(BaseRenderCanvas, RemoteFrameBuffer):

_rc_canvas_group = JupyterCanvasGroup(loop)

# Set jupyter_rfb bitmask to use the old-style events. Pygfx assumes these. We will solve this compat issue
# when we refactor rendercanvas event objects.
# In the new events:(event_type -> type, time_stamp -> timestamp, pixel_ratio -> ratio
_event_compatibility = 1

def __init__(self, *args, **kwargs):
# The jupyter backend's default title is empty
kwargs["title"] = kwargs.get("title", "")

super().__init__(*args, **kwargs)

# Internal variables
Expand All @@ -33,6 +41,13 @@ def __init__(self, *args, **kwargs):
self._draw_request_time = 0
self._rendercanvas_event_types = set(EventType)

# The send_frame() method was added in jupyter_rfb 1.0, but it was always there as a private method,
# so we can make it backwards compatible.
try:
self.send_frame # noqa
except AttributeError:
self.send_frame = self._rfb_send_frame

# Set size, title, etc.
self._final_canvas_init()

Expand All @@ -42,7 +57,7 @@ def get_frame(self):
# The result is either a numpy array or None, and this matches
# with what this method is expected to return.
self._time_to_draw()
return self._last_image
return None

# %% Methods to implement RenderCanvas

Expand Down Expand Up @@ -74,18 +89,12 @@ def _rc_request_paint(self):
loop.call_soon(self._time_to_paint)

def _rc_force_paint(self):
# A bit hacky to use the internals of jupyter_rfb this way.
# This pushes frames to the browser as long as the websocket
# buffer permits it. It works!
# But a better way would be `await canvas.wait_draw()`.
# Todo: would also be nice if jupyter_rfb had a public api for this.
array = self._last_image
if array is not None:
self._rfb_send_frame(array)
pass

def _rc_present_bitmap(self, *, data, format, **kwargs):
assert format == "rgba-u8"
self._last_image = np.asarray(data)
self.send_frame(self._last_image)

def _rc_set_logical_size(self, width, height):
self.css_width = f"{width}px"
Expand All @@ -98,7 +107,8 @@ def _rc_get_closed(self):
return self._is_closed

def _rc_set_title(self, title):
pass # not supported yet
self.title = title
self.has_titlebar = bool(title) # show titlebar when a title is set

def _rc_set_cursor(self, cursor):
self.cursor = cursor
Expand Down
Loading