بنقرة واحدة
js-echarts-to-streamlit
// Transforms JavaScript ECharts options and demos into Python dictionary configurations compatible with streamlit-echarts.
// Transforms JavaScript ECharts options and demos into Python dictionary configurations compatible with streamlit-echarts.
| name | js-echarts-to-streamlit |
| description | Transforms JavaScript ECharts options and demos into Python dictionary configurations compatible with streamlit-echarts. |
This skill converts standard JavaScript/TypeScript Apache ECharts examples into Python code rendered with streamlit-echarts.
{ key: value } → Python dicts {"key": value} (all keys quoted)true/false → True/Falsenull → None.map(), .filter(), .reduce(), for loops → Python list comprehensions or loopsMath.floor(), Math.random() → math.floor(), random.random()Array.from({length: n}, (_, i) => ...) → list(range(n)) or comprehensions$.get('data.json', ...) → with open('data.json') as f: data = json.load(f)random module equivalentlyImport: from streamlit_echarts import JsCode
Wrap any raw JavaScript expression with JsCode("...").js_code. Use cases:
Formatters (tooltip, label, axisLabel):
# JS: formatter: function(params) { return params.value + '%'; }
"formatter": JsCode("function(params) { return params.value + '%'; }").js_code
# JS: valueFormatter: function(value) { return value + ' ml'; }
"valueFormatter": JsCode("function(value) { return value + ' ml'; }").js_code
Gradients:
# JS: color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: 'rgb(128, 255, 165)'}, {offset: 1, color: 'rgb(1, 191, 236)'}])
"color": JsCode(
"new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: 'rgb(128, 255, 165)'}, {offset: 1, color: 'rgb(1, 191, 236)'}])"
).js_code
Important: Only use JsCode when the value must be a JS function or JS object constructor. Do NOT wrap plain strings, numbers, or static formatters like "{value} °C" — those stay as Python strings.
ECharts accepts series as either an object or array. Preserve the original structure:
series: { type: 'bar', ... } → "series": {"type": "bar", ...} (dict)series: [{ type: 'bar', ... }] → "series": [{"type": "bar", ...}] (list)grid, tooltip, or other propertieslen(names) instead of hardcoded numbers when the JS uses names.lengthFor examples that use myChart.on('click', ...) to dynamically change options (e.g., drilldown):
import streamlit as st
def render_interactive_chart():
if "drill_state" not in st.session_state:
st.session_state.drill_state = None
# Build options conditionally based on session_state
if st.session_state.drill_state is None:
options = {
... # top-level view
"series": {
"type": "bar",
"id": "sales",
"data": [
{"value": 5, "groupId": "animals"},
...
],
"universalTransition": {"enabled": True, "divideShape": "clone"},
},
}
else:
options = {
... # drilled-down view
"series": {
"type": "bar",
"id": "sales",
"dataGroupId": drill_state,
"data": [...],
"universalTransition": {"enabled": True, "divideShape": "clone"},
},
}
# Capture click events via JS function that returns data
events = {
"click": "function(params) { return params.data && params.data.groupId ? params.data.groupId : null }",
}
# Back button when drilled down
if st.session_state.drill_state is not None:
if st.button("Back", key="drill_back"):
st.session_state.drill_state = None
st.rerun()
result = st_echarts(
options=options, events=events, height="500px",
replace_merge="series", key="render_drill",
)
if result and result.chart_event and result.chart_event in valid_groups:
st.session_state.drill_state = result.chart_event
st.rerun()
Key points:
events dict maps event names to JS function strings that return dataresult.chart_event contains the returned valuest.session_state to track state across Streamlit rerunskey= on st_echarts so the component is tracked across option changesst.button for "Back" navigation instead of graphic onclick handlersuniversalTransition and replace_mergeECharts universalTransition requires merge-mode setOption so it can compare old vs new series by id. Pass replace_merge="series" to enable this:
"id" on the series across both views so ECharts can match them"universalTransition": {"enabled": True, "divideShape": "clone"} in each series"dataGroupId" on the drilled-down series and "groupId" on individual data items in the top-level seriesreplace_merge, st_echarts uses notMerge: true which fully replaces options and prevents the morph animationmyChart.getWidth(), myChart.dispatchAction() etc. are not available from PythonsetInterval/setTimeout for rotating highlights or live data won't workgraphic elements with onclick handlers must be replaced with Streamlit widgets (e.g., st.button)from streamlit_echarts import st_echarts
def render_chart_name():
options = { ... }
st_echarts(options=options, height="500px")
ST_CATEGORY_DEMOS = {
"Chart Title": (
render_chart_name,
"https://echarts.apache.org/examples/en/editor.html?c=example-id",
),
}
render_<descriptive_name>()500px standard, 700px for dense charts (e.g., Sunburst)title from the source file's comment block