Skip to content

Commit 94c76ba

Browse files
committed
Add support matplotlib using plot component (with example and docs)
1 parent f21155f commit 94c76ba

File tree

16 files changed

+453
-3
lines changed

16 files changed

+453
-3
lines changed

build_defs/defaults.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ THIRD_PARTY_PY_LIBCST = [
8181
requirement("libcst"),
8282
]
8383

84+
THIRD_PARTY_PY_MATPLOTLIB = [
85+
requirement("matplotlib"),
86+
]
87+
8488
THIRD_PARTY_PY_PYDANTIC = [
8589
requirement("pydantic"),
8690
]

build_defs/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ mkdocstrings[python]
77
pydantic==1.10
88
--no-binary pydantic
99
libcst==1.1.0
10+
11+
matplotlib # only used for example

build_defs/requirements_lock.txt

Lines changed: 348 additions & 1 deletion
Large diffs are not rendered by default.

docs/components/plot.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Overview
2+
3+
Plot provides a convenient way to render [Matplotlib](https://matplotlib.org/) figures as an image.
4+
5+
## Examples
6+
7+
```python
8+
--8<-- "mesop/examples/integrations/matplotlib.py"
9+
```
10+
11+
## API
12+
13+
::: mesop.components.plot.plot.plot

mesop/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ py_library(
2222
"//mesop/components/audio:py",
2323
"//mesop/components/image:py",
2424
"//mesop/components/slider:py",
25+
"//mesop/components/plot:py",
2526
"//mesop/components/select:py",
2627
"//mesop/components/radio:py",
2728
"//mesop/components/slide_toggle:py",

mesop/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
from mesop.components.input.input import input as input
5656
from mesop.components.input.input import textarea as textarea
5757
from mesop.components.markdown.markdown import markdown as markdown
58+
from mesop.components.plot.plot import (
59+
plot as plot,
60+
)
5861
from mesop.components.progress_bar.progress_bar import (
5962
progress_bar as progress_bar,
6063
)

mesop/cli/BUILD

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//build_defs:defaults.bzl", "THIRD_PARTY_PY_ABSL_PY", "THIRD_PARTY_PY_PYTEST", "py_binary", "py_library", "py_test")
1+
load("//build_defs:defaults.bzl", "THIRD_PARTY_PY_ABSL_PY", "THIRD_PARTY_PY_MATPLOTLIB", "THIRD_PARTY_PY_PYTEST", "py_binary", "py_library", "py_test")
22

33
package(
44
default_visibility = ["//build_defs:mesop_internal"],
@@ -13,7 +13,7 @@ COMMON_DEPS = [
1313
"//mesop", # Keep dep to ensure the entire Mesop library is loaded.
1414
"//mesop/exceptions",
1515
"//mesop/runtime",
16-
] + THIRD_PARTY_PY_ABSL_PY
16+
] + THIRD_PARTY_PY_ABSL_PY + THIRD_PARTY_PY_MATPLOTLIB # Used for /examples
1717

1818
exports_files(["cli.py"])
1919

mesop/components/plot/BUILD

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
load("//build_defs:defaults.bzl", "py_library")
2+
3+
package(
4+
default_visibility = ["//build_defs:mesop_internal"],
5+
)
6+
7+
py_library(
8+
name = "py",
9+
srcs = glob(["*.py"]),
10+
deps = ["//mesop/components/image:py"],
11+
)

mesop/components/plot/__init__.py

Whitespace-only changes.

mesop/components/plot/plot.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import base64
2+
from io import BytesIO
3+
from typing import Protocol
4+
5+
from mesop.component_helpers import Style, component
6+
from mesop.components.image.image import image
7+
8+
9+
class Figure(Protocol):
10+
"""
11+
Provides a minimal interface based on matplotlib's Figure class.
12+
"""
13+
14+
def savefig(self, fname: BytesIO, *, format: str):
15+
pass
16+
17+
18+
@component
19+
def plot(figure: Figure, *, style: Style | None = None):
20+
"""
21+
Creates a plot component from a Matplotlib figure.
22+
23+
Args:
24+
figure: A [Matplotlib figure](https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure) which will be rendered.
25+
style: An optional Style object that defines the visual styling for the
26+
plot component. If None, default styling (e.g. height, width) is used.
27+
"""
28+
buf = BytesIO()
29+
figure.savefig(buf, format="png")
30+
data = base64.b64encode(buf.getbuffer()).decode("ascii")
31+
image(src=f"data:image/png;base64,{data}", style=style)

0 commit comments

Comments
 (0)