[](https://github.com/pygfx/rendercanvas/actions)
[](https://rendercanvas.readthedocs.io)
[](https://badge.fury.io/py/rendercanvas)
[](https://jacobtomlinson.dev/effver)
# rendercanvas
One canvas API, multiple backends 🚀
<div>
<img width=354 src='https://github.com/user-attachments/assets/42656d13-0d81-47dd-b9c7-d76da8cfa6c1' />
<img width=354 src='https://github.com/user-attachments/assets/af8eefe0-4485-4daf-9fbd-36710e44f07c' />
</div>
*This project is part of [pygfx.org](https://pygfx.org)*
## Introduction
See how the two windows above look the same? That's the idea; they also look the
same to the code that renders to them. Yet, the GUI systems are very different
(Qt vs glfw in this case). Now that's a powerful abstraction!
Coming from `wgpu.gui`? Check [from_wgpu_canvas.md](from_wgpu_canvas.md).
## Purpose
* Provide a generic canvas API to render to.
* Provide an event loop for scheduling events and draws.
* Provide a simple but powerful event system with standardized event objects.
* Provide various canvas implementations:
* One that is light and easily installed (glfw).
* For various GUI libraries (e.g. qt and wx), so visuzalizations can be embedded in a GUI.
* For specific platforms (e.g. Jupyter, browser).
The main use-case is rendering with [wgpu](https://github.com/pygfx/wgpu-py),
but ``rendercanvas``can be used by anything that can render based on a window-id or
by producing bitmap images.
## Installation
```
pip install rendercanvas
```
To have at least one backend, we recommend:
```
pip install rendercanvas glfw
```
## Usage
Also see the [online documentation](https://rendercanvas.readthedocs.io) and the [examples](https://github.com/pygfx/rendercanvas/tree/main/examples).
A minimal example that renders noise:
```py
import numpy as np
from rendercanvas.auto import RenderCanvas, loop
canvas = RenderCanvas(update_mode="continuous")
context = canvas.get_context("bitmap")
@canvas.request_draw
def animate():
w, h = canvas.get_logical_size()
bitmap = np.random.uniform(0, 255, (h, w)).astype(np.uint8)
context.set_bitmap(bitmap)
loop.run()
```
Run wgpu visualizations:
```py
from rendercanvas.auto import RenderCanvas, loop
from rendercanvas.utils.cube import setup_drawing_sync
canvas = RenderCanvas(
title="The wgpu cube example on $backend", update_mode="continuous"
)
draw_frame = setup_drawing_sync(canvas)
canvas.request_draw(draw_frame)
loop.run()
````
Embed in a Qt application:
```py
from PySide6 import QtWidgets
from rendercanvas.qt import QRenderWidget
class Main(QtWidgets.QWidget):
def __init__(self):
super().__init__()
splitter = QtWidgets.QSplitter()
self.canvas = QRenderWidget(splitter)
...
app = QtWidgets.QApplication([])
main = Main()
app.exec()
```
## Async or not async
We support both; a render canvas can be used in a fully async setting using e.g. Asyncio or Trio, or in an event-drived framework like Qt.
If you like callbacks, ``loop.call_later()`` always works. If you like async, use ``loop.add_task()``. Event handlers can always be async.
See the [docs on async](https://rendercanvas.readthedocs.io/stable/start.html#async) for details.
## License
This code is distributed under the 2-clause BSD license.
## Developers
* Clone the repo.
* Install `rendercanvas` and developer deps using `pip install -e .[dev]`.
* Use `ruff format` to apply autoformatting.
* Use `ruff check` to check for linting errors.
* Optionally, if you install [pre-commit](https://github.com/pre-commit/pre-commit/) hooks with `pre-commit install`, lint fixes and formatting will be automatically applied on `git commit`.
* Use `pytest tests` to run the tests.
* Use `pytest examples` to run a subset of the examples.
Raw data
{
"_id": null,
"home_page": null,
"name": "rendercanvas",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "canvas, rendering, graphics, wgpu, qt, wx, glfw, jupyter",
"author": "Almar Klein, Korijn van Golen",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/eb/2e/1f4a5e6ada741a3ce8f539c74b12117bb8d81fe7946fbec397096e13d8a4/rendercanvas-2.0.1.tar.gz",
"platform": null,
"description": "[](https://github.com/pygfx/rendercanvas/actions)\n[](https://rendercanvas.readthedocs.io)\n[](https://badge.fury.io/py/rendercanvas)\n[](https://jacobtomlinson.dev/effver)\n\n\n# rendercanvas\n\nOne canvas API, multiple backends \ud83d\ude80\n\n<div>\n <img width=354 src='https://github.com/user-attachments/assets/42656d13-0d81-47dd-b9c7-d76da8cfa6c1' />\n <img width=354 src='https://github.com/user-attachments/assets/af8eefe0-4485-4daf-9fbd-36710e44f07c' />\n</div>\n\n*This project is part of [pygfx.org](https://pygfx.org)*\n\n\n## Introduction\n\nSee how the two windows above look the same? That's the idea; they also look the\nsame to the code that renders to them. Yet, the GUI systems are very different\n(Qt vs glfw in this case). Now that's a powerful abstraction!\n\nComing from `wgpu.gui`? Check [from_wgpu_canvas.md](from_wgpu_canvas.md).\n\n\n## Purpose\n\n* Provide a generic canvas API to render to.\n* Provide an event loop for scheduling events and draws.\n* Provide a simple but powerful event system with standardized event objects.\n* Provide various canvas implementations:\n * One that is light and easily installed (glfw).\n * For various GUI libraries (e.g. qt and wx), so visuzalizations can be embedded in a GUI.\n * For specific platforms (e.g. Jupyter, browser).\n\n\nThe main use-case is rendering with [wgpu](https://github.com/pygfx/wgpu-py),\nbut ``rendercanvas``can be used by anything that can render based on a window-id or\nby producing bitmap images.\n\n\n## Installation\n\n```\npip install rendercanvas\n```\n\nTo have at least one backend, we recommend:\n```\npip install rendercanvas glfw\n```\n\n## Usage\n\nAlso see the [online documentation](https://rendercanvas.readthedocs.io) and the [examples](https://github.com/pygfx/rendercanvas/tree/main/examples).\n\nA minimal example that renders noise:\n```py\nimport numpy as np\nfrom rendercanvas.auto import RenderCanvas, loop\n\ncanvas = RenderCanvas(update_mode=\"continuous\")\ncontext = canvas.get_context(\"bitmap\")\n\n@canvas.request_draw\ndef animate():\n w, h = canvas.get_logical_size()\n bitmap = np.random.uniform(0, 255, (h, w)).astype(np.uint8)\n context.set_bitmap(bitmap)\n\nloop.run()\n```\n\nRun wgpu visualizations:\n```py\nfrom rendercanvas.auto import RenderCanvas, loop\nfrom rendercanvas.utils.cube import setup_drawing_sync\n\n\ncanvas = RenderCanvas(\n title=\"The wgpu cube example on $backend\", update_mode=\"continuous\"\n)\ndraw_frame = setup_drawing_sync(canvas)\ncanvas.request_draw(draw_frame)\n\nloop.run()\n````\n\nEmbed in a Qt application:\n```py\nfrom PySide6 import QtWidgets\nfrom rendercanvas.qt import QRenderWidget\n\nclass Main(QtWidgets.QWidget):\n\n def __init__(self):\n super().__init__()\n\n splitter = QtWidgets.QSplitter()\n self.canvas = QRenderWidget(splitter)\n ...\n\n\napp = QtWidgets.QApplication([])\nmain = Main()\napp.exec()\n```\n\n## Async or not async\n\nWe support both; a render canvas can be used in a fully async setting using e.g. Asyncio or Trio, or in an event-drived framework like Qt.\nIf you like callbacks, ``loop.call_later()`` always works. If you like async, use ``loop.add_task()``. Event handlers can always be async.\nSee the [docs on async](https://rendercanvas.readthedocs.io/stable/start.html#async) for details.\n\n\n## License\n\nThis code is distributed under the 2-clause BSD license.\n\n\n## Developers\n\n* Clone the repo.\n* Install `rendercanvas` and developer deps using `pip install -e .[dev]`.\n* Use `ruff format` to apply autoformatting.\n* Use `ruff check` to check for linting errors.\n* Optionally, if you install [pre-commit](https://github.com/pre-commit/pre-commit/) hooks with `pre-commit install`, lint fixes and formatting will be automatically applied on `git commit`.\n* Use `pytest tests` to run the tests.\n* Use `pytest examples` to run a subset of the examples.\n\n\n",
"bugtrack_url": null,
"license": null,
"summary": "One canvas API, multiple backends",
"version": "2.0.1",
"project_urls": {
"Documentation": "https://rendercanvas.readthedocs.io",
"Homepage": "https://github.com/pygfx/rendercanvas",
"Repository": "https://github.com/pygfx/rendercanvas"
},
"split_keywords": [
"canvas",
" rendering",
" graphics",
" wgpu",
" qt",
" wx",
" glfw",
" jupyter"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5659eb7b4fc804fd5589d06fe99f31e7d4064519814c0fc1da8af0febea7637f",
"md5": "2b6e0d0752fa5e68c897166833f4af78",
"sha256": "52e364cbda13b3676db868b5932f2f5e4c9e55ba44de526cff725480f6631060"
},
"downloads": -1,
"filename": "rendercanvas-2.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2b6e0d0752fa5e68c897166833f4af78",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 68385,
"upload_time": "2025-01-05T12:45:44",
"upload_time_iso_8601": "2025-01-05T12:45:44.091818Z",
"url": "https://files.pythonhosted.org/packages/56/59/eb7b4fc804fd5589d06fe99f31e7d4064519814c0fc1da8af0febea7637f/rendercanvas-2.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "eb2e1f4a5e6ada741a3ce8f539c74b12117bb8d81fe7946fbec397096e13d8a4",
"md5": "fff2cabfb6793aeb289f77d886f558e1",
"sha256": "d8a4cfe928bf7dd1a64f568d9a84e414b52f6eef5a3b97101d002a3ac173c049"
},
"downloads": -1,
"filename": "rendercanvas-2.0.1.tar.gz",
"has_sig": false,
"md5_digest": "fff2cabfb6793aeb289f77d886f558e1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 56616,
"upload_time": "2025-01-05T12:45:46",
"upload_time_iso_8601": "2025-01-05T12:45:46.236632Z",
"url": "https://files.pythonhosted.org/packages/eb/2e/1f4a5e6ada741a3ce8f539c74b12117bb8d81fe7946fbec397096e13d8a4/rendercanvas-2.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-05 12:45:46",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pygfx",
"github_project": "rendercanvas",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "rendercanvas"
}