reflex-monocharts 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reflex_monocharts-0.1.1/LICENSE +21 -0
- reflex_monocharts-0.1.1/PKG-INFO +235 -0
- reflex_monocharts-0.1.1/README.md +204 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/__init__.py +221 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/card.py +329 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/__init__.py +8 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/_common.py +107 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/areas.py +281 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/bars.py +504 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/layout.py +967 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/lines.py +416 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/points.py +216 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/charts/polar.py +716 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/data.py +303 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/py.typed +0 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/theme.py +161 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts/tooltip.py +123 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts.egg-info/PKG-INFO +235 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts.egg-info/SOURCES.txt +23 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts.egg-info/dependency_links.txt +1 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts.egg-info/requires.txt +10 -0
- reflex_monocharts-0.1.1/custom_components/reflex_monocharts.egg-info/top_level.txt +1 -0
- reflex_monocharts-0.1.1/pyproject.toml +74 -0
- reflex_monocharts-0.1.1/setup.cfg +4 -0
- reflex_monocharts-0.1.1/tests/test_charts.py +66 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ernesto Crespo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reflex-monocharts
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Monochromatic, rounded chart cards for Reflex - a Python port of the Monocharts design system built on rx.recharts.
|
|
5
|
+
Author-email: Ernesto Crespo <ecrespo@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ecrespo/reflex-monocharts
|
|
8
|
+
Project-URL: Source, https://github.com/ecrespo/reflex-monocharts
|
|
9
|
+
Project-URL: Issues, https://github.com/ecrespo/reflex-monocharts/issues
|
|
10
|
+
Keywords: reflex,reflex-custom-components,charts,recharts,monocharts,dataviz
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: reflex>=0.9.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build; extra == "dev"
|
|
24
|
+
Requires-Dist: twine; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
28
|
+
Requires-Dist: bandit[toml]>=1.7; extra == "dev"
|
|
29
|
+
Requires-Dist: pip-audit>=2.7; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# reflex-monocharts
|
|
33
|
+
|
|
34
|
+
Monochromatic, rounded chart cards for [Reflex](https://reflex.dev) — a pure-Python
|
|
35
|
+
port of the [Monocharts](https://github.com/Subhan-code/Monocharts) design system.
|
|
36
|
+
|
|
37
|
+
28 components: splines, pill bars, gradient areas, donuts, radars, radial gauges,
|
|
38
|
+
bullet targets, treemaps, heatmaps, candlesticks, Sankey bands and a GitHub-style
|
|
39
|
+
contribution grid. All one hue, all rounded, dark and light.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install reflex-monocharts
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+

|
|
47
|
+
|
|
48
|
+
## Why a port and not a wrapper
|
|
49
|
+
|
|
50
|
+
Monocharts ships as copy-paste React/TSX built on Recharts and Tailwind, with the
|
|
51
|
+
data hard-coded in each component. Reflex already wraps Recharts, so this library
|
|
52
|
+
rebuilds the *design system* in Python instead of shipping JavaScript:
|
|
53
|
+
|
|
54
|
+
- **No npm dependency and no Tailwind requirement.** Every class is translated to
|
|
55
|
+
Reflex style props, so the cards drop into any Reflex app unchanged.
|
|
56
|
+
- **Data-driven.** Each chart takes `data` plus `*_key` arguments and binds to
|
|
57
|
+
`rx.State`. Call it with no arguments and you get the original demo card.
|
|
58
|
+
- **Reactive theming.** `theme=` accepts `"dark"`, `"light"`, or a state Var, so a
|
|
59
|
+
toggle re-themes every card without a reload. `compact=` works the same way.
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import reflex as rx
|
|
65
|
+
from reflex_monocharts import monocharts as mc
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class State(rx.State):
|
|
69
|
+
theme: str = "dark"
|
|
70
|
+
traffic: list[dict] = [
|
|
71
|
+
{"hour": "02:00", "hits": 18},
|
|
72
|
+
{"hour": "06:00", "hits": 34},
|
|
73
|
+
{"hour": "10:00", "hits": 72},
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
@rx.event
|
|
77
|
+
def toggle_theme(self):
|
|
78
|
+
self.theme = "light" if self.theme == "dark" else "dark"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def index() -> rx.Component:
|
|
82
|
+
return rx.vstack(
|
|
83
|
+
rx.button("Toggle theme", on_click=State.toggle_theme),
|
|
84
|
+
mc.area(
|
|
85
|
+
State.traffic,
|
|
86
|
+
x_key="hour",
|
|
87
|
+
value_key="hits",
|
|
88
|
+
theme=State.theme,
|
|
89
|
+
title="Traffic",
|
|
90
|
+
badge="Live",
|
|
91
|
+
unit="requests",
|
|
92
|
+
),
|
|
93
|
+
mc.gauge(84, theme=State.theme),
|
|
94
|
+
width="420px",
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Long names are available too — `mc.area` is `mono_rounded_area_chart`.
|
|
99
|
+
|
|
100
|
+
## The catalog
|
|
101
|
+
|
|
102
|
+
| Short name | Function | What it draws |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `mc.line` | `mono_rounded_line_chart` | Spline with a dashed baseline series |
|
|
105
|
+
| `mc.step` | `mono_rounded_step_chart` | Discrete staircase |
|
|
106
|
+
| `mc.sparkline` | `mono_rounded_sparkline_chart` | Stacked telemetry rows with micro splines |
|
|
107
|
+
| `mc.kpi` | `mono_rounded_kpi_card_chart` | Big KPI over a gradient sparkline |
|
|
108
|
+
| `mc.bar` | `mono_rounded_bar_chart` | Pill bars, as columns or rows |
|
|
109
|
+
| `mc.stacked_bar` | `mono_rounded_stacked_bar_chart` | Tonal stack with rounded ends |
|
|
110
|
+
| `mc.composed` | `mono_rounded_composed_chart` | Outlined columns plus a spline |
|
|
111
|
+
| `mc.waterfall` | `mono_rounded_waterfall_chart` | Floating delta pillars |
|
|
112
|
+
| `mc.funnel` | `mono_rounded_funnel_chart` | Horizontal pipeline stages |
|
|
113
|
+
| `mc.bullet` | `mono_rounded_bullet_chart` | Progress bars with benchmark markers |
|
|
114
|
+
| `mc.pyramid` | `mono_rounded_pyramid_chart` | Hierarchy tiers |
|
|
115
|
+
| `mc.candlestick` | `mono_rounded_candlestick_chart` | OHLC candles with rounded wicks |
|
|
116
|
+
| `mc.area` | `mono_rounded_area_chart` | Curved area with a soft gradient |
|
|
117
|
+
| `mc.range` | `mono_rounded_range_chart` | Floating min-max band |
|
|
118
|
+
| `mc.stream` | `mono_rounded_stream_chart` | Two natural-spline waves |
|
|
119
|
+
| `mc.donut` | `mono_rounded_donut_chart` | Donut with rounded caps and a centre readout |
|
|
120
|
+
| `mc.radar` | `mono_rounded_radar_chart` | Multi-axis polygon web |
|
|
121
|
+
| `mc.polar` | `mono_rounded_polar_chart` | 360-degree radial pillars |
|
|
122
|
+
| `mc.radial_group` | `mono_rounded_radial_bar_group` | Half-circle arc group |
|
|
123
|
+
| `mc.radial_gauge` | `mono_rounded_radial_gauge_chart` | Concentric progress rings |
|
|
124
|
+
| `mc.gauge` | `mono_rounded_gauge_arc` | 240-degree speedometer dial |
|
|
125
|
+
| `mc.meter` | `mono_rounded_meter_chart` | Semicircle meter |
|
|
126
|
+
| `mc.scatter` | `mono_rounded_scatter_chart` | Weighted node matrix |
|
|
127
|
+
| `mc.bubble` | `mono_rounded_bubble_chart` | Outlined bubbles, area-encoded |
|
|
128
|
+
| `mc.heatmap` | `mono_rounded_heatmap_chart` | Labelled density matrix |
|
|
129
|
+
| `mc.treemap` | `mono_rounded_treemap_chart` | Rounded partition tiles |
|
|
130
|
+
| `mc.sankey` | `mono_rounded_sankey_chart` | Curved flow bands |
|
|
131
|
+
| `mc.activity` | `mono_activity_heatmap` | Contribution grid (green/blue/purple/mono) |
|
|
132
|
+
|
|
133
|
+
## Common arguments
|
|
134
|
+
|
|
135
|
+
Every chart accepts these, on top of its own `*_key` arguments:
|
|
136
|
+
|
|
137
|
+
| Argument | Meaning |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| `data` | Rows to plot. Omit for the built-in demo dataset. |
|
|
140
|
+
| `theme` | `"dark"`, `"light"`, or a state Var. |
|
|
141
|
+
| `compact` | Short card instead of tall. Accepts a Var. |
|
|
142
|
+
| `title` / `badge` | The uppercase eyebrow and the pill beside it. |
|
|
143
|
+
| `value` / `unit` | The headline metric and its muted suffix. Derived from the data when omitted. |
|
|
144
|
+
| `footer_left` / `footer_right` | The two monospace footer captions. |
|
|
145
|
+
| `control` | A component rendered flush right in the header. |
|
|
146
|
+
| `**props` | Any extra style props, forwarded to the card. |
|
|
147
|
+
|
|
148
|
+
## Interactive controls
|
|
149
|
+
|
|
150
|
+
The originals bake their toggles into the component. Here the option is a prop,
|
|
151
|
+
so it can be wired to your own state — `mono_segmented` renders the matching pill
|
|
152
|
+
control:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from reflex_monocharts import mono_segmented, monocharts as mc
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class State(rx.State):
|
|
159
|
+
curve: str = "monotone"
|
|
160
|
+
|
|
161
|
+
@rx.event
|
|
162
|
+
def set_curve(self, value: str):
|
|
163
|
+
self.curve = value
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
mc.area(
|
|
167
|
+
curve=State.curve,
|
|
168
|
+
control=mono_segmented(
|
|
169
|
+
[("monotone", "Monotone"), ("natural", "Natural")],
|
|
170
|
+
State.curve,
|
|
171
|
+
State.set_curve,
|
|
172
|
+
theme=State.theme,
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The same pattern drives `series=` on the line card, `orientation=` on the bar card
|
|
178
|
+
and `show_trend=` on the hybrid card.
|
|
179
|
+
|
|
180
|
+
## Building your own cards
|
|
181
|
+
|
|
182
|
+
The chrome is exported, so a custom chart can sit in the same system:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from reflex_monocharts import mono_card, mono_header, mono_stage, mono_footer, mono_tooltip
|
|
186
|
+
|
|
187
|
+
mono_card(
|
|
188
|
+
mono_header("My Metric", "Custom", "1,204", "events", theme="dark"),
|
|
189
|
+
mono_stage(my_chart, theme="dark"),
|
|
190
|
+
mono_footer("Left caption", "Right caption", theme="dark"),
|
|
191
|
+
theme="dark",
|
|
192
|
+
)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`ink()`, `ink_alpha()`, `pick()` and `is_dark()` from `reflex_monocharts.theme`
|
|
196
|
+
resolve the monochrome palette for either a plain theme string or a Var.
|
|
197
|
+
|
|
198
|
+
## Notes and deliberate differences
|
|
199
|
+
|
|
200
|
+
- **Badge and footer rule are theme-aware here.** Upstream hard-codes
|
|
201
|
+
`bg-white/10 text-white` and `border-white/5`, which is invisible on the light
|
|
202
|
+
card; this port resolves both per theme.
|
|
203
|
+
- **The tooltip is `rx.recharts.graphing_tooltip`** styled to match the original's
|
|
204
|
+
blurred dark panel. Recharts' `content` render-prop takes a React component,
|
|
205
|
+
which Reflex cannot pass, so the styling is reproduced through
|
|
206
|
+
`content_style` / `item_style` / `label_style`.
|
|
207
|
+
- **Gradients are defined in a hidden sibling `<svg>`** with a process-unique id,
|
|
208
|
+
so several gradient-filled cards can share a page.
|
|
209
|
+
- **`mono_activity_heatmap` seeds its RNG** so the grid is stable across
|
|
210
|
+
re-renders. Pass `seed=None` to `data.activity_contributions` for the original
|
|
211
|
+
random behaviour, and use a native `title` tooltip per cell rather than a
|
|
212
|
+
server round-trip for 140 cells.
|
|
213
|
+
- **`mono_rounded_candlestick_chart` needs explicit `low_bound`/`high_bound`**
|
|
214
|
+
when `data` is a state Var, since the price scale cannot be derived at build
|
|
215
|
+
time. `mono_rounded_sankey_chart` computes its band geometry in Python and
|
|
216
|
+
takes a plain list.
|
|
217
|
+
|
|
218
|
+
## Demo app
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
cd monocharts_demo
|
|
222
|
+
uv run reflex run
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The gallery shows every chart, a live-state section wired to `rx.State`, a theme
|
|
226
|
+
toggle, a compact toggle and a category filter.
|
|
227
|
+
|
|
228
|
+
## Credits
|
|
229
|
+
|
|
230
|
+
Design system by [Syed Subhan](https://github.com/Subhan-code) — see
|
|
231
|
+
[Monocharts](https://github.com/Subhan-code/Monocharts) and
|
|
232
|
+
[amicro](https://amicro.vercel.app/mono-charts). This is an independent Python
|
|
233
|
+
port for Reflex, not affiliated with the original project.
|
|
234
|
+
|
|
235
|
+
MIT licensed.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# reflex-monocharts
|
|
2
|
+
|
|
3
|
+
Monochromatic, rounded chart cards for [Reflex](https://reflex.dev) — a pure-Python
|
|
4
|
+
port of the [Monocharts](https://github.com/Subhan-code/Monocharts) design system.
|
|
5
|
+
|
|
6
|
+
28 components: splines, pill bars, gradient areas, donuts, radars, radial gauges,
|
|
7
|
+
bullet targets, treemaps, heatmaps, candlesticks, Sankey bands and a GitHub-style
|
|
8
|
+
contribution grid. All one hue, all rounded, dark and light.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install reflex-monocharts
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
## Why a port and not a wrapper
|
|
18
|
+
|
|
19
|
+
Monocharts ships as copy-paste React/TSX built on Recharts and Tailwind, with the
|
|
20
|
+
data hard-coded in each component. Reflex already wraps Recharts, so this library
|
|
21
|
+
rebuilds the *design system* in Python instead of shipping JavaScript:
|
|
22
|
+
|
|
23
|
+
- **No npm dependency and no Tailwind requirement.** Every class is translated to
|
|
24
|
+
Reflex style props, so the cards drop into any Reflex app unchanged.
|
|
25
|
+
- **Data-driven.** Each chart takes `data` plus `*_key` arguments and binds to
|
|
26
|
+
`rx.State`. Call it with no arguments and you get the original demo card.
|
|
27
|
+
- **Reactive theming.** `theme=` accepts `"dark"`, `"light"`, or a state Var, so a
|
|
28
|
+
toggle re-themes every card without a reload. `compact=` works the same way.
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import reflex as rx
|
|
34
|
+
from reflex_monocharts import monocharts as mc
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class State(rx.State):
|
|
38
|
+
theme: str = "dark"
|
|
39
|
+
traffic: list[dict] = [
|
|
40
|
+
{"hour": "02:00", "hits": 18},
|
|
41
|
+
{"hour": "06:00", "hits": 34},
|
|
42
|
+
{"hour": "10:00", "hits": 72},
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
@rx.event
|
|
46
|
+
def toggle_theme(self):
|
|
47
|
+
self.theme = "light" if self.theme == "dark" else "dark"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def index() -> rx.Component:
|
|
51
|
+
return rx.vstack(
|
|
52
|
+
rx.button("Toggle theme", on_click=State.toggle_theme),
|
|
53
|
+
mc.area(
|
|
54
|
+
State.traffic,
|
|
55
|
+
x_key="hour",
|
|
56
|
+
value_key="hits",
|
|
57
|
+
theme=State.theme,
|
|
58
|
+
title="Traffic",
|
|
59
|
+
badge="Live",
|
|
60
|
+
unit="requests",
|
|
61
|
+
),
|
|
62
|
+
mc.gauge(84, theme=State.theme),
|
|
63
|
+
width="420px",
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Long names are available too — `mc.area` is `mono_rounded_area_chart`.
|
|
68
|
+
|
|
69
|
+
## The catalog
|
|
70
|
+
|
|
71
|
+
| Short name | Function | What it draws |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `mc.line` | `mono_rounded_line_chart` | Spline with a dashed baseline series |
|
|
74
|
+
| `mc.step` | `mono_rounded_step_chart` | Discrete staircase |
|
|
75
|
+
| `mc.sparkline` | `mono_rounded_sparkline_chart` | Stacked telemetry rows with micro splines |
|
|
76
|
+
| `mc.kpi` | `mono_rounded_kpi_card_chart` | Big KPI over a gradient sparkline |
|
|
77
|
+
| `mc.bar` | `mono_rounded_bar_chart` | Pill bars, as columns or rows |
|
|
78
|
+
| `mc.stacked_bar` | `mono_rounded_stacked_bar_chart` | Tonal stack with rounded ends |
|
|
79
|
+
| `mc.composed` | `mono_rounded_composed_chart` | Outlined columns plus a spline |
|
|
80
|
+
| `mc.waterfall` | `mono_rounded_waterfall_chart` | Floating delta pillars |
|
|
81
|
+
| `mc.funnel` | `mono_rounded_funnel_chart` | Horizontal pipeline stages |
|
|
82
|
+
| `mc.bullet` | `mono_rounded_bullet_chart` | Progress bars with benchmark markers |
|
|
83
|
+
| `mc.pyramid` | `mono_rounded_pyramid_chart` | Hierarchy tiers |
|
|
84
|
+
| `mc.candlestick` | `mono_rounded_candlestick_chart` | OHLC candles with rounded wicks |
|
|
85
|
+
| `mc.area` | `mono_rounded_area_chart` | Curved area with a soft gradient |
|
|
86
|
+
| `mc.range` | `mono_rounded_range_chart` | Floating min-max band |
|
|
87
|
+
| `mc.stream` | `mono_rounded_stream_chart` | Two natural-spline waves |
|
|
88
|
+
| `mc.donut` | `mono_rounded_donut_chart` | Donut with rounded caps and a centre readout |
|
|
89
|
+
| `mc.radar` | `mono_rounded_radar_chart` | Multi-axis polygon web |
|
|
90
|
+
| `mc.polar` | `mono_rounded_polar_chart` | 360-degree radial pillars |
|
|
91
|
+
| `mc.radial_group` | `mono_rounded_radial_bar_group` | Half-circle arc group |
|
|
92
|
+
| `mc.radial_gauge` | `mono_rounded_radial_gauge_chart` | Concentric progress rings |
|
|
93
|
+
| `mc.gauge` | `mono_rounded_gauge_arc` | 240-degree speedometer dial |
|
|
94
|
+
| `mc.meter` | `mono_rounded_meter_chart` | Semicircle meter |
|
|
95
|
+
| `mc.scatter` | `mono_rounded_scatter_chart` | Weighted node matrix |
|
|
96
|
+
| `mc.bubble` | `mono_rounded_bubble_chart` | Outlined bubbles, area-encoded |
|
|
97
|
+
| `mc.heatmap` | `mono_rounded_heatmap_chart` | Labelled density matrix |
|
|
98
|
+
| `mc.treemap` | `mono_rounded_treemap_chart` | Rounded partition tiles |
|
|
99
|
+
| `mc.sankey` | `mono_rounded_sankey_chart` | Curved flow bands |
|
|
100
|
+
| `mc.activity` | `mono_activity_heatmap` | Contribution grid (green/blue/purple/mono) |
|
|
101
|
+
|
|
102
|
+
## Common arguments
|
|
103
|
+
|
|
104
|
+
Every chart accepts these, on top of its own `*_key` arguments:
|
|
105
|
+
|
|
106
|
+
| Argument | Meaning |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| `data` | Rows to plot. Omit for the built-in demo dataset. |
|
|
109
|
+
| `theme` | `"dark"`, `"light"`, or a state Var. |
|
|
110
|
+
| `compact` | Short card instead of tall. Accepts a Var. |
|
|
111
|
+
| `title` / `badge` | The uppercase eyebrow and the pill beside it. |
|
|
112
|
+
| `value` / `unit` | The headline metric and its muted suffix. Derived from the data when omitted. |
|
|
113
|
+
| `footer_left` / `footer_right` | The two monospace footer captions. |
|
|
114
|
+
| `control` | A component rendered flush right in the header. |
|
|
115
|
+
| `**props` | Any extra style props, forwarded to the card. |
|
|
116
|
+
|
|
117
|
+
## Interactive controls
|
|
118
|
+
|
|
119
|
+
The originals bake their toggles into the component. Here the option is a prop,
|
|
120
|
+
so it can be wired to your own state — `mono_segmented` renders the matching pill
|
|
121
|
+
control:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from reflex_monocharts import mono_segmented, monocharts as mc
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class State(rx.State):
|
|
128
|
+
curve: str = "monotone"
|
|
129
|
+
|
|
130
|
+
@rx.event
|
|
131
|
+
def set_curve(self, value: str):
|
|
132
|
+
self.curve = value
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
mc.area(
|
|
136
|
+
curve=State.curve,
|
|
137
|
+
control=mono_segmented(
|
|
138
|
+
[("monotone", "Monotone"), ("natural", "Natural")],
|
|
139
|
+
State.curve,
|
|
140
|
+
State.set_curve,
|
|
141
|
+
theme=State.theme,
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The same pattern drives `series=` on the line card, `orientation=` on the bar card
|
|
147
|
+
and `show_trend=` on the hybrid card.
|
|
148
|
+
|
|
149
|
+
## Building your own cards
|
|
150
|
+
|
|
151
|
+
The chrome is exported, so a custom chart can sit in the same system:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from reflex_monocharts import mono_card, mono_header, mono_stage, mono_footer, mono_tooltip
|
|
155
|
+
|
|
156
|
+
mono_card(
|
|
157
|
+
mono_header("My Metric", "Custom", "1,204", "events", theme="dark"),
|
|
158
|
+
mono_stage(my_chart, theme="dark"),
|
|
159
|
+
mono_footer("Left caption", "Right caption", theme="dark"),
|
|
160
|
+
theme="dark",
|
|
161
|
+
)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`ink()`, `ink_alpha()`, `pick()` and `is_dark()` from `reflex_monocharts.theme`
|
|
165
|
+
resolve the monochrome palette for either a plain theme string or a Var.
|
|
166
|
+
|
|
167
|
+
## Notes and deliberate differences
|
|
168
|
+
|
|
169
|
+
- **Badge and footer rule are theme-aware here.** Upstream hard-codes
|
|
170
|
+
`bg-white/10 text-white` and `border-white/5`, which is invisible on the light
|
|
171
|
+
card; this port resolves both per theme.
|
|
172
|
+
- **The tooltip is `rx.recharts.graphing_tooltip`** styled to match the original's
|
|
173
|
+
blurred dark panel. Recharts' `content` render-prop takes a React component,
|
|
174
|
+
which Reflex cannot pass, so the styling is reproduced through
|
|
175
|
+
`content_style` / `item_style` / `label_style`.
|
|
176
|
+
- **Gradients are defined in a hidden sibling `<svg>`** with a process-unique id,
|
|
177
|
+
so several gradient-filled cards can share a page.
|
|
178
|
+
- **`mono_activity_heatmap` seeds its RNG** so the grid is stable across
|
|
179
|
+
re-renders. Pass `seed=None` to `data.activity_contributions` for the original
|
|
180
|
+
random behaviour, and use a native `title` tooltip per cell rather than a
|
|
181
|
+
server round-trip for 140 cells.
|
|
182
|
+
- **`mono_rounded_candlestick_chart` needs explicit `low_bound`/`high_bound`**
|
|
183
|
+
when `data` is a state Var, since the price scale cannot be derived at build
|
|
184
|
+
time. `mono_rounded_sankey_chart` computes its band geometry in Python and
|
|
185
|
+
takes a plain list.
|
|
186
|
+
|
|
187
|
+
## Demo app
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
cd monocharts_demo
|
|
191
|
+
uv run reflex run
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The gallery shows every chart, a live-state section wired to `rx.State`, a theme
|
|
195
|
+
toggle, a compact toggle and a category filter.
|
|
196
|
+
|
|
197
|
+
## Credits
|
|
198
|
+
|
|
199
|
+
Design system by [Syed Subhan](https://github.com/Subhan-code) — see
|
|
200
|
+
[Monocharts](https://github.com/Subhan-code/Monocharts) and
|
|
201
|
+
[amicro](https://amicro.vercel.app/mono-charts). This is an independent Python
|
|
202
|
+
port for Reflex, not affiliated with the original project.
|
|
203
|
+
|
|
204
|
+
MIT licensed.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Monocharts for Reflex.
|
|
2
|
+
|
|
3
|
+
A Python port of the Monocharts design system: 28 monochromatic, rounded chart
|
|
4
|
+
cards built on ``rx.recharts`` and Reflex layout primitives, with no npm
|
|
5
|
+
dependency and no Tailwind requirement.
|
|
6
|
+
|
|
7
|
+
Every chart is a plain function returning an ``rx.Component``. Called with no
|
|
8
|
+
arguments it renders the original demo card; pass ``data`` (and the matching
|
|
9
|
+
``*_key`` arguments) to bind it to your own state.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
```python
|
|
13
|
+
import reflex as rx
|
|
14
|
+
from reflex_monocharts import monocharts
|
|
15
|
+
|
|
16
|
+
class State(rx.State):
|
|
17
|
+
theme: str = "dark"
|
|
18
|
+
traffic: list[dict] = [{"label": "Jan", "value": 24}]
|
|
19
|
+
|
|
20
|
+
def index() -> rx.Component:
|
|
21
|
+
return monocharts.line(
|
|
22
|
+
State.traffic, value_key="value", secondary_key=None, theme=State.theme
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from types import SimpleNamespace
|
|
30
|
+
|
|
31
|
+
from . import data
|
|
32
|
+
from .card import (
|
|
33
|
+
FONT_MONO,
|
|
34
|
+
FONT_SANS,
|
|
35
|
+
mono_card,
|
|
36
|
+
mono_footer,
|
|
37
|
+
mono_header,
|
|
38
|
+
mono_segmented,
|
|
39
|
+
mono_stage,
|
|
40
|
+
)
|
|
41
|
+
from .charts.areas import (
|
|
42
|
+
mono_rounded_area_chart,
|
|
43
|
+
mono_rounded_range_chart,
|
|
44
|
+
mono_rounded_stream_chart,
|
|
45
|
+
)
|
|
46
|
+
from .charts.bars import (
|
|
47
|
+
mono_rounded_bar_chart,
|
|
48
|
+
mono_rounded_composed_chart,
|
|
49
|
+
mono_rounded_funnel_chart,
|
|
50
|
+
mono_rounded_stacked_bar_chart,
|
|
51
|
+
mono_rounded_waterfall_chart,
|
|
52
|
+
)
|
|
53
|
+
from .charts.layout import (
|
|
54
|
+
mono_activity_heatmap,
|
|
55
|
+
mono_rounded_bullet_chart,
|
|
56
|
+
mono_rounded_candlestick_chart,
|
|
57
|
+
mono_rounded_heatmap_chart,
|
|
58
|
+
mono_rounded_pyramid_chart,
|
|
59
|
+
mono_rounded_sankey_chart,
|
|
60
|
+
mono_rounded_treemap_chart,
|
|
61
|
+
)
|
|
62
|
+
from .charts.lines import (
|
|
63
|
+
mono_rounded_kpi_card_chart,
|
|
64
|
+
mono_rounded_line_chart,
|
|
65
|
+
mono_rounded_sparkline_chart,
|
|
66
|
+
mono_rounded_step_chart,
|
|
67
|
+
)
|
|
68
|
+
from .charts.points import mono_rounded_bubble_chart, mono_rounded_scatter_chart
|
|
69
|
+
from .charts.polar import (
|
|
70
|
+
mono_rounded_donut_chart,
|
|
71
|
+
mono_rounded_gauge_arc,
|
|
72
|
+
mono_rounded_meter_chart,
|
|
73
|
+
mono_rounded_polar_chart,
|
|
74
|
+
mono_rounded_radar_chart,
|
|
75
|
+
mono_rounded_radial_bar_group,
|
|
76
|
+
mono_rounded_radial_gauge_chart,
|
|
77
|
+
)
|
|
78
|
+
from .theme import (
|
|
79
|
+
ACCENT,
|
|
80
|
+
CARD_DARK,
|
|
81
|
+
CARD_LIGHT,
|
|
82
|
+
INK_DARK,
|
|
83
|
+
INK_LIGHT,
|
|
84
|
+
STAGE_DARK,
|
|
85
|
+
STAGE_LIGHT,
|
|
86
|
+
ThemeLike,
|
|
87
|
+
ink,
|
|
88
|
+
ink_alpha,
|
|
89
|
+
is_dark,
|
|
90
|
+
pick,
|
|
91
|
+
)
|
|
92
|
+
from .tooltip import mono_gradient, mono_tooltip
|
|
93
|
+
|
|
94
|
+
__version__ = "0.1.1"
|
|
95
|
+
|
|
96
|
+
#: Short aliases, so a whole dashboard reads as ``monocharts.line(...)``.
|
|
97
|
+
monocharts = SimpleNamespace(
|
|
98
|
+
activity=mono_activity_heatmap,
|
|
99
|
+
area=mono_rounded_area_chart,
|
|
100
|
+
bar=mono_rounded_bar_chart,
|
|
101
|
+
bubble=mono_rounded_bubble_chart,
|
|
102
|
+
bullet=mono_rounded_bullet_chart,
|
|
103
|
+
candlestick=mono_rounded_candlestick_chart,
|
|
104
|
+
composed=mono_rounded_composed_chart,
|
|
105
|
+
donut=mono_rounded_donut_chart,
|
|
106
|
+
funnel=mono_rounded_funnel_chart,
|
|
107
|
+
gauge=mono_rounded_gauge_arc,
|
|
108
|
+
heatmap=mono_rounded_heatmap_chart,
|
|
109
|
+
kpi=mono_rounded_kpi_card_chart,
|
|
110
|
+
line=mono_rounded_line_chart,
|
|
111
|
+
meter=mono_rounded_meter_chart,
|
|
112
|
+
polar=mono_rounded_polar_chart,
|
|
113
|
+
pyramid=mono_rounded_pyramid_chart,
|
|
114
|
+
radar=mono_rounded_radar_chart,
|
|
115
|
+
radial_gauge=mono_rounded_radial_gauge_chart,
|
|
116
|
+
radial_group=mono_rounded_radial_bar_group,
|
|
117
|
+
range=mono_rounded_range_chart,
|
|
118
|
+
sankey=mono_rounded_sankey_chart,
|
|
119
|
+
scatter=mono_rounded_scatter_chart,
|
|
120
|
+
sparkline=mono_rounded_sparkline_chart,
|
|
121
|
+
stacked_bar=mono_rounded_stacked_bar_chart,
|
|
122
|
+
step=mono_rounded_step_chart,
|
|
123
|
+
stream=mono_rounded_stream_chart,
|
|
124
|
+
treemap=mono_rounded_treemap_chart,
|
|
125
|
+
waterfall=mono_rounded_waterfall_chart,
|
|
126
|
+
# chrome
|
|
127
|
+
card=mono_card,
|
|
128
|
+
header=mono_header,
|
|
129
|
+
stage=mono_stage,
|
|
130
|
+
footer=mono_footer,
|
|
131
|
+
segmented=mono_segmented,
|
|
132
|
+
tooltip=mono_tooltip,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
#: Every chart function, in catalog order - handy for building a gallery.
|
|
136
|
+
ALL_CHARTS = (
|
|
137
|
+
mono_activity_heatmap,
|
|
138
|
+
mono_rounded_line_chart,
|
|
139
|
+
mono_rounded_bar_chart,
|
|
140
|
+
mono_rounded_area_chart,
|
|
141
|
+
mono_rounded_donut_chart,
|
|
142
|
+
mono_rounded_composed_chart,
|
|
143
|
+
mono_rounded_scatter_chart,
|
|
144
|
+
mono_rounded_candlestick_chart,
|
|
145
|
+
mono_rounded_kpi_card_chart,
|
|
146
|
+
mono_rounded_pyramid_chart,
|
|
147
|
+
mono_rounded_radial_bar_group,
|
|
148
|
+
mono_rounded_gauge_arc,
|
|
149
|
+
mono_rounded_bullet_chart,
|
|
150
|
+
mono_rounded_sankey_chart,
|
|
151
|
+
mono_rounded_step_chart,
|
|
152
|
+
mono_rounded_stacked_bar_chart,
|
|
153
|
+
mono_rounded_radar_chart,
|
|
154
|
+
mono_rounded_radial_gauge_chart,
|
|
155
|
+
mono_rounded_funnel_chart,
|
|
156
|
+
mono_rounded_heatmap_chart,
|
|
157
|
+
mono_rounded_sparkline_chart,
|
|
158
|
+
mono_rounded_bubble_chart,
|
|
159
|
+
mono_rounded_treemap_chart,
|
|
160
|
+
mono_rounded_stream_chart,
|
|
161
|
+
mono_rounded_meter_chart,
|
|
162
|
+
mono_rounded_waterfall_chart,
|
|
163
|
+
mono_rounded_polar_chart,
|
|
164
|
+
mono_rounded_range_chart,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
__all__ = [
|
|
168
|
+
"ACCENT",
|
|
169
|
+
"ALL_CHARTS",
|
|
170
|
+
"CARD_DARK",
|
|
171
|
+
"CARD_LIGHT",
|
|
172
|
+
"FONT_MONO",
|
|
173
|
+
"FONT_SANS",
|
|
174
|
+
"INK_DARK",
|
|
175
|
+
"INK_LIGHT",
|
|
176
|
+
"STAGE_DARK",
|
|
177
|
+
"STAGE_LIGHT",
|
|
178
|
+
"ThemeLike",
|
|
179
|
+
"__version__",
|
|
180
|
+
"data",
|
|
181
|
+
"ink",
|
|
182
|
+
"ink_alpha",
|
|
183
|
+
"is_dark",
|
|
184
|
+
"mono_activity_heatmap",
|
|
185
|
+
"mono_card",
|
|
186
|
+
"mono_footer",
|
|
187
|
+
"mono_gradient",
|
|
188
|
+
"mono_header",
|
|
189
|
+
"mono_rounded_area_chart",
|
|
190
|
+
"mono_rounded_bar_chart",
|
|
191
|
+
"mono_rounded_bubble_chart",
|
|
192
|
+
"mono_rounded_bullet_chart",
|
|
193
|
+
"mono_rounded_candlestick_chart",
|
|
194
|
+
"mono_rounded_composed_chart",
|
|
195
|
+
"mono_rounded_donut_chart",
|
|
196
|
+
"mono_rounded_funnel_chart",
|
|
197
|
+
"mono_rounded_gauge_arc",
|
|
198
|
+
"mono_rounded_heatmap_chart",
|
|
199
|
+
"mono_rounded_kpi_card_chart",
|
|
200
|
+
"mono_rounded_line_chart",
|
|
201
|
+
"mono_rounded_meter_chart",
|
|
202
|
+
"mono_rounded_polar_chart",
|
|
203
|
+
"mono_rounded_pyramid_chart",
|
|
204
|
+
"mono_rounded_radar_chart",
|
|
205
|
+
"mono_rounded_radial_bar_group",
|
|
206
|
+
"mono_rounded_radial_gauge_chart",
|
|
207
|
+
"mono_rounded_range_chart",
|
|
208
|
+
"mono_rounded_sankey_chart",
|
|
209
|
+
"mono_rounded_scatter_chart",
|
|
210
|
+
"mono_rounded_sparkline_chart",
|
|
211
|
+
"mono_rounded_stacked_bar_chart",
|
|
212
|
+
"mono_rounded_step_chart",
|
|
213
|
+
"mono_rounded_stream_chart",
|
|
214
|
+
"mono_rounded_treemap_chart",
|
|
215
|
+
"mono_rounded_waterfall_chart",
|
|
216
|
+
"mono_segmented",
|
|
217
|
+
"mono_stage",
|
|
218
|
+
"mono_tooltip",
|
|
219
|
+
"monocharts",
|
|
220
|
+
"pick",
|
|
221
|
+
]
|