├── .python-version ├── src └── reflex_plot │ ├── __init__.py │ └── core.py ├── static └── screenshot.png ├── .gitignore ├── .github └── workflows │ ├── test.yaml │ └── publish.yaml ├── LICENSE ├── pyproject.toml ├── README.md └── tests ├── test_plot.py └── test_pandas_backend.py /.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /src/reflex_plot/__init__.py: -------------------------------------------------------------------------------- 1 | from .core import plot 2 | -------------------------------------------------------------------------------- /static/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucianosrp/reflex-plot/HEAD/static/screenshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.py[cod] 3 | .coverage 4 | htmlcov 5 | .web 6 | __pycache__/ 7 | assets/external/ 8 | reflex-plot-example 9 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | uv-example: 10 | strategy: 11 | matrix: 12 | python-version: ["3.9", "3.10", "3.11", "3.12"] 13 | os: [windows-latest, ubuntu-latest] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Install uv 19 | uses: astral-sh/setup-uv@v3 20 | 21 | - name: Install the project 22 | run: uv sync --all-extras --dev 23 | 24 | - name: Run tests 25 | # For example, using `pytest` 26 | run: uv run pytest tests 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Luciano 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. 22 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy: 20 | runs-on: ubuntu-latest 21 | environment: production 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Set up Python 26 | uses: actions/setup-python@v3 27 | with: 28 | python-version: "3.x" 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install build 33 | - name: Build package 34 | run: python -m build 35 | - name: Publish package 36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "reflex-plot" 3 | version = "0.1.0" 4 | description = "Plot your dataframe with reflex!" 5 | authors = [ 6 | { name = "Luciano Scarpulla", email = "66913960+lucianosrp@users.noreply.github.com" }, 7 | ] 8 | readme = "README.md" 9 | requires-python = ">=3.9" 10 | dependencies = [ 11 | "reflex>=0.5.9", 12 | "pandas>=2.0.0", 13 | "narwhals>=1.25.2", 14 | ] 15 | classifiers = [ 16 | "Programming Language :: Python :: 3", 17 | "License :: OSI Approved :: MIT License", 18 | "Operating System :: OS Independent", 19 | ] 20 | 21 | keywords = ["reflex-plot", "pandas", "reflex", "dashboard", "plotting"] 22 | 23 | [project.urls] 24 | source = "https://github.com/lucianosrp/reflex-plot" 25 | 26 | [build-system] 27 | requires = ["hatchling"] 28 | build-backend = "hatchling.build" 29 | 30 | [tool.uv] 31 | dev-dependencies = [ 32 | "inline-snapshot>=0.13.3", 33 | "pytest-coverage>=0.0", 34 | "pytest>=8.3.2", 35 | "mypy>=1.15.0", 36 | ] 37 | 38 | [tool.hatch.build] 39 | exclude = ["/.*", "/docs", "/tests", "/examples", "reflex-plot-example"] 40 | 41 | [tool.hatch.build.targets.wheel] 42 | packages = ["src/reflex_plot"] 43 | 44 | [tool.pytest.ini_options] 45 | addopts = "--cov=src --cov-fail-under=100" 46 | 47 | [project.entry-points.pandas_plotting_backends] 48 | reflex = "reflex_plot" 49 | -------------------------------------------------------------------------------- /src/reflex_plot/core.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Literal, Optional 2 | 3 | import narwhals as nw 4 | import reflex as rx 5 | from narwhals.typing import IntoDataFrame 6 | 7 | 8 | def plot( 9 | df: IntoDataFrame, 10 | kind: Literal["line", "area", "bar"], 11 | x: str, 12 | y: str, 13 | xlabel: Optional[str] = None, 14 | ylabel: Optional[str] = None, 15 | grid: bool = False, 16 | tool_tip: bool = False, 17 | heigth: int = 300, 18 | width: str = "100%", 19 | margin: Dict[str, int] = dict(left=60, bottom=60), 20 | ) -> rx.Component: 21 | df = nw.from_native(df) 22 | data = df.rows(named=True) 23 | components = [ 24 | getattr(rx.recharts, kind)(data_key=y), 25 | rx.recharts.x_axis(x or xlabel, label=dict(value=x, position="bottom")), 26 | rx.recharts.y_axis( 27 | y or ylabel, label=dict(value=y, position="left", angle=-90) 28 | ), 29 | ] 30 | 31 | if grid: 32 | components.append( 33 | rx.recharts.cartesian_grid(stroke_dasharray="4 4"), 34 | ) 35 | 36 | if tool_tip: 37 | components.append(rx.recharts.graphing_tooltip()) 38 | 39 | return getattr(rx.recharts, f"{kind}_chart")( 40 | *components, 41 | data=data, 42 | width=width, 43 | height=heigth, 44 | margin=margin, 45 | ) 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reflex-plot 2 | Seamlessly plot dataframes in _Reflex_ just like you would do with Matplotlib. 3 | 4 | ![](./static/screenshot.png) 5 | 6 | You can import `plot` from `reflex_plot` to get a Rechart component. 7 | 8 | ```python 9 | import random 10 | from typing import Literal 11 | 12 | import pandas as pd 13 | import reflex as rx 14 | from reflex_plot import plot 15 | 16 | def plot_data(kind: Literal["line", "area", "bar"]) -> rx.Component: 17 | df = pd.DataFrame( 18 | { 19 | "category": list(range(20)), 20 | "value": [random.randint(0, 1000) for _ in range(20)], 21 | } 22 | ) 23 | return plot( 24 | df, 25 | kind=kind, 26 | x="category", 27 | y="value", 28 | grid=True, 29 | tool_tip=True, 30 | ) 31 | ``` 32 | ## Plot _any_ DataFrame 33 | Using [Narwhals](https://github.com/narwhals-dev/narwhals) under the hood, `reflex-plot` supports plotting from any DataFrame library including Pandas, Polars, and Dask. The `plot()` function accepts any DataFrame type and seamlessly converts it to a Recharts component. 34 | 35 | ```python 36 | import polars as pl 37 | import pandas as pd 38 | import dask.dataframe as dd 39 | 40 | # These all work the same way 41 | df_pd = pd.DataFrame({"x": [1,2,3], "y": [4,5,6]}) 42 | df_pl = pl.DataFrame({"x": [1,2,3], "y": [4,5,6]}) 43 | df_dd = dd.from_pandas(df_pd) 44 | 45 | plot(df_pd, kind="line", x="x", y="y") 46 | plot(df_pl, kind="line", x="x", y="y") 47 | plot(df_dd, kind="line", x="x", y="y") 48 | ``` 49 | 50 | 51 | ## Pandas plotting backend 52 | 53 | You can also set `reflex_plot` as the default backend for pandas and use `DataFrame.plot` as you would do with Matplotlib 54 | 55 | 56 | ```python 57 | pd.set_option("plotting.backend", "reflex_plot") 58 | 59 | 60 | def plot_data(kind: Literal["line", "area", "bar"]) -> rx.Component: 61 | df = pd.DataFrame( 62 | { 63 | "category": list(range(20)), 64 | "value": [random.randint(0, 1000) for _ in range(20)], 65 | } 66 | ) 67 | return df.plot( 68 | kind=kind, 69 | x="category", 70 | y="value", 71 | grid=True, 72 | tool_tip=True, 73 | ) 74 | 75 | ``` 76 | 77 | ## How to install 78 | ``` 79 | pip install reflex-plot 80 | ``` 81 | 82 | ## Charts type covered 83 | - [x] Line 84 | - [x] Area 85 | - [x] Bar 86 | -------------------------------------------------------------------------------- /tests/test_plot.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from inline_snapshot import snapshot 3 | 4 | from reflex_plot.core import plot 5 | 6 | 7 | def test_bar_plot(): 8 | df = pd.DataFrame({"a": [1, 2], "b": [10, 0]}) 9 | chart = plot( 10 | df, 11 | kind="bar", 12 | x="a", 13 | y="b", 14 | grid=True, 15 | tool_tip=True, 16 | ).render() 17 | 18 | assert chart == snapshot( 19 | { 20 | "name": "RechartsResponsiveContainer", 21 | "props": [ 22 | "height={300}", 23 | "width={`100%`}", 24 | ], 25 | "contents": "", 26 | "args": None, 27 | "special_props": set(), 28 | "children": [ 29 | { 30 | "name": "RechartsBarChart", 31 | "props": [ 32 | "barCategoryGap={`10%`}", 33 | "barGap={4}", 34 | 'data={[{"a": 1, "b": 10}, {"a": 2, "b": 0}]}', 35 | "height={`100%`}", 36 | 'margin={{"left": 60, "bottom": 60}}', 37 | "width={`100%`}", 38 | ], 39 | "contents": "", 40 | "args": None, 41 | "special_props": set(), 42 | "children": [ 43 | { 44 | "name": "RechartsBar", 45 | "props": ["dataKey={`b`}", "fill={`var(--accent-9)`}"], 46 | "contents": "", 47 | "args": None, 48 | "special_props": set(), 49 | "children": [], 50 | "autofocus": False, 51 | }, 52 | { 53 | "name": "RechartsXAxis", 54 | "props": [ 55 | "includeHidden={false}", 56 | 'label={{"value": "a", "position": "bottom"}}', 57 | "stroke={`var(--gray-9)`}", 58 | "tickLine={false}", 59 | ], 60 | "contents": "", 61 | "args": None, 62 | "special_props": set(), 63 | "children": [ 64 | { 65 | "name": "", 66 | "props": [], 67 | "contents": "{`a`}", 68 | "args": None, 69 | "special_props": set(), 70 | "children": [], 71 | "autofocus": False, 72 | } 73 | ], 74 | "autofocus": False, 75 | }, 76 | { 77 | "name": "RechartsYAxis", 78 | "props": [ 79 | 'label={{"value": "b", "position": "left", "angle": -90}}', 80 | "stroke={`var(--gray-9)`}", 81 | "tickLine={false}", 82 | ], 83 | "contents": "", 84 | "args": None, 85 | "special_props": set(), 86 | "children": [ 87 | { 88 | "name": "", 89 | "props": [], 90 | "contents": "{`b`}", 91 | "args": None, 92 | "special_props": set(), 93 | "children": [], 94 | "autofocus": False, 95 | } 96 | ], 97 | "autofocus": False, 98 | }, 99 | { 100 | "name": "RechartsCartesianGrid", 101 | "props": [ 102 | "stroke={`var(--gray-7)`}", 103 | "strokeDasharray={`4 4`}", 104 | ], 105 | "contents": "", 106 | "args": None, 107 | "special_props": set(), 108 | "children": [], 109 | "autofocus": False, 110 | }, 111 | { 112 | "name": "RechartsTooltip", 113 | "props": [ 114 | 'allowEscapeViewBox={{"x": false, "y": false}}', 115 | 'contentStyle={{"background": "var(--gray-1)", "borderColor": "var(--gray-4)", "borderRadius": "8px"}}', 116 | 'cursor={{"strokeWidth": 1, "fill": "var(--gray-3)"}}', 117 | 'itemStyle={{"color": "var(--gray-12)"}}', 118 | 'labelStyle={{"color": "var(--gray-11)"}}', 119 | ], 120 | "contents": "", 121 | "args": None, 122 | "special_props": set(), 123 | "children": [], 124 | "autofocus": False, 125 | }, 126 | ], 127 | "autofocus": False, 128 | } 129 | ], 130 | "autofocus": False, 131 | } 132 | ) 133 | 134 | 135 | def test_line_plot(): 136 | df = pd.DataFrame({"a": [1, 2], "b": [10, 0]}) 137 | chart = plot(df, kind="line", x="a", y="b").render() 138 | 139 | assert chart == snapshot( 140 | { 141 | "name": "RechartsResponsiveContainer", 142 | "props": [ 143 | "height={300}", 144 | "width={`100%`}", 145 | ], 146 | "contents": "", 147 | "args": None, 148 | "special_props": set(), 149 | "children": [ 150 | { 151 | "name": "RechartsLineChart", 152 | "props": [ 153 | 'data={[{"a": 1, "b": 10}, {"a": 2, "b": 0}]}', 154 | "height={`100%`}", 155 | 'margin={{"left": 60, "bottom": 60}}', 156 | "width={`100%`}", 157 | ], 158 | "contents": "", 159 | "args": None, 160 | "special_props": set(), 161 | "children": [ 162 | { 163 | "name": "RechartsLine", 164 | "props": [ 165 | 'activeDot={{"stroke": "var(--accent-2)", "fill": "var(--accent-10)"}}', 166 | "dataKey={`b`}", 167 | 'dot={{"stroke": "var(--accent-10)", "fill": "var(--accent-4)"}}', 168 | "stroke={`var(--accent-9)`}", 169 | ], 170 | "contents": "", 171 | "args": None, 172 | "special_props": set(), 173 | "children": [], 174 | "autofocus": False, 175 | }, 176 | { 177 | "name": "RechartsXAxis", 178 | "props": [ 179 | "includeHidden={false}", 180 | 'label={{"value": "a", "position": "bottom"}}', 181 | "stroke={`var(--gray-9)`}", 182 | "tickLine={false}", 183 | ], 184 | "contents": "", 185 | "args": None, 186 | "special_props": set(), 187 | "children": [ 188 | { 189 | "name": "", 190 | "props": [], 191 | "contents": "{`a`}", 192 | "args": None, 193 | "special_props": set(), 194 | "children": [], 195 | "autofocus": False, 196 | } 197 | ], 198 | "autofocus": False, 199 | }, 200 | { 201 | "name": "RechartsYAxis", 202 | "props": [ 203 | 'label={{"value": "b", "position": "left", "angle": -90}}', 204 | "stroke={`var(--gray-9)`}", 205 | "tickLine={false}", 206 | ], 207 | "contents": "", 208 | "args": None, 209 | "special_props": set(), 210 | "children": [ 211 | { 212 | "name": "", 213 | "props": [], 214 | "contents": "{`b`}", 215 | "args": None, 216 | "special_props": set(), 217 | "children": [], 218 | "autofocus": False, 219 | } 220 | ], 221 | "autofocus": False, 222 | }, 223 | ], 224 | "autofocus": False, 225 | } 226 | ], 227 | "autofocus": False, 228 | } 229 | ) 230 | 231 | 232 | def test_area_plot(): 233 | df = pd.DataFrame({"a": [1, 2], "b": [10, 0]}) 234 | chart = plot(df, kind="area", x="a", y="b").render() 235 | 236 | assert chart == snapshot( 237 | { 238 | "name": "RechartsResponsiveContainer", 239 | "props": [ 240 | "height={300}", 241 | "width={`100%`}", 242 | ], 243 | "contents": "", 244 | "args": None, 245 | "special_props": set(), 246 | "children": [ 247 | { 248 | "name": "RechartsAreaChart", 249 | "props": [ 250 | 'data={[{"a": 1, "b": 10}, {"a": 2, "b": 0}]}', 251 | "height={`100%`}", 252 | 'margin={{"left": 60, "bottom": 60}}', 253 | "width={`100%`}", 254 | ], 255 | "contents": "", 256 | "args": None, 257 | "special_props": set(), 258 | "children": [ 259 | { 260 | "name": "RechartsArea", 261 | "props": [ 262 | 'activeDot={{"stroke": "var(--accent-2)", "fill": "var(--accent-10)"}}', 263 | "dataKey={`b`}", 264 | "fill={`var(--accent-5)`}", 265 | "stroke={`var(--accent-9)`}", 266 | "strokeWidth={1}", 267 | "type={`monotone`}", 268 | ], 269 | "contents": "", 270 | "args": None, 271 | "special_props": set(), 272 | "children": [], 273 | "autofocus": False, 274 | }, 275 | { 276 | "name": "RechartsXAxis", 277 | "props": [ 278 | "includeHidden={false}", 279 | 'label={{"value": "a", "position": "bottom"}}', 280 | "stroke={`var(--gray-9)`}", 281 | "tickLine={false}", 282 | ], 283 | "contents": "", 284 | "args": None, 285 | "special_props": set(), 286 | "children": [ 287 | { 288 | "name": "", 289 | "props": [], 290 | "contents": "{`a`}", 291 | "args": None, 292 | "special_props": set(), 293 | "children": [], 294 | "autofocus": False, 295 | } 296 | ], 297 | "autofocus": False, 298 | }, 299 | { 300 | "name": "RechartsYAxis", 301 | "props": [ 302 | 'label={{"value": "b", "position": "left", "angle": -90}}', 303 | "stroke={`var(--gray-9)`}", 304 | "tickLine={false}", 305 | ], 306 | "contents": "", 307 | "args": None, 308 | "special_props": set(), 309 | "children": [ 310 | { 311 | "name": "", 312 | "props": [], 313 | "contents": "{`b`}", 314 | "args": None, 315 | "special_props": set(), 316 | "children": [], 317 | "autofocus": False, 318 | } 319 | ], 320 | "autofocus": False, 321 | }, 322 | ], 323 | "autofocus": False, 324 | } 325 | ], 326 | "autofocus": False, 327 | } 328 | ) 329 | -------------------------------------------------------------------------------- /tests/test_pandas_backend.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from inline_snapshot import snapshot 3 | 4 | pd.set_option("plotting.backend", "reflex_plot") 5 | 6 | 7 | def test_bar_chart(): 8 | df = pd.DataFrame({"a": [1, 2], "b": [10, 0]}) 9 | pandas_chart = df.plot( 10 | kind="bar", 11 | x="a", 12 | y="b", 13 | grid=True, 14 | tool_tip=True, 15 | ).render() 16 | assert pandas_chart == snapshot( 17 | { 18 | "name": "RechartsResponsiveContainer", 19 | "props": ["height={300}", "width={`100%`}"], 20 | "contents": "", 21 | "args": None, 22 | "special_props": set(), 23 | "children": [ 24 | { 25 | "name": "RechartsBarChart", 26 | "props": [ 27 | "barCategoryGap={`10%`}", 28 | "barGap={4}", 29 | 'data={[{"a": 1, "b": 10}, {"a": 2, "b": 0}]}', 30 | "height={`100%`}", 31 | 'margin={{"left": 60, "bottom": 60}}', 32 | "width={`100%`}", 33 | ], 34 | "contents": "", 35 | "args": None, 36 | "special_props": set(), 37 | "children": [ 38 | { 39 | "name": "RechartsBar", 40 | "props": [ 41 | "dataKey={`b`}", 42 | "fill={`var(--accent-9)`}", 43 | ], 44 | "contents": "", 45 | "args": None, 46 | "special_props": set(), 47 | "children": [], 48 | "autofocus": False, 49 | }, 50 | { 51 | "name": "RechartsXAxis", 52 | "props": [ 53 | "includeHidden={false}", 54 | 'label={{"value": "a", "position": "bottom"}}', 55 | "stroke={`var(--gray-9)`}", 56 | "tickLine={false}", 57 | ], 58 | "contents": "", 59 | "args": None, 60 | "special_props": set(), 61 | "children": [ 62 | { 63 | "name": "", 64 | "props": [], 65 | "contents": "{`a`}", 66 | "args": None, 67 | "special_props": set(), 68 | "children": [], 69 | "autofocus": False, 70 | } 71 | ], 72 | "autofocus": False, 73 | }, 74 | { 75 | "name": "RechartsYAxis", 76 | "props": [ 77 | 'label={{"value": "b", "position": "left", "angle": -90}}', 78 | "stroke={`var(--gray-9)`}", 79 | "tickLine={false}", 80 | ], 81 | "contents": "", 82 | "args": None, 83 | "special_props": set(), 84 | "children": [ 85 | { 86 | "name": "", 87 | "props": [], 88 | "contents": "{`b`}", 89 | "args": None, 90 | "special_props": set(), 91 | "children": [], 92 | "autofocus": False, 93 | } 94 | ], 95 | "autofocus": False, 96 | }, 97 | { 98 | "name": "RechartsCartesianGrid", 99 | "props": [ 100 | "stroke={`var(--gray-7)`}", 101 | "strokeDasharray={`4 4`}", 102 | ], 103 | "contents": "", 104 | "args": None, 105 | "special_props": set(), 106 | "children": [], 107 | "autofocus": False, 108 | }, 109 | { 110 | "name": "RechartsTooltip", 111 | "props": [ 112 | 'allowEscapeViewBox={{"x": false, "y": false}}', 113 | 'contentStyle={{"background": "var(--gray-1)", "borderColor": "var(--gray-4)", "borderRadius": "8px"}}', 114 | 'cursor={{"strokeWidth": 1, "fill": "var(--gray-3)"}}', 115 | 'itemStyle={{"color": "var(--gray-12)"}}', 116 | 'labelStyle={{"color": "var(--gray-11)"}}', 117 | ], 118 | "contents": "", 119 | "args": None, 120 | "special_props": set(), 121 | "children": [], 122 | "autofocus": False, 123 | }, 124 | ], 125 | "autofocus": False, 126 | } 127 | ], 128 | "autofocus": False, 129 | } 130 | ) 131 | 132 | 133 | def test_line_chart(): 134 | import pandas as pd 135 | 136 | df = pd.DataFrame({"a": [1, 2], "b": [10, 0]}) 137 | pandas_chart = df.plot(kind="line", x="a", y="b").render() 138 | assert pandas_chart == snapshot( 139 | { 140 | "name": "RechartsResponsiveContainer", 141 | "props": ["height={300}", "width={`100%`}"], 142 | "contents": "", 143 | "args": None, 144 | "special_props": set(), 145 | "children": [ 146 | { 147 | "name": "RechartsLineChart", 148 | "props": [ 149 | 'data={[{"a": 1, "b": 10}, {"a": 2, "b": 0}]}', 150 | "height={`100%`}", 151 | 'margin={{"left": 60, "bottom": 60}}', 152 | "width={`100%`}", 153 | ], 154 | "contents": "", 155 | "args": None, 156 | "special_props": set(), 157 | "children": [ 158 | { 159 | "name": "RechartsLine", 160 | "props": [ 161 | 'activeDot={{"stroke": "var(--accent-2)", "fill": "var(--accent-10)"}}', 162 | "dataKey={`b`}", 163 | 'dot={{"stroke": "var(--accent-10)", "fill": "var(--accent-4)"}}', 164 | "stroke={`var(--accent-9)`}", 165 | ], 166 | "contents": "", 167 | "args": None, 168 | "special_props": set(), 169 | "children": [], 170 | "autofocus": False, 171 | }, 172 | { 173 | "name": "RechartsXAxis", 174 | "props": [ 175 | "includeHidden={false}", 176 | 'label={{"value": "a", "position": "bottom"}}', 177 | "stroke={`var(--gray-9)`}", 178 | "tickLine={false}", 179 | ], 180 | "contents": "", 181 | "args": None, 182 | "special_props": set(), 183 | "children": [ 184 | { 185 | "name": "", 186 | "props": [], 187 | "contents": "{`a`}", 188 | "args": None, 189 | "special_props": set(), 190 | "children": [], 191 | "autofocus": False, 192 | } 193 | ], 194 | "autofocus": False, 195 | }, 196 | { 197 | "name": "RechartsYAxis", 198 | "props": [ 199 | 'label={{"value": "b", "position": "left", "angle": -90}}', 200 | "stroke={`var(--gray-9)`}", 201 | "tickLine={false}", 202 | ], 203 | "contents": "", 204 | "args": None, 205 | "special_props": set(), 206 | "children": [ 207 | { 208 | "name": "", 209 | "props": [], 210 | "contents": "{`b`}", 211 | "args": None, 212 | "special_props": set(), 213 | "children": [], 214 | "autofocus": False, 215 | } 216 | ], 217 | "autofocus": False, 218 | }, 219 | ], 220 | "autofocus": False, 221 | } 222 | ], 223 | "autofocus": False, 224 | } 225 | ) 226 | 227 | 228 | def test_area_chart(): 229 | import pandas as pd 230 | 231 | df = pd.DataFrame({"a": [1, 2], "b": [10, 0]}) 232 | pandas_chart = df.plot(kind="area", x="a", y="b").render() 233 | assert pandas_chart == snapshot( 234 | { 235 | "name": "RechartsResponsiveContainer", 236 | "props": ["height={300}", "width={`100%`}"], 237 | "contents": "", 238 | "args": None, 239 | "special_props": set(), 240 | "children": [ 241 | { 242 | "name": "RechartsAreaChart", 243 | "props": [ 244 | 'data={[{"a": 1, "b": 10}, {"a": 2, "b": 0}]}', 245 | "height={`100%`}", 246 | 'margin={{"left": 60, "bottom": 60}}', 247 | "width={`100%`}", 248 | ], 249 | "contents": "", 250 | "args": None, 251 | "special_props": set(), 252 | "children": [ 253 | { 254 | "name": "RechartsArea", 255 | "props": [ 256 | 'activeDot={{"stroke": "var(--accent-2)", "fill": "var(--accent-10)"}}', 257 | "dataKey={`b`}", 258 | "fill={`var(--accent-5)`}", 259 | "stroke={`var(--accent-9)`}", 260 | "strokeWidth={1}", 261 | "type={`monotone`}", 262 | ], 263 | "contents": "", 264 | "args": None, 265 | "special_props": set(), 266 | "children": [], 267 | "autofocus": False, 268 | }, 269 | { 270 | "name": "RechartsXAxis", 271 | "props": [ 272 | "includeHidden={false}", 273 | 'label={{"value": "a", "position": "bottom"}}', 274 | "stroke={`var(--gray-9)`}", 275 | "tickLine={false}", 276 | ], 277 | "contents": "", 278 | "args": None, 279 | "special_props": set(), 280 | "children": [ 281 | { 282 | "name": "", 283 | "props": [], 284 | "contents": "{`a`}", 285 | "args": None, 286 | "special_props": set(), 287 | "children": [], 288 | "autofocus": False, 289 | } 290 | ], 291 | "autofocus": False, 292 | }, 293 | { 294 | "name": "RechartsYAxis", 295 | "props": [ 296 | 'label={{"value": "b", "position": "left", "angle": -90}}', 297 | "stroke={`var(--gray-9)`}", 298 | "tickLine={false}", 299 | ], 300 | "contents": "", 301 | "args": None, 302 | "special_props": set(), 303 | "children": [ 304 | { 305 | "name": "", 306 | "props": [], 307 | "contents": "{`b`}", 308 | "args": None, 309 | "special_props": set(), 310 | "children": [], 311 | "autofocus": False, 312 | } 313 | ], 314 | "autofocus": False, 315 | }, 316 | ], 317 | "autofocus": False, 318 | } 319 | ], 320 | "autofocus": False, 321 | } 322 | ) 323 | --------------------------------------------------------------------------------