echartsy 0.1.0__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.
- echartsy-0.1.0/LICENSE +21 -0
- echartsy-0.1.0/PKG-INFO +636 -0
- echartsy-0.1.0/README.md +596 -0
- echartsy-0.1.0/echartsy/__init__.py +65 -0
- echartsy-0.1.0/echartsy/_config.py +65 -0
- echartsy-0.1.0/echartsy/_helpers.py +215 -0
- echartsy-0.1.0/echartsy/exceptions.py +39 -0
- echartsy-0.1.0/echartsy/figure.py +1491 -0
- echartsy-0.1.0/echartsy/renderers/__init__.py +4 -0
- echartsy-0.1.0/echartsy/renderers/_dispatch.py +61 -0
- echartsy-0.1.0/echartsy/renderers/_html_template.py +298 -0
- echartsy-0.1.0/echartsy/renderers/_jupyter.py +93 -0
- echartsy-0.1.0/echartsy/renderers/_python.py +66 -0
- echartsy-0.1.0/echartsy/renderers/_streamlit.py +100 -0
- echartsy-0.1.0/echartsy/styles.py +68 -0
- echartsy-0.1.0/echartsy/timeline.py +752 -0
- echartsy-0.1.0/echartsy.egg-info/PKG-INFO +636 -0
- echartsy-0.1.0/echartsy.egg-info/SOURCES.txt +21 -0
- echartsy-0.1.0/echartsy.egg-info/dependency_links.txt +1 -0
- echartsy-0.1.0/echartsy.egg-info/requires.txt +20 -0
- echartsy-0.1.0/echartsy.egg-info/top_level.txt +1 -0
- echartsy-0.1.0/pyproject.toml +47 -0
- echartsy-0.1.0/setup.cfg +4 -0
echartsy-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jigar
|
|
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.
|
echartsy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: echartsy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A matplotlib-style fluent builder API for Apache ECharts in Python, Jupyter Notebooks, and Streamlit.
|
|
5
|
+
Author-email: Jigar <astrojigs24@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/astrojigs/echartsy
|
|
8
|
+
Project-URL: Documentation, https://github.com/astrojigs/echartsy#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/astrojigs/echartsy
|
|
10
|
+
Keywords: echarts,visualization,charts,jupyter,plotting
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
21
|
+
Classifier: Framework :: Jupyter
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: pandas>=1.5.0
|
|
26
|
+
Requires-Dist: numpy>=1.23.0
|
|
27
|
+
Provides-Extra: jupyter
|
|
28
|
+
Requires-Dist: ipython>=7.0; extra == "jupyter"
|
|
29
|
+
Provides-Extra: streamlit
|
|
30
|
+
Requires-Dist: streamlit-echarts>=0.4.0; extra == "streamlit"
|
|
31
|
+
Provides-Extra: scipy
|
|
32
|
+
Requires-Dist: scipy>=1.9.0; extra == "scipy"
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: ipython>=7.0; extra == "all"
|
|
35
|
+
Requires-Dist: streamlit-echarts>=0.4.0; extra == "all"
|
|
36
|
+
Requires-Dist: scipy>=1.9.0; extra == "all"
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
39
|
+
Requires-Dist: ipython>=7.0; extra == "dev"
|
|
40
|
+
|
|
41
|
+
<p align="center">
|
|
42
|
+
<img src="https://echarts.apache.org/en/images/logo.png" alt="Apache ECharts" width="70" />
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<h1 align="center">echartsy</h1>
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<em>Interactive charts in Python — the matplotlib workflow, the ECharts experience.</em>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
<a href="https://pypi.org/project/echartsy/"><img src="https://img.shields.io/pypi/v/echartsy?color=%2334d058&label=PyPI" alt="PyPI version" /></a>
|
|
53
|
+
<a href="https://pypi.org/project/echartsy/"><img src="https://img.shields.io/pypi/pyversions/echartsy?color=%2334d058" alt="Python versions" /></a>
|
|
54
|
+
<a href="https://github.com/astrojigs/echartsy/blob/main/LICENSE"><img src="https://img.shields.io/github/license/astrojigs/echartsy?color=blue" alt="License" /></a>
|
|
55
|
+
<a href="https://github.com/astrojigs/echartsy/stargazers"><img src="https://img.shields.io/github/stars/astrojigs/echartsy?style=flat&color=yellow" alt="Stars" /></a>
|
|
56
|
+
<a href="https://github.com/astrojigs/echartsy/issues"><img src="https://img.shields.io/github/issues/astrojigs/echartsy?color=orange" alt="Issues" /></a>
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
<p align="center">
|
|
60
|
+
Build publication-quality interactive charts with a familiar<br/>
|
|
61
|
+
<code>fig = figure()</code> → <code>fig.bar()</code> → <code>fig.show()</code> workflow.<br/>
|
|
62
|
+
Works everywhere: <b>Jupyter</b> · <b>Streamlit</b> · <b>standalone scripts</b>
|
|
63
|
+
</p>
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Why echartsy?
|
|
68
|
+
|
|
69
|
+
- **Feels like matplotlib** — If you know `plt.figure()` / `plt.show()`, you already know 90% of the API. No JSON wrangling, no JavaScript.
|
|
70
|
+
- **Interactive out of the box** — Every chart ships with tooltips, legend toggling, zoom, and a built-in export toolbox. Zero configuration needed.
|
|
71
|
+
- **One library, three engines** — Write once, render in Jupyter notebooks, Streamlit apps, or plain Python scripts that pop open a browser.
|
|
72
|
+
- **Composable & animated** — Layer pies on bar charts, build dual-axis dashboards, or animate any chart across time with `TimelineFigure`.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install echartsy
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Need extras?
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install echartsy[jupyter] # Jupyter Notebook / JupyterLab
|
|
86
|
+
pip install echartsy[streamlit] # Streamlit apps
|
|
87
|
+
pip install echartsy[scipy] # KDE density plots
|
|
88
|
+
pip install echartsy[all] # Everything
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> **Requirements:** Python 3.9+ · pandas ≥ 1.5 · numpy ≥ 1.23
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Quick Start
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import pandas as pd
|
|
99
|
+
import echartsy as ec
|
|
100
|
+
|
|
101
|
+
ec.config(engine="jupyter") # or "python" / "streamlit"
|
|
102
|
+
|
|
103
|
+
df = pd.DataFrame({
|
|
104
|
+
"Fruit": ["Apples", "Bananas", "Cherries", "Dates", "Elderberries"],
|
|
105
|
+
"Sales": [120, 95, 78, 42, 63],
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
fig = ec.figure()
|
|
109
|
+
fig.bar(df, x="Fruit", y="Sales", gradient=True, labels=True)
|
|
110
|
+
fig.title("Fruit Sales")
|
|
111
|
+
fig.show()
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Three lines from DataFrame to interactive chart.
|
|
115
|
+
|
|
116
|
+
<p align="center">
|
|
117
|
+
<img src="assets/demo_bar.png" alt="Quick Start — Bar Chart" width="600" />
|
|
118
|
+
</p>
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Gallery
|
|
123
|
+
|
|
124
|
+
### Cartesian Charts
|
|
125
|
+
|
|
126
|
+
<table>
|
|
127
|
+
<tr>
|
|
128
|
+
<td width="50%">
|
|
129
|
+
<p align="center"><strong>Bar + Pie Overlay</strong></p>
|
|
130
|
+
<p align="center"><img src="assets/demo_bar_pie.png" alt="Bar + Pie Overlay" width="100%" /></p>
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
fig = ec.figure(height="500px")
|
|
134
|
+
fig.bar(df, x="Dept", y="Budget",
|
|
135
|
+
gradient=True, labels=True)
|
|
136
|
+
fig.pie(df, names="Dept", values="Budget",
|
|
137
|
+
center=["82%","25%"],
|
|
138
|
+
radius=["18%","28%"])
|
|
139
|
+
fig.show()
|
|
140
|
+
```
|
|
141
|
+
</td>
|
|
142
|
+
<td width="50%">
|
|
143
|
+
<p align="center"><strong>Smooth Line</strong></p>
|
|
144
|
+
<p align="center"><img src="assets/demo_line.png" alt="Line Chart" width="100%" /></p>
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
fig = ec.figure()
|
|
148
|
+
fig.plot(df, x="Month", y="Sales",
|
|
149
|
+
smooth=True, area=True)
|
|
150
|
+
fig.show()
|
|
151
|
+
```
|
|
152
|
+
</td>
|
|
153
|
+
</tr>
|
|
154
|
+
<tr>
|
|
155
|
+
<td width="50%">
|
|
156
|
+
<p align="center"><strong>Scatter Plot</strong></p>
|
|
157
|
+
<p align="center"><img src="assets/demo_scatter.png" alt="Scatter Plot" width="100%" /></p>
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
fig = ec.figure()
|
|
161
|
+
fig.scatter(df, x="Height", y="Weight",
|
|
162
|
+
color="Gender", size="Age")
|
|
163
|
+
fig.show()
|
|
164
|
+
```
|
|
165
|
+
</td>
|
|
166
|
+
<td width="50%">
|
|
167
|
+
<p align="center"><strong>Grouped Bar</strong></p>
|
|
168
|
+
<p align="center"><img src="assets/demo_grouped.png" alt="Grouped Bar" width="100%" /></p>
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
fig = ec.figure()
|
|
172
|
+
fig.bar(df, x="Quarter", y="Revenue",
|
|
173
|
+
hue="Region")
|
|
174
|
+
fig.show()
|
|
175
|
+
```
|
|
176
|
+
</td>
|
|
177
|
+
</tr>
|
|
178
|
+
<tr>
|
|
179
|
+
<td width="50%">
|
|
180
|
+
<p align="center"><strong>Stacked Bar</strong></p>
|
|
181
|
+
<p align="center"><img src="assets/demo_stacked.png" alt="Stacked Bar" width="100%" /></p>
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
fig = ec.figure()
|
|
185
|
+
fig.bar(df, x="Month", y="Revenue",
|
|
186
|
+
hue="Product", stack=True)
|
|
187
|
+
fig.show()
|
|
188
|
+
```
|
|
189
|
+
</td>
|
|
190
|
+
<td width="50%">
|
|
191
|
+
<p align="center"><strong>Histogram</strong></p>
|
|
192
|
+
<p align="center"><img src="assets/demo_histogram.png" alt="Histogram" width="100%" /></p>
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
fig = ec.figure()
|
|
196
|
+
fig.hist(df, column="Score", bins=20)
|
|
197
|
+
fig.show()
|
|
198
|
+
```
|
|
199
|
+
</td>
|
|
200
|
+
</tr>
|
|
201
|
+
<tr>
|
|
202
|
+
<td width="50%">
|
|
203
|
+
<p align="center"><strong>Area Chart</strong></p>
|
|
204
|
+
<p align="center"><img src="assets/demo_area.png" alt="Area Chart" width="100%" /></p>
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
fig = ec.figure()
|
|
208
|
+
fig.plot(df, x="Month", y="Users",
|
|
209
|
+
area=True, smooth=True)
|
|
210
|
+
fig.show()
|
|
211
|
+
```
|
|
212
|
+
</td>
|
|
213
|
+
<td width="50%">
|
|
214
|
+
<p align="center"><strong>Horizontal Bar</strong></p>
|
|
215
|
+
<p align="center"><img src="assets/demo_horizontal.png" alt="Horizontal Bar" width="100%" /></p>
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
fig = ec.figure()
|
|
219
|
+
fig.bar(df, x="Country", y="Population",
|
|
220
|
+
orient="h")
|
|
221
|
+
fig.show()
|
|
222
|
+
```
|
|
223
|
+
</td>
|
|
224
|
+
</tr>
|
|
225
|
+
<tr>
|
|
226
|
+
<td width="50%">
|
|
227
|
+
<p align="center"><strong>Dual Axis: Bar + Line</strong></p>
|
|
228
|
+
<p align="center"><img src="assets/demo_dual.png" alt="Dual Axis" width="100%" /></p>
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
fig = ec.figure()
|
|
232
|
+
fig.bar(df, x="Month", y="Revenue")
|
|
233
|
+
fig.plot(df, x="Month", y="Growth",
|
|
234
|
+
smooth=True, axis=1)
|
|
235
|
+
fig.ylabel("Revenue ($K)")
|
|
236
|
+
fig.ylabel_right("Growth %")
|
|
237
|
+
fig.show()
|
|
238
|
+
```
|
|
239
|
+
</td>
|
|
240
|
+
<td width="50%">
|
|
241
|
+
<p align="center"><strong>Gradient Bars</strong></p>
|
|
242
|
+
<p align="center"><img src="assets/demo_gradient.png" alt="Gradient Bars" width="100%" /></p>
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
fig = ec.figure()
|
|
246
|
+
fig.bar(df, x="City", y="Temp",
|
|
247
|
+
gradient=True,
|
|
248
|
+
gradient_colors=["#83bff6","#188df0"])
|
|
249
|
+
fig.show()
|
|
250
|
+
```
|
|
251
|
+
</td>
|
|
252
|
+
</tr>
|
|
253
|
+
<tr>
|
|
254
|
+
<td width="50%">
|
|
255
|
+
<p align="center"><strong>Multi-Line with Area</strong></p>
|
|
256
|
+
<p align="center"><img src="assets/demo_multiline.png" alt="Multi-Line" width="100%" /></p>
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
fig = ec.figure()
|
|
260
|
+
fig.plot(df, x="Month", y="Value",
|
|
261
|
+
hue="Series", smooth=True,
|
|
262
|
+
area=True)
|
|
263
|
+
fig.show()
|
|
264
|
+
```
|
|
265
|
+
</td>
|
|
266
|
+
<td width="50%">
|
|
267
|
+
<p align="center"><strong>Boxplot</strong></p>
|
|
268
|
+
<p align="center"><img src="assets/demo_boxplot.png" alt="Boxplot" width="100%" /></p>
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
fig = ec.figure()
|
|
272
|
+
fig.boxplot(df, x="Department", y="Salary")
|
|
273
|
+
fig.show()
|
|
274
|
+
```
|
|
275
|
+
</td>
|
|
276
|
+
</tr>
|
|
277
|
+
</table>
|
|
278
|
+
|
|
279
|
+
### Standalone Charts
|
|
280
|
+
|
|
281
|
+
<table>
|
|
282
|
+
<tr>
|
|
283
|
+
<td width="50%">
|
|
284
|
+
<p align="center"><strong>Donut / Pie</strong></p>
|
|
285
|
+
<p align="center"><img src="assets/demo_pie.png" alt="Donut Chart" width="100%" /></p>
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
fig = ec.figure()
|
|
289
|
+
fig.pie(df, names="Browser", values="Share",
|
|
290
|
+
inner_radius="40%")
|
|
291
|
+
fig.show()
|
|
292
|
+
```
|
|
293
|
+
</td>
|
|
294
|
+
<td width="50%">
|
|
295
|
+
<p align="center"><strong>Radar</strong></p>
|
|
296
|
+
<p align="center"><img src="assets/demo_radar.png" alt="Radar Chart" width="100%" /></p>
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
fig = ec.figure()
|
|
300
|
+
fig.radar(indicators, data,
|
|
301
|
+
series_names=["Warrior","Mage"])
|
|
302
|
+
fig.show()
|
|
303
|
+
```
|
|
304
|
+
</td>
|
|
305
|
+
</tr>
|
|
306
|
+
<tr>
|
|
307
|
+
<td width="50%">
|
|
308
|
+
<p align="center"><strong>Heatmap</strong></p>
|
|
309
|
+
<p align="center"><img src="assets/demo_heatmap.png" alt="Heatmap" width="100%" /></p>
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
fig = ec.figure()
|
|
313
|
+
fig.heatmap(df, x="Day", y="Hour",
|
|
314
|
+
value="Count")
|
|
315
|
+
fig.show()
|
|
316
|
+
```
|
|
317
|
+
</td>
|
|
318
|
+
<td width="50%">
|
|
319
|
+
<p align="center"><strong>Funnel</strong></p>
|
|
320
|
+
<p align="center"><img src="assets/demo_funnel.png" alt="Funnel" width="100%" /></p>
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
fig = ec.figure()
|
|
324
|
+
fig.funnel(df, names="Stage", values="Count")
|
|
325
|
+
fig.show()
|
|
326
|
+
```
|
|
327
|
+
</td>
|
|
328
|
+
</tr>
|
|
329
|
+
<tr>
|
|
330
|
+
<td width="50%">
|
|
331
|
+
<p align="center"><strong>Treemap</strong></p>
|
|
332
|
+
<p align="center"><img src="assets/demo_treemap.png" alt="Treemap" width="100%" /></p>
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
fig = ec.figure()
|
|
336
|
+
fig.treemap(df,
|
|
337
|
+
path=["Category","SubCat"],
|
|
338
|
+
value="Sales")
|
|
339
|
+
fig.show()
|
|
340
|
+
```
|
|
341
|
+
</td>
|
|
342
|
+
<td width="50%">
|
|
343
|
+
<p align="center"><strong>Sankey Diagram</strong></p>
|
|
344
|
+
<p align="center"><img src="assets/demo_sankey.png" alt="Sankey Diagram" width="100%" /></p>
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
fig = ec.figure()
|
|
348
|
+
fig.sankey(df,
|
|
349
|
+
levels=["Source","Channel","Outcome"],
|
|
350
|
+
value="Users")
|
|
351
|
+
fig.show()
|
|
352
|
+
```
|
|
353
|
+
</td>
|
|
354
|
+
</tr>
|
|
355
|
+
</table>
|
|
356
|
+
|
|
357
|
+
### Composite & Dashboard Charts
|
|
358
|
+
|
|
359
|
+
<table>
|
|
360
|
+
<tr>
|
|
361
|
+
<td width="50%">
|
|
362
|
+
<p align="center"><strong>Bar + Pie (Dark)</strong></p>
|
|
363
|
+
<p align="center"><img src="assets/demo_composite_dark.png" alt="Composite Dark" width="100%" /></p>
|
|
364
|
+
</td>
|
|
365
|
+
<td width="50%">
|
|
366
|
+
<p align="center"><strong>Triple Composite</strong></p>
|
|
367
|
+
<p align="center"><img src="assets/demo_composite.png" alt="Triple Composite" width="100%" /></p>
|
|
368
|
+
</td>
|
|
369
|
+
</tr>
|
|
370
|
+
<tr>
|
|
371
|
+
<td width="50%">
|
|
372
|
+
<p align="center"><strong>KPI Dashboard</strong></p>
|
|
373
|
+
<p align="center"><img src="assets/demo_dashboard.png" alt="KPI Dashboard" width="100%" /></p>
|
|
374
|
+
</td>
|
|
375
|
+
<td width="50%">
|
|
376
|
+
<p align="center"><strong>Stacked + Trend + Pie</strong></p>
|
|
377
|
+
<p align="center"><img src="assets/demo_full_dashboard.png" alt="Full Dashboard" width="100%" /></p>
|
|
378
|
+
</td>
|
|
379
|
+
</tr>
|
|
380
|
+
<tr>
|
|
381
|
+
<td width="50%">
|
|
382
|
+
<p align="center"><strong>Side-by-Side Pies</strong></p>
|
|
383
|
+
<p align="center"><img src="assets/demo_sidebyside_pies.png" alt="Side-by-Side Pies" width="100%" /></p>
|
|
384
|
+
</td>
|
|
385
|
+
<td width="50%">
|
|
386
|
+
<p align="center"><strong>Dark Theme</strong></p>
|
|
387
|
+
<p align="center"><img src="assets/demo_dark.png" alt="Dark Theme" width="100%" /></p>
|
|
388
|
+
</td>
|
|
389
|
+
</tr>
|
|
390
|
+
</table>
|
|
391
|
+
|
|
392
|
+
> Every chart is fully interactive — hover for tooltips, click legend items to toggle series, use the toolbox to export.
|
|
393
|
+
> Open the [HTML demos in `assets/`](assets/) for the live experience, or run `python generate_demos.py` yourself.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Supported Chart Types
|
|
398
|
+
|
|
399
|
+
| Category | Method | Description |
|
|
400
|
+
|:---|:---|:---|
|
|
401
|
+
| **Line** | `fig.plot()` | Smooth/straight lines, multi-series via `hue`, optional filled area |
|
|
402
|
+
| **Bar** | `fig.bar()` | Vertical/horizontal, grouped (`hue`), stacked, gradient fills |
|
|
403
|
+
| **Scatter** | `fig.scatter()` | Color and size encoding, numeric axes |
|
|
404
|
+
| **Histogram** | `fig.hist()` | Auto-binned frequency distribution |
|
|
405
|
+
| **Boxplot** | `fig.boxplot()` | Five-number statistical summary |
|
|
406
|
+
| **KDE** | `fig.kde()` | Kernel density estimation (requires `scipy`) |
|
|
407
|
+
| **Pie / Donut** | `fig.pie()` | Pie, donut (`inner_radius`), rose charts, side-by-side multiples |
|
|
408
|
+
| **Radar** | `fig.radar()` | Multi-indicator polygon charts |
|
|
409
|
+
| **Heatmap** | `fig.heatmap()` | Matrix visualisation with colour mapping |
|
|
410
|
+
| **Sankey** | `fig.sankey()` | Multi-level flow diagrams |
|
|
411
|
+
| **Treemap** | `fig.treemap()` | Hierarchical area charts |
|
|
412
|
+
| **Funnel** | `fig.funnel()` | Stage-based conversion funnels |
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Rendering Engines
|
|
417
|
+
|
|
418
|
+
echartsy writes your chart once; `ec.config()` controls where it renders.
|
|
419
|
+
|
|
420
|
+
| Engine | Use case | Install |
|
|
421
|
+
|:---|:---|:---|
|
|
422
|
+
| `"python"` | Standalone scripts — opens the default browser | No extra deps |
|
|
423
|
+
| `"jupyter"` | Jupyter Notebook / JupyterLab inline widgets | `pip install echartsy[jupyter]` |
|
|
424
|
+
| `"streamlit"` | Streamlit applications | `pip install echartsy[streamlit]` |
|
|
425
|
+
|
|
426
|
+
```python
|
|
427
|
+
ec.config(engine="jupyter")
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Adaptive Dark Mode
|
|
433
|
+
|
|
434
|
+
Charts automatically respond to the user's OS or browser `prefers-color-scheme` setting.
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
ec.config(engine="jupyter", adaptive="auto") # auto-detect (default)
|
|
438
|
+
ec.config(engine="jupyter", adaptive="dark") # force dark
|
|
439
|
+
ec.config(engine="jupyter", adaptive="light") # force light
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Style Presets & Palettes
|
|
445
|
+
|
|
446
|
+
Apply a pre-built visual theme in one argument:
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
fig = ec.figure(style=ec.StylePreset.CLINICAL) # Clean defaults
|
|
450
|
+
fig = ec.figure(style=ec.StylePreset.DASHBOARD_DARK) # Dark background
|
|
451
|
+
fig = ec.figure(style=ec.StylePreset.KPI_REPORT) # Warm rusty tones
|
|
452
|
+
fig = ec.figure(style=ec.StylePreset.MINIMAL) # Minimal & light
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Or set a custom palette at any time:
|
|
456
|
+
|
|
457
|
+
```python
|
|
458
|
+
fig.palette(["#667eea", "#764ba2", "#f093fb", "#f5576c", "#4facfe"])
|
|
459
|
+
fig.palette(ec.PALETTE_RUSTY)
|
|
460
|
+
fig.palette(ec.PALETTE_CLINICAL)
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Build your own `StylePreset` for full control over fonts, grid lines, tooltip style, and more:
|
|
464
|
+
|
|
465
|
+
```python
|
|
466
|
+
my_style = ec.StylePreset(
|
|
467
|
+
palette=("#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"),
|
|
468
|
+
bg="#fefae0",
|
|
469
|
+
font_family="Georgia",
|
|
470
|
+
title_font_size=20,
|
|
471
|
+
)
|
|
472
|
+
fig = ec.figure(style=my_style)
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Composite Charts
|
|
478
|
+
|
|
479
|
+
Overlay pies on cartesian charts, or combine bar + line on dual axes — all on one figure.
|
|
480
|
+
|
|
481
|
+
```python
|
|
482
|
+
fig = ec.figure(height="550px")
|
|
483
|
+
|
|
484
|
+
# Primary axis: bars
|
|
485
|
+
fig.bar(df, x="Month", y="Revenue", labels=True, border_radius=4)
|
|
486
|
+
|
|
487
|
+
# Secondary axis: trend line
|
|
488
|
+
fig.plot(df, x="Month", y="Growth", smooth=True, axis=1, line_width=3)
|
|
489
|
+
|
|
490
|
+
# Inset pie
|
|
491
|
+
fig.pie(df_mix, names="Plan", values="Share",
|
|
492
|
+
center=["25%", "32%"], radius=["15%", "25%"])
|
|
493
|
+
|
|
494
|
+
fig.ylabel("Revenue ($K)")
|
|
495
|
+
fig.ylabel_right("Growth %")
|
|
496
|
+
fig.legend(top=40, left=350)
|
|
497
|
+
fig.show()
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Timeline Animations
|
|
503
|
+
|
|
504
|
+
Animate any chart across a time dimension with `TimelineFigure`. It mirrors the `Figure` API; every series method gains one extra parameter: `time_col`.
|
|
505
|
+
|
|
506
|
+
```python
|
|
507
|
+
fig = ec.TimelineFigure(height="500px", interval=1.5)
|
|
508
|
+
fig.bar(df, x="Country", y="GDP", time_col="Year", labels=True)
|
|
509
|
+
fig.title("GDP by Country")
|
|
510
|
+
fig.ylabel("GDP (Trillion USD)")
|
|
511
|
+
fig.legend(top=30)
|
|
512
|
+
fig.show()
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
<p align="center">
|
|
516
|
+
<img src="assets/demo_timeline.png" alt="Timeline Animation" width="700" />
|
|
517
|
+
</p>
|
|
518
|
+
|
|
519
|
+
**TimelineFigure features:**
|
|
520
|
+
|
|
521
|
+
| Feature | API |
|
|
522
|
+
|:---|:---|
|
|
523
|
+
| Playback control | `TimelineFigure(interval=2.0, autoplay=True, loop=True)` |
|
|
524
|
+
| Adjust after creation | `fig.playback(interval=1.0, rewind=True)` |
|
|
525
|
+
| Smart frame sorting | Parses years, quarters (`Q1 2024`), months (`Jan 2024`), ISO dates, fiscal years |
|
|
526
|
+
| Supported series | `bar()`, `plot()`, `scatter()`, `pie()` |
|
|
527
|
+
| Diagnose format | `ec.detect_time_format(df["Year"])` |
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Chart Configuration Reference
|
|
532
|
+
|
|
533
|
+
Every `Figure` and `TimelineFigure` supports these configuration methods:
|
|
534
|
+
|
|
535
|
+
```python
|
|
536
|
+
# Titles
|
|
537
|
+
fig.title("Main Title", subtitle="Sub-title")
|
|
538
|
+
|
|
539
|
+
# Axes
|
|
540
|
+
fig.xlabel("X Label", rotate=30)
|
|
541
|
+
fig.ylabel("Y Label")
|
|
542
|
+
fig.ylabel_right("Secondary Y")
|
|
543
|
+
fig.xlim(0, 100)
|
|
544
|
+
fig.ylim(0, 500)
|
|
545
|
+
|
|
546
|
+
# Layout
|
|
547
|
+
fig.legend(orient="vertical", left="right", top=40)
|
|
548
|
+
fig.margins(left=100, right=120, top=40)
|
|
549
|
+
fig.grid(show=True)
|
|
550
|
+
|
|
551
|
+
# Interactivity
|
|
552
|
+
fig.datazoom(start=0, end=80)
|
|
553
|
+
fig.toolbox(download=True, zoom=True)
|
|
554
|
+
fig.tooltip(trigger="axis")
|
|
555
|
+
|
|
556
|
+
# Export
|
|
557
|
+
fig.save(name="my_chart", fmt="png", dpi=3)
|
|
558
|
+
fig.to_html("my_chart.html")
|
|
559
|
+
|
|
560
|
+
# Palette
|
|
561
|
+
fig.palette(["#5470C6", "#91CC75", "#FAC858"])
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## Exporting
|
|
567
|
+
|
|
568
|
+
```python
|
|
569
|
+
# Standalone HTML file (fully interactive, no server needed)
|
|
570
|
+
fig.to_html("report.html")
|
|
571
|
+
|
|
572
|
+
# Raw ECharts option dict (for debugging or custom renderers)
|
|
573
|
+
option = fig.to_option()
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## API at a Glance
|
|
579
|
+
|
|
580
|
+
### `ec.config(engine, adaptive="auto")`
|
|
581
|
+
|
|
582
|
+
Set the global rendering engine (`"python"`, `"jupyter"`, `"streamlit"`) and theme adaptation mode (`"auto"`, `"light"`, `"dark"`).
|
|
583
|
+
|
|
584
|
+
### `ec.figure(**kwargs)` / `ec.Figure(**kwargs)`
|
|
585
|
+
|
|
586
|
+
Create a chart canvas. Key keyword arguments:
|
|
587
|
+
|
|
588
|
+
| Parameter | Default | Description |
|
|
589
|
+
|:---|:---|:---|
|
|
590
|
+
| `height` | `"400px"` | CSS height of the chart container |
|
|
591
|
+
| `width` | `None` | CSS width (defaults to full container) |
|
|
592
|
+
| `renderer` | `"canvas"` | `"canvas"` or `"svg"` |
|
|
593
|
+
| `style` | `StylePreset.CLINICAL` | A `StylePreset` instance |
|
|
594
|
+
|
|
595
|
+
### `ec.TimelineFigure(**kwargs)` / `ec.timeline_figure(**kwargs)`
|
|
596
|
+
|
|
597
|
+
Same as `Figure` but adds timeline animation. Extra parameters:
|
|
598
|
+
|
|
599
|
+
| Parameter | Default | Description |
|
|
600
|
+
|:---|:---|:---|
|
|
601
|
+
| `interval` | `2.0` | Seconds between animation frames |
|
|
602
|
+
| `autoplay` | `True` | Start playing automatically |
|
|
603
|
+
| `loop` | `True` | Loop back to the first frame |
|
|
604
|
+
|
|
605
|
+
### `ec.StylePreset`
|
|
606
|
+
|
|
607
|
+
Frozen dataclass bundling visual defaults: `palette`, `bg`, `font_family`, `title_font_size`, `axis_label_font_size`, `grid_line_color`, and more.
|
|
608
|
+
|
|
609
|
+
### `ec.detect_time_format(series)`
|
|
610
|
+
|
|
611
|
+
Diagnostic helper that inspects a pandas Series and reports how well TimelineFigure will parse its values.
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## Generating Showcase Images
|
|
616
|
+
|
|
617
|
+
To regenerate the demo screenshots shown above:
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
# 1. Generate the interactive HTML demos
|
|
621
|
+
python generate_demos.py
|
|
622
|
+
|
|
623
|
+
# 2. Capture PNG screenshots (requires Playwright)
|
|
624
|
+
pip install playwright && playwright install chromium
|
|
625
|
+
python capture_screenshots.py
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## Contributing
|
|
631
|
+
|
|
632
|
+
Contributions, bug reports, and feature requests are welcome. Please open an [issue](https://github.com/astrojigs/echartsy/issues) or submit a pull request on [GitHub](https://github.com/astrojigs/echartsy).
|
|
633
|
+
|
|
634
|
+
## License
|
|
635
|
+
|
|
636
|
+
[MIT](LICENSE) — Jigar, 2026
|