> ## Documentation Index
> Fetch the complete documentation index at: https://docs.evidence.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Echart

> Render any Apache ECharts chart type using a raw ECharts config in the tag body. An escape hatch for charts the built-in components cannot express.

```liquid theme={null}
{% custom_echart data="demo.daily_orders" %}
{
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}
```

## Examples

### Basic Usage

```liquid theme={null}
{% custom_echart data="demo.daily_orders" %}
{
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}
```

### Multiple Series with Tooltip

```liquid theme={null}
{% custom_echart data="demo.daily_orders" %}
{
  tooltip: { trigger: 'axis' },
  legend: { show: true },
  xAxis: { type: 'category' },
  yAxis: {},
  series: [
    { type: 'bar', name: 'Sales', encode: { x: 'category', y: 'total_sales' } },
    { type: 'line', name: 'Transactions', encode: { x: 'category', y: 'transactions' } }
  ]
}
{% /custom_echart %}
```

### Dataset Transform

```liquid theme={null}
{% custom_echart data="demo.daily_orders" %}
{
  dataset: [
    {},
    { transform: { type: 'sort', config: { dimension: 'total_sales', order: 'desc' } } }
  ],
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', datasetIndex: 1, encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}
```

### Waterfall (EBITDA Bridge)

````liquid theme={null}
<!-- Waterfalls float each bar on a transparent placeholder series; inc/dec/tot must be mutually exclusive per row. fmt: formatters handle currency display, so values stay unscaled in SQL. -->
```sql ebitda_bridge
select 'Prior EBITDA' as step, 1 as ord, 0 as placeholder, null as inc, null as dec, 32000000 as tot
union all select 'Home', 2, 32000000, 6200000, null, null
union all select 'Sports', 3, 38200000, 4100000, null, null
union all select 'Groceries', 4, 40000000, null, 2300000, null
union all select 'Current EBITDA', 5, 0, null, null, 40000000
order by ord
```

{% custom_echart data="ebitda_bridge" title="EBITDA Bridge" %}
{
  tooltip: { trigger: 'axis', valueFormatter: 'fmt:usd1m' },
  xAxis: { type: 'category', axisLabel: { interval: 0 } },
  yAxis: { axisLabel: { formatter: 'fmt:usd0m' } },
  series: [
    { type: 'bar', stack: 'bridge', silent: true,
      itemStyle: { color: 'transparent' },
      encode: { x: 'step', y: 'placeholder' } },
    { type: 'bar', stack: 'bridge', name: 'Increase',
      itemStyle: { color: '#22A39F' },
      label: { show: true, position: 'top', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'inc' } },
    { type: 'bar', stack: 'bridge', name: 'Decrease',
      itemStyle: { color: '#E2483D' },
      label: { show: true, position: 'bottom', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'dec' } },
    { type: 'bar', stack: 'bridge', name: 'Total',
      itemStyle: { color: '#475569' },
      label: { show: true, position: 'top', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'tot' } }
  ]
}
{% /custom_echart %}
````

### JavaScript mode (functions, gradients)

```liquid theme={null}
<!-- A body with JS function syntax automatically routes to a sandboxed iframe. Globals: data, columns, echarts, theme, fmt. Use real functions when you need them (formatter/tooltip/renderItem) or echarts.graphic. -->
{% custom_echart data="demo.daily_orders" %}
{
  tooltip: { trigger: 'axis', valueFormatter: (value) => fmt(value, 'usd0') },
  xAxis: { type: 'category' },
  yAxis: { axisLabel: { formatter: (value) => fmt(value, 'usd0m') } },
  series: [
    {
      type: 'bar',
      encode: { x: 'category', y: 'total_sales' },
      itemStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: theme.colorPalettes.default[0] },
          { offset: 1, color: theme.colorPalettes.default[1] }
        ])
      },
      label: { show: true, formatter: (params) => fmt(params.value.total_sales, 'usd0') }
    }
  ]
}
{% /custom_echart %}
```

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Use date\_range to filter data for specific time periods. Accepts predefined ranges (e.g., "last 12 months"), dynamic ranges (e.g., "Last 90 days"), custom date ranges (e.g., "2020-01-01 to 2023-03-01"), or partial ranges (e.g., "from 2020-01-01", "until 2023-03-01")

  **Example:**

  ```
  date_range={
    range = "today"
    date = "string"
  }
  ```

  **Attributes:**

  * range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
    * **Allowed values:**
      * `today`
      * `yesterday`
      * `last 7 days`
      * `last 30 days`
      * `last 3 months`
      * `last 6 months`
      * `last 12 months`
      * `previous week`
      * `previous month`
      * `previous quarter`
      * `previous year`
      * `this week`
      * `this month`
      * `this quarter`
      * `this year`
      * `next week`
      * `next month`
      * `next quarter`
      * `next year`
      * `week to date`
      * `month to date`
      * `quarter to date`
      * `year to date`
      * `all time`
  * date: `string` - Date column to filter on. Required when the data has multiple date columns.
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the chart
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title)
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info\_link)
</ResponseField>

<ResponseField name="renderer" type="string" default="canvas">
  ECharts rendering engine

  **Allowed values:**

  * `canvas`
  * `svg`
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date\_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column\_name", "column\_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>
