https://github.com/cataseven/statistics-graph-chart-card
A highly customizable, smooth, and advanced graph card. Shows historical sensor data with dynamic trend colors, statistics (min, max, avg), and more. A great alternative to the default history graph and sensor cards.
https://github.com/cataseven/statistics-graph-chart-card
analysis analytics bar-chart chart data data-analysis data-science data-visualization graph graphics histogram historical-data history home-assistant statistical-analysis statistics
Last synced: about 2 months ago
JSON representation
A highly customizable, smooth, and advanced graph card. Shows historical sensor data with dynamic trend colors, statistics (min, max, avg), and more. A great alternative to the default history graph and sensor cards.
- Host: GitHub
- URL: https://github.com/cataseven/statistics-graph-chart-card
- Owner: cataseven
- License: apache-2.0
- Created: 2025-08-09T09:41:30.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2026-04-01T12:36:58.000Z (2 months ago)
- Last Synced: 2026-04-02T03:06:12.125Z (2 months ago)
- Topics: analysis, analytics, bar-chart, chart, data, data-analysis, data-science, data-visualization, graph, graphics, histogram, historical-data, history, home-assistant, statistical-analysis, statistics
- Homepage:
- Size: 33.2 MB
- Stars: 25
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ๐ Home Assistant - Statistics Graph Chart Card

[](https://github.com/hacs/frontend)
[](https://github.com/cataseven/Statistics-Graph-Chart-Card/releases)
[](LICENSE)


[](https://github.com/cataseven/Statistics-Graph-Chart-Card)
[](https://github.com/cataseven/Statistics-Graph-Chart-Card/issues)
An awesome feature-rich custom card for [Home Assistant](https://www.home-assistant.io/) that combines a time-series graph with live state rows โ all in a single card. Built with no external dependencies, fully configurable via the visual editor or YAML.
---
## ๐ผ๏ธ Preview

















---
## โจ Features
| | |
|---|---|
| ๐ | Line, step, and bar charts with smooth Bezier curves |
| ๐
| **Built-in Date Picker** โ navigate Day, Week, Month, Year views with arrow buttons, calendar popup, and preset ranges (Last 7/30 Days, Last 12 Months). Sync multiple cards with `date_picker_group` โ even cards without a visible picker can follow the group. Customize visible modes with `date_picker_modes` โ lock to a single mode for a minimal nav bar |
| ๐ข | Live state rows with current value, MDI icons, and configurable font sizes |
| ๐ฏ | **Nine chart modes** โ Timeline, Scatter, Pie (donut), Ranking (horizontal bar), Radial Bar (concentric arcs), Polar Area (variable-radius pie), Radar (spider polygon), Heatmap (days ร hours), Calendar (weekly grid) โ selectable from a single dropdown |
| ๐๏ธ | **Gauge display** โ replace the state row with a half-circle gauge showing current value against min/max bounds |
| โจ | **Sparkline mode** โ ultra-compact inline graphs with no chrome, ideal for dashboard overview tiles |
| ๐ | **Rise/Fall colorization** โ graph segments automatically change color as values climb or drop, with independent colors for rising, falling, and stable periods |
| โฉ | **Trend icon** โ a โฒโผโฏโฏ indicator on each state row shows the current direction of change, calculated over a configurable time window (`trend_period_hours`) |
| ๐ | **Locale-aware formatting** โ control how numbers are displayed per entity (`number_format`) and how timestamps appear card-wide (`datetime_format`), independent of your HA locale |
| ๐ท๏ธ | **Custom unit per entity** โ override auto-detected units with `unit: kWh` on any entity. Essential for attributes and unitless sensors |
| ๐ก | **Axis label customization** โ adjust font size and opacity of Y-axis and X-axis labels independently for a clean, tailored look |
| ๐ | **Axis tick marks** โ optional small tick lines at each label position, controllable independently for X and Y axes |
| ๐ | **Graph Start Hour** โ pin the X-axis to a fixed start hour (e.g. 06:00) to cut out irrelevant nighttime data on solar dashboards |
| ๐ ๏ธ | **Full visual editor** โ every option is configurable through the Lovelace UI without touching YAML; entities can be reordered by drag-and-drop. The editor adapts dynamically: irrelevant options hide based on the selected chart mode |
| โ๏ธ | Dual Y-axis support (primary + secondary) with per-axis bounds and configurable tick count |
| โ๏ธ | **Independent Y2 axis toggle** โ show or hide the secondary (right) Y axis labels without affecting the primary axis |
| โ๏ธ | **Independent Y-axis** โ `y_axis: independent` gives each entity its own hidden scale based on its min/max, enabling trend comparison across sensors with wildly different units (ยฐC, %, lux, hPa) on a single graph |
| ๐จ | Color thresholds with smooth or hard transitions |
| ๐บ | Min / Max extrema labels โ always on, on click, or never |
| โ | Average line โ dashed reference at the mean value for the visible window |
| ๐ฌ | Tooltip with crosshair on hover |
| ๐
| Per-entity gradient fill with same-hue fade |
| โฆ | Grid lines โ horizontal + vertical aligned to actual data points |
| ๐ | Logarithmic scale |
| ๐ | **Zoom brush** โ click and drag on the graph to zoom into a time range; double-click or "Reset zoom" to restore |
| ๐ | **Annotations** โ add threshold lines, event markers, time span highlights, and comfort zone bands to the graph |
| ๐ | **Tooltip sync** โ hover one card and see crosshairs on all synced cards, with optional named groups |
| ๐ | **Stacked** mode โ stack line/area/bar entities to show composition |
| โ๏ธ | **Time Offset** โ per-entity hour offset to overlay the same sensor from different periods on one graph. Supports helper entities (e.g. `input_number`) for dynamic offset values |
| ใฐ๏ธ | Soft bounds (`~` prefix) โ axis expands when data exceeds the bound |
| ๐ฃ | `state_map` for non-numeric entities (binary sensors, input selects) |
| ๐ | Attribute reading with dot-notation nested path support |
| โฉ | Forward-fill for sparse sensors (e.g. weather entities) |
| ๐จ | Adaptive state color โ state row inherits entity line color automatically |
| ๐๏ธ | **Interval picker** โ quick-select time range buttons (1Hโ1Y) directly on the card, no editor needed |
| โก | **Auto scale points** โ automatically reduces data density for longer time ranges, keeping performance smooth |
| ๐ | **Attribute switcher** โ per-entity dropdown on the card to switch between state and any numeric attribute on the fly |
| ๐ | **Scrollable graph** โ set a visible window smaller than the data range and scroll horizontally through history |
| โ๏ธ | **Configurable icon position** โ place the header icon on the left or right side of the title |
| ๐ท๏ธ | **Compact Legend** โ color-coded entity name key below the graph with configurable position (left, center, right). Click any legend item to temporarily hide that entity from the graph |
| ๐ | **Per-entity legend stats** โ choose any combination of Min, Avg, Max, Last for each entity's legend row. Click to toggle entity visibility |
| ๐ท๏ธ | **Vertical axis labels** โ optional vertical unit labels on the left and right edges of the graph. Defaults to the entity's unit of measurement, with custom text override |
| ๐ | **Smart X-axis labels** โ when the time range spans multiple days, midnight ticks automatically show the date (e.g. "28 Mar") while other ticks show `HH:mm`. Tick density adapts to label width and font size |
| โฌ๏ธ | **Bottom state rows** โ place entity state rows below the graph instead of above with `bottom-left`, `bottom-center`, `bottom-right` alignment |
| ๐ | **Grid aligned to tick marks** โ horizontal grid lines match Y axis tick values exactly |
| ๐ | **Value Transform** โ apply a JavaScript expression to every data point using `x`, `first`, `min`, `max`, `avg`, `last`, `index` โ ideal for normalize-to-zero, splitting sensors, and percentage calculations |
| ๐ | **Range Band** โ per-entity min/max shaded band behind the line showing value fluctuation within each data bucket |
| โ๏ธ | **Dynamic Y-axis width** โ axis label areas auto-expand to fit longer numbers without clipping |
| โก | **Energy Date Sync** โ sync the card's time range with HA's Energy dashboard date picker or [energy-period-selector-plus](https://github.com/flixlix/energy-period-selector-plus) |
| ๐ | **External Statistics** โ display imported statistics that have no regular entity (e.g. `gazpar:gazpar_consumption`) by setting `statistic_id` |
| ๐
| **Long-range views** โ `group_by: week` and `month` with native HA statistics periods, `graph_start` anchoring to calendar boundaries, and smart X-axis labels that adapt to the grouping mode |
| โก | **Change aggregation** โ `aggregate_func: change` uses HA's native `change` field for energy, gas, and water meters. Combine with `group_by: date/week/month` for accurate consumption charts |
| ๐ | **Stacked Groups** โ per-entity `stack_group` names let you create multiple side-by-side stacked bar groups on a single chart |
| ๐ท๏ธ | **Template names** โ use `{{ state_attr('sensor.x', 'attr') }}` with Jinja2 filters (`capitalize`, `upper`, `replace()`, `round()`, etc.) for dynamic entity names |
| โ๏ธ | **Horizontal state layout** โ `state_layout: horizontal` flows entity values side by side instead of stacking vertically |
| ๐ข | **Y-axis decimals** โ card-level `y_axis_decimals` overrides per-entity decimals for axis labels only, keeping state row precision separate |
| โฑ๏ธ | **X-axis interval** โ `x_axis_interval` for manual tick spacing (1hโ3M) with clean boundary snapping |
| ๐
| **Show Full Period** โ extend the X-axis to cover a complete calendar period (day, week, month, year) with a "now" indicator line, leaving empty space after the current time. Ideal for imported data or comparing today vs yesterday |
| ๐ | **Battery icon** โ `battery_entity` displays a color-coded battery level indicator in the header or state row, with configurable low threshold |
| ๐ก | **Attribute Data Source** โ read chart data from an entity attribute array (forecast, spot prices) instead of history. Supports future timestamps for EPEX, Nordpool, Tibber, solar forecasts, and weather predictions. Also accepts numeric/categorical time fields (`month_of_year`, `day_of_year`, `hour_of_day`, epoch seconds/ms) so monthly summaries and hourly profiles work without artificial timestamps |
| ๐
| **Group by Year** โ `group_by: year` for multi-year trend views with automatic bar width and X-axis labels |
| ๐ | **Invert bars** โ per-entity `invert: true` draws bars downward from zero. Combine with `stacked: true` for butterfly charts (energy import/export, network in/out) |
| ๐ | **Rolling date picker window** โ `date_picker_step` turns the picker into an N-unit rolling window. `step: 4` + `mode: week` shows the last 4 weeks and prev/next jumps a full 4 weeks at a time |
| ๐พ | **Long-term statistics auto-routing** โ entities with `state_class` declared automatically use HA's long-term statistics for ranges beyond recorder retention. Set `statistic_id` explicitly or use `hours_to_show > 240` to opt in for short ranges. A console warning lists entities lacking `state_class` when the range exceeds retention |
| ๐ | **Static data carry-forward** โ when a sensor stops emitting state changes, the last known value is carried forward to "now" instead of leaving the chart blank. Matches the behavior of HA's built-in statistics card |
| โ ๏ธ | **Offline sensor gaps** โ when HA reports a sensor as `unavailable`, the line breaks at that point and resumes when the sensor recovers. Makes it instantly obvious when a sensor was offline versus when its value was simply steady |
| ๐ฅง | **Pie chart styles** โ `pie_style` presets (Classic, Thick, Donut, Thin) with optional `pie_3d` depth effect, `pie_spacing` for gaps between slices, and automatic rounded slice corners. Slice labels show the actual value with unit. Customize slice and center label fonts/colors with `pie_label_font_size`, `pie_label_color`, `pie_center_font_size`, and `pie_center_color` โ all accept theme variables |
| ๐ฏ | **Snap-to-data tooltips** โ hovering over a line graph snaps the tooltip and dot to the nearest real data point instead of interpolating fake values between samples. The crosshair line aligns with the snapped point too, so what you see is exactly what your sensor recorded |
| ๐ค | **Theme-aware fonts** โ every canvas-rendered chart (Pie, Heatmap, Calendar, Ranking, Radial Bar, Polar Area, Radar, Gauge, axis labels) uses your active HA font (`--primary-font-family`) instead of generic sans-serif |
| ๐งน | **Clean YAML output** โ the visual editor only writes fields you've actually customized. New cards start with 5 lines, not 80. Toggle a setting and it appears in YAML; revert to default and it disappears. Explicit overrides are always preserved |
| ๐ท๏ธ | **Y-axis state names** โ when graphing entities with `state_map` (washing machines, alarm panels, media players), the Y-axis automatically shows the original state names (`idle`, `running`, `done`) instead of `0`, `1`, `2`. Optional friendly labels supported via `value, label` in the editor |
| ๐จ | **Custom axis colors** โ `y_axis_color`, `x_axis_color`, and `x_axis_date_color` let you color-match the axis labels and tick marks to your dashboard theme |
| โจ | **Bar hover highlight** โ bars brighten on mouse hover so it's obvious which bar a tooltip refers to, especially in stacked or multi-entity charts |
---
## ๐ Table of Contents
| Section | Description |
|---|---|
| [Installation](#-installation) | HACS and manual setup |
| [Quick Start](#-quick-start) | Minimal YAML to get started |
| [Configuration](#%EF%B8%8F-configuration) | Card-level and entity-level options |
| [Chart Modes](#-chart-modes) | Timeline, Scatter, Pie, Ranking, Heatmap, Calendar, Radial Bar, Polar Area, Radar |
| [Feature Guides](#-feature-guides) | Date Picker, Energy Sync, Zoom, Sparkline, Annotations, and more |
| [Examples](#-examples) | Ready-to-use YAML configurations |
| [Reference](#-reference) | Aggregation functions, date formats, bounds, tap actions |
| [Visual Editor](#%EF%B8%8F-visual-editor) | Editor tabs, drag-and-drop, dynamic behavior |
---
## ๐ฆ Installation
### HACS (recommended)
1. Open **HACS
2. Search from the search bar: Statistics Graph Chart Card
3. Install **Home Assistant - Statistics Graph Chart Card**
4. Hard-refresh your browser
### Manual
1. Download `Home Assistant - Statistics Graph Chart Card.js` from the [latest release](../../releases/latest)
2. Copy it to `/config/www/`
3. Add the resource in **Settings โ Dashboards โ Resources**:
```yaml
url: /local/Home Assistant - Statistics Graph Chart Card.js
type: module
```
---
## ๐ Quick Start
```yaml
type: custom:statistics-graph-chart-card
card_header: Living Room
entities:
- entity: sensor.temperature_living
name: Temperature
color: "#ff6b35"
```
> **No YAML needed?** The card has a full visual editor built in. Click the pencil icon on any card in the Lovelace UI to configure everything โ including rise/fall colors, trend settings, and number formats โ without writing a single line of YAML. See [Visual Editor](#๏ธ-visual-editor) for details.
---
## โ๏ธ Configuration
Show card-level and entity-level option tables
### ๐ Card Options
These options apply to the whole card.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `chart_mode` | string | `"timeline"` | Chart visualization mode. See [Chart Modes](#-chart-modes). `timeline` \| `scatter` \| `pie` \| `ranking` \| `radialbar` \| `polararea` \| `radar` \| `heatmap` \| `calendar` |
| `sparkline` | boolean | `false` | Compact mode โ strips all chrome (header, axes, grid, toolbar) and renders tiny inline graphs. See [Sparkline Mode](#-sparkline-mode). Only available in Timeline mode. |
| `card_header` | string | `""` | Title shown at the top. Leave empty to hide. |
| `card_icon` | string | `null` | MDI icon next to the title, e.g. `mdi:thermometer` |
| `card_icon_image` | string | `null` | URL to a custom image. Overrides `card_icon`. |
| `card_icon_color` | string | `null` | Color of the header icon (CSS color). Set to `"threshold"` to color dynamically based on the first entity's value and its color threshold rules. |
| `card_header_size` | string | `null` | Font size of the title and battery icon. The battery indicator scales proportionally with this value. Accepts CSS values like `16px` or `1.2em`. |
| `card_icon_size` | string | `null` | Size of the header icon, e.g. `22px` |
| `card_icon_position` | string | `"left"` | Header icon position: `left` or `right` |
| `battery_entity` | string | `null` | Entity ID reporting battery level (0โ100%). Shows a color-coded battery icon with percentage in the header (when header exists) or state row (when no header). See [Battery Icon](#-battery-icon). |
| `battery_low_threshold` | string/number | `20` | Battery percentage below which the icon turns red. Accepts a number, entity ID (`sensor.x`), or entity attribute (`sensor.x.attribute`). |
| `align_header` | string | `"default"` | Header alignment: `default` / `left` / `center` / `right` |
| `state_layout` | string | `"default"` | State row layout: `default` (vertical stack) / `horizontal` / `horizontal-center` / `horizontal-right`. Horizontal modes flow entities side by side in a single row. |
| `hours_to_show` | number | `24` | Hours of history to load and display. Ignored when `graph_start` is set to `week`, `month`, or `year` โ the calendar period defines the range instead. |
| `points_per_hour` | number | `2` | Data points fetched per hour (global default). Integer only. |
| `auto_scale_points` | boolean | `false` | Automatically scale `points_per_hour` when the interval picker changes the time range. See [Auto Scale Points](#-auto-scale-points). |
| `height` | number | `150` | Graph area height in pixels |
| `group_by` | string | `"interval"` | Bucketing strategy: `interval` / `hour` / `date` / `week` / `month` / `year`. When set to `week`, `month`, or `year`, data is fetched using native HA statistics periods for accuracy and performance. See [Long-Range Views](#-long-range-views). |
| `update_interval` | number | `null` | Auto-refresh interval in seconds. Empty = HA events only. |
| `bar_spacing` | number | `4` | Gap between bar columns in pixels. Timeline mode only. |
| `stacked` | boolean | `false` | Stack entities on top of each other. Timeline mode only. See [Stacked Mode](#-stacked-mode). |
| `min_bound_range` | number | `null` | Minimum span of the primary Y axis |
| `min_bound_range_secondary` | number | `null` | Minimum span of the secondary Y axis |
| `lower_bound` | string/number | `null` | Hard or soft minimum for the primary Y axis. See [Bounds](#-bounds). |
| `upper_bound` | string/number | `null` | Hard or soft maximum for the primary Y axis. See [Bounds](#-bounds). |
| `lower_bound_secondary` | string/number | `null` | Hard or soft minimum for the secondary Y axis. See [Bounds](#-bounds). |
| `upper_bound_secondary` | string/number | `null` | Hard or soft maximum for the secondary Y axis. See [Bounds](#-bounds). |
| `y_axis_ticks` | number | `4` | Number of tick marks (grid lines + labels) on the Y axis. |
| `y_axis_decimals` | number | `null` | Number of decimal places for Y-axis labels. Overrides per-entity `decimals` for axis labels only โ state row values are not affected. Leave empty for auto. |
| `show_y_axis_label` | boolean | `false` | Show vertical unit labels on the left and/or right edge of the graph. When enabled, defaults to the unit of measurement of the first entity on each axis. |
| `y_axis_label` | string | `null` | Custom text for the left (primary) vertical axis label. Overrides the auto-detected unit. Requires `show_y_axis_label: true`. |
| `y2_axis_label` | string | `null` | Custom text for the right (secondary) vertical axis label. Overrides the auto-detected unit. Requires `show_y_axis_label: true`. |
| `y_axis_font_size` | number | `null` | Font size of Y-axis numeric labels in pixels. Default is 10. |
| `y_axis_font_opacity` | number | `null` | Opacity of Y-axis labels. 0 = invisible, 1 = fully opaque. Default is 0.65. |
| `y_axis_color` | string | `null` | Custom color for Y-axis labels and tick marks. Accepts any CSS color (hex, rgba, color name) or a CSS variable like `var(--my-color)`. Leave empty for theme default. |
| `x_axis_font_size` | number | `null` | Font size of X-axis time labels in pixels. Default is 10. |
| `x_axis_font_opacity` | number | `null` | Opacity of X-axis labels. 0 = invisible, 1 = fully opaque. Default is 0.5. |
| `x_axis_color` | string | `null` | Custom color for X-axis time labels and tick marks. Accepts any CSS color or CSS variable. Leave empty for theme default. |
| `x_axis_date_color` | string | `null` | Custom color for X-axis date markers (the bold date dividers shown in 12+ hour views). Defaults to `--primary-color` so dates stand out. Set to match `x_axis_color` for a uniform axis. |
| `pie_style` | string | `"donut"` | Pie chart visual preset: `classic` (full pie), `thick` (wide donut), `donut` (default), or `thin` (narrow ring). Pie mode only. |
| `pie_spacing` | number | `0` | Gap between pie slices in degrees (0โ15). Spaced slices automatically get rounded corners. Pie mode only, donut styles only. |
| `pie_3d` | boolean | `false` | Adds depth and a perspective effect to the pie chart with subtle shadows and a glossy highlight on top. Works with any `pie_style`. Pie mode only. |
| `pie_label_font_size` | number | `null` | Font size in pixels of slice value labels (the per-slice numbers like *"21.1 kWh"*). Leave empty for auto-size based on chart radius. Pie mode only. |
| `pie_label_color` | string | `null` | Color for slice value labels. Accepts any CSS color (hex, rgba, name) or CSS variable like `var(--accent-color)`. Leave empty for auto white (high contrast against any slice color). Pie mode only. |
| `pie_center_font_size` | number | `null` | Font size in pixels of the center total value shown in the donut hole. Requires `show_tooltip_total: true`. Leave empty for auto-size. Pie mode only. |
| `pie_center_color` | string | `null` | Color of the center total value and its sub-label (which inherits the same color with reduced opacity). Accepts any CSS color or variable. Leave empty for the theme default. Pie mode only. |
| `x_axis_interval` | string | `null` | Manual X-axis tick spacing. Values: `1h`โ`12h`, `1d`, `2d`, `7d`, `1w`, `2w`, `1M`, `3M`. Ticks snap to clean boundaries (hour starts, midnight, Mondays, 1st of month). Leave empty for auto. |
| `datetime_format` | string | `"system"` | Controls how timestamps appear on the X-axis, tooltips, and extrema labels. See [Date Formats](#-date-formats). |
| `show_grid` | boolean | `true` | Show grid lines. Available in Timeline and Scatter modes. |
| `show_tooltip` | boolean | `true` | Show hover tooltip with crosshair |
| `show_tooltip_total` | boolean | `true` | Controls total/summary displays across chart modes. Timeline/Scatter: Total row in tooltip. Pie/Polar Area: total in donut center (off = full pie). Radial Bar: average in center. Ranking: percentage labels on bars and Share row in tooltip. |
| `show_y_axis` | boolean | `true` | Show primary (left) Y axis value labels. Available in Timeline and Scatter modes. |
| `show_y2_axis` | boolean | `true` | Show secondary (right) Y axis value labels independently. Only visible when at least one entity uses `y_axis: secondary`. Disable to hide right-side labels while keeping secondary entities plotted. |
| `show_x_axis` | boolean | `true` | Show X axis labels (time in Timeline, values in Scatter). Available in Timeline and Scatter modes. |
| `show_x_ticks` | boolean | `false` | Draw small tick marks at each X-axis label position. |
| `show_y_ticks` | boolean | `false` | Draw small tick marks at each Y-axis label position. |
| `graph_start_hour` | number | `null` | Anchors the X-axis to a fixed hour of the day (0โ23). For example, `6` starts the chart at 06:00 โ ideal for solar panels. Ignored when the interval picker is active. |
| `graph_start` | string | `null` | Snaps the graph start to a calendar boundary: `week` (Monday 00:00), `month` (1st of month), `year` (Jan 1st). Useful with `group_by: week/month` for clean period views. Ignored when the interval picker is active. See [Long-Range Views](#-long-range-views). |
| `show_full_period` | boolean | `false` | Extends the X-axis to cover the full calendar period instead of stopping at "now". A dashed vertical line marks the current time. Works with `graph_start` (week/month/year) and `energy_date_sync`. See [Show Full Period](#-show-full-period). |
| `show_legend` | boolean | `false` | Show a compact color-coded entity name key below the graph. Click any item to temporarily toggle that entity's visibility on the graph. For per-entity stats, use the entity-level Legend toggle. |
| `legend_position` | string | `"center"` | Position of the compact legend: `left` / `center` / `right`. The legend flows inline at the chosen alignment. |
| `logarithmic` | boolean | `false` | Logarithmic Y axis scale. Timeline mode only. |
| `animate_graph` | boolean | `false` | Draw-in animation on load. Timeline mode only. |
| `max_visible_interval` | number | `null` | Maximum visible time range in hours. Enables horizontal scrolling. Timeline mode only. |
| `scroll_mode` | string | `"scrollbar"` | Scroll behavior: `scrollbar` or `wheel`. Timeline mode only. |
| `show_interval_picker` | boolean | `false` | Show quick-select time range buttons on the card. Default set: 1H, 2H, 4H, 8H, 12H, 24H, 7D. Customize with `interval_options`. |
| `interval_picker_position` | string | `"left"` | Position of the interval picker: `left` / `center` / `right` |
| `interval_options` | list | `null` | Which interval buttons to show. Example: `["2H", "12H", "24H", "7D"]`. When not set, the default compact set (1Hโ24H + 7D) is used. Available labels: `1H`, `2H`, `4H`, `8H`, `12H`, `24H`, `3D`, `7D`, `14D`, `30D`, `90D`, `6M`, `1Y`. |
| `show_attribute_list` | boolean | `false` | Show per-entity attribute dropdown selectors on the card |
| `attribute_list_position` | string | `"left"` | Position of the attribute list: `left` / `center` / `right` |
| `tooltip_sync` | boolean | `false` | Broadcast hovered timestamp to other synced cards. Timeline mode only. |
| `tooltip_sync_group` | string | `null` | Named group for tooltip sync. Cards with the same name sync only with each other. Leave empty to sync with all. |
| `energy_date_sync` | boolean | `false` | Sync the card's time range with HA's Energy dashboard date picker or the [energy-period-selector-plus](https://github.com/flixlix/energy-period-selector-plus) custom card. When the user selects a date range, this card automatically updates to show the same period. See [Energy Date Sync](#-energy-date-sync). |
| `show_date_picker` | boolean | `false` | Show a built-in date navigation bar with Day/Week/Month/Year buttons, arrow navigation, calendar popup, and preset ranges. Cannot be used together with `energy_date_sync`. See [Date Picker](#-date-picker). |
| `date_picker_position` | string | `top` | Position of the date picker bar. `top` or `bottom`. |
| `date_picker_group` | string | `null` | Named group for date picker sync. Cards with the same group name share date selection โ change the date on one card and all cards in the group update together. Works even on cards without `show_date_picker` โ a single card with a visible picker can control all other cards in the group. |
| `date_picker_modes` | list | `null` | Which period buttons to show: `day`, `week`, `month`, `year`. Example: `[month, year]`. When only one mode is listed, the D/W/M/Y buttons are hidden and the navigation is centered. Default (null) = all four modes visible. |
| `date_picker_step` | number | `1` | Window width in units of the selected mode. `1` = single-unit window (legacy behavior โ one day, one month, etc.). `>1` turns the picker into a rolling N-unit window: prev/next buttons jump a full N units at a time. Example: `4` with `week` mode shows the last 4 weeks and navigates back/forward 4 weeks per click. See [Date Picker โ Window Step](#-date-picker). |
| `annotations` | list | `[]` | Reference lines and markers on the graph. Timeline mode only. See [Annotations](#-annotations). |
---
### ๐ท Entity Options
Each entry under `entities` supports the following options.
#### ๐ General
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `entity` | string | **required** | HA entity ID. Can be left empty when using `statistic_id`. |
| `statistic_id` | string | `null` | For imported/external statistics that have no regular entity (e.g. `gazpar:gazpar_consumption`). These exist only in the statistics database. Leave empty for normal entities. See [External Statistics](#-external-statistics). |
| `name` | string | `null` | Custom display name. Leave empty to hide the name entirely โ only shown when explicitly set. Supports HA-style templates: `{{ states('sensor.x') }}`, `{{ state_attr('sensor.x', 'attr') }}` with Jinja2 filters like `capitalize`, `upper`, `replace()`. See [Template Names](#-template-names). |
| `unit` | string | `null` | Custom unit label (e.g. `kWh`, `ยฐC`, `%`). Overrides the auto-detected `unit_of_measurement`. Useful for attributes, unitless sensors, or when you want a different label. Appears in state row, tooltip, chart center, and axis labels. |
| `y_axis` | string | `"primary"` | `primary` (left), `secondary` (right), or `independent` (hidden, own scale). Independent entities are scaled to their own min/max โ ideal for overlaying sensors with different units for trend comparison. See [Independent Y-Axis](#-independent-y-axis). |
| `aggregate_func` | string | `"avg"` | Aggregation: `avg` / `min` / `max` / `last` / `first` / `median` / `sum` / `change` / `delta` / `diff`. The `change` option uses HA's native statistics `change` field โ ideal for energy, gas, and water meters with `group_by: date/week/month`. |
| `decimals` | number | `1` | Decimal places shown in state row and labels |
| `attribute` | string | `null` | Read an attribute instead of state. Supports dot notation: `forecast.0.temperature` |
| `value_factor` | number | `0` | Multiplies value by 10^N. `-3` = รท1000, `2` = ร100 |
| `value_transform` | string | `null` | JavaScript expression to transform each data value. Available variables: `x` (current value), `first`, `last`, `min`, `max`, `avg` (series stats), `index` (point position). Applied after `value_factor`. Example: `return x - first`. See [Value Transform](#-value-transform). |
| `data_attribute` | string | `null` | Read chart data from an entity attribute array instead of history. The attribute must contain an array of objects with time and value fields. Ideal for forecast/price data (EPEX, Nordpool, weather). See [Attribute Data Source](#-attribute-data-source). |
| `data_time_field` | string | `"start_time"` | Name of the time field in each array item when using `data_attribute`. |
| `data_value_field` | string | `"price_per_kwh"` | Name of the value field in each array item when using `data_attribute`. |
| `data_time_unit` | string | `"iso"` | How to interpret the time field. `iso` = string or epoch ms (default โ existing behavior). `epoch_seconds` / `epoch_ms` = Unix timestamp. `month_of_year` (1โ12), `day_of_year` (1โ366), `week_of_year` (1โ53), `hour_of_day` (0โ23) = numeric category โ perfect for monthly summaries, day-of-year datasets, and hourly profiles without generating artificial timestamps. See [Attribute Data Source โ Time Unit](#-attribute-data-source). |
| `data_time_year` | number | `null` | Reference year used to anchor categorical time units (`month_of_year`, `day_of_year`, `week_of_year`). Empty = current year. Has no effect for `iso` or `epoch_*` units. |
| `offset` | string/number | `0` | Shifts this entity backward in time by the given number of hours. Use to overlay the same sensor from different periods. `24` = yesterday, `168` = last week, `720` = last month. Also accepts a helper entity ID (e.g. `input_number.my_offset`) for dynamic offset โ the entity's state is read as hours. See [Time Offset](#-time-offset). |
| `points_per_hour` | number | `null` | Per-entity override. Inherits card-level setting if empty. |
| `number_format` | string | `"system"` | Controls how numbers are displayed in the state row and tooltip. `system` follows HA's locale; `comma` forces European style (1.234,56); `dot` forces English style (1,234.56). Useful when mixing sensors from different regional sources. |
| `datetime_format` | string | `"system"` | **Deprecated** โ use the card-level `datetime_format` instead. Entity-level values still work for backward compatibility and override the card setting when present. |
| `fixed_value` | boolean | `false` | Draw a flat horizontal reference line at the current value instead of history |
| `invert` | boolean | `false` | Draws bars downward from the zero line. Tooltip, state row, and extrema labels show positive values. Use with `stacked: true` for butterfly charts. See [Invert Bars](#-invert-bars-butterfly-charts). |
| `state_map` | list | `null` | Map non-numeric states to numbers for graphing. See [State Map](#-state-map). |
| `tap_action` | object | `null` | Action on tapping the state row. See [Tap Actions](#-tap-actions). |
#### ๐๏ธ Appearance
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `graph_type` | string | `"line"` | `line` / `step` / `bar`. Only available in Timeline mode โ other chart modes ignore this. |
| `show_graph` | boolean | `true` | Show this entity on the graph |
| `show_line` | boolean | `true` | Show the line edge. Timeline mode only. |
| `show_fill` | boolean | `true` | Show the fill area below the line. Timeline mode only. |
| `show_range_band` | boolean | `false` | Draw a min/max shaded band behind the line showing the value range within each aggregation bucket. The line shows the average while the band shows how much the value fluctuated. See [Range Band](#-range-band). Timeline mode only. |
| `gradient` | boolean | `true` | Fade the fill from the entity color to transparent. Only applies when `show_fill` is true. Timeline mode only. |
| `show_points` | boolean | `false` | Show a dot at each data point. Timeline mode only. |
| `smooth` | boolean | `true` | Bezier curve smoothing. Timeline mode only. |
| `line_width` | number | `2.5` | Line thickness in pixels. Timeline mode only. |
| `show_extrema` | string | `"click"` | Min/Max labels: `never` / `click` / `always`. Timeline mode only. |
| `show_average` | boolean | `false` | Draw a dashed horizontal line at the mean value. Timeline mode only. |
| `show_state` | string/boolean | `true` | State row display: `true` (text), `false` (hidden), `"gauge"` (half-circle arc). See [Gauge Display](#-gauge-display). |
| `show_state_last` | boolean | `false` | Show the last aggregated graph value instead of the live HA state. |
| `show_second_state_as` | string | `null` | Show a secondary stat value next to the primary state. Options: `min`, `max`, `avg`, `sum`, `first`, `last`. Displays with the same styling as the primary value, with a small label prefix. |
| `show_trend_icon` | boolean | `true` | Show โฒโผโฏโฏ trend direction icon next to the state value. |
| `trend_period_hours` | number | `1` | Time window (in hours) for trend direction calculation. Set `0` for full range. |
| `show_in_legend` | boolean | `false` | Show a statistics row below the graph for this entity. Which stats are shown is controlled by `legend_stats`. |
| `legend_stats` | list | `["min","avg","max"]` | Which statistics to display in the legend row. Any combination of `min`, `avg`, `max`, `last`, `sum`. Requires `show_in_legend: true`. |
| `lower_bound` | string/number | `null` | Y axis minimum / gauge minimum. See [Bounds](#-bounds). |
| `upper_bound` | string/number | `null` | Y axis maximum / gauge maximum. See [Bounds](#-bounds). |
| `align_state` | string | `"left"` | State row position and alignment. Top variants: `left` / `center` / `right` (above the graph). Bottom variants: `bottom-left` / `bottom-center` / `bottom-right` (below the graph). |
| `stack_group` | string | `null` | Named group for stacked bars/lines. Entities with the same group name stack on top of each other; different groups sit side by side. Leave empty to stack all entities together (default). Requires `stacked: true`. See [Stacked Groups](#-stacked-groups). |
| `icon` | string | `null` | MDI icon in the state row, e.g. `mdi:thermometer` |
| `icon_size` | string | `null` | State row icon size, e.g. `18px` |
| `name_size` | string | `null` | State row name font size, e.g. `14px` |
| `state_size` | string | `null` | State row value font size, e.g. `13px` |
| `trend_icon_size` | string | `null` | Trend icon font size, e.g. `12px` |
#### ๐จ Colors
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `color` | string | `"#ff4757"` | Line and fill color. Use `threshold` to drive from color thresholds. |
| `point_colors` | string | `null` | Color of data point dots. Use `threshold` for per-point threshold color. |
| `icon_color` | string | `null` | State row icon color. Use `threshold` for dynamic color. |
| `state_color` | string | `null` | State row value text color. Use `threshold` for dynamic color. |
| `state_adaptive_color` | boolean | `false` | Automatically tint state value and icon with the entity's line color. Quick alternative to setting `state_color` and `icon_color` manually. |
| `rise_fall_colors` | object | `null` | Color by rise/fall direction. See [Rise/Fall Colors](#-risefall-colors). |
| `color_thresholds` | object | `null` | Color by value. See [Color Thresholds](#-color-thresholds). |
---
## ๐ฏ Chart Modes
Timeline, Scatter, Pie, Ranking, Heatmap, Calendar, Radial Bar, Polar Area, Radar
The `chart_mode` option at the card level controls the overall visualization. Each mode takes over the entire graph area.
### Timeline *(default)*
Classic time-series chart. Entities can individually be `line`, `step`, or `bar`. All Timeline-specific options (axes, grid, stacked, scroll, annotations, offset, zoom) are available.

### Scatter
Plots the first entity on the X axis and the second on the Y axis to reveal correlations. Exactly 2 entities required.

```yaml
chart_mode: scatter
entities:
- entity: sensor.temperature
color: "#ff4757"
- entity: sensor.humidity
color: "#378ADD"
```
Points are matched by timestamp (5-minute tolerance). Older dots are faded, newer dots are vivid. X/Y axes show entity value ranges, not time.
### Pie Chart
Centered chart showing proportional shares. Slice labels show the actual value with the unit (or percentage in Ranking mode).
**Style presets** โ choose how the pie ring looks:
- **Classic** โ full pie with no center hole
- **Thick** โ wide donut ring, plenty of fill
- **Donut** *(default)* โ standard donut with a center hole
- **Thin** โ narrow ring, modern minimal look
**3D effect** โ set `pie_3d: true` to add depth, perspective and a subtle highlight on top. Works with any preset.
**Slice spacing** โ set `pie_spacing` (in degrees, 0โ15) for visible gaps between slices. Spaced slices automatically get rounded corners. Only applies to donut styles, not Classic.
**Center total** โ when `show_tooltip_total: true`, the total value appears in the donut hole. Disable to make Classic a true full pie.
**Label and color customization** โ fine-tune the look of slice labels and the center total to match your theme:
- `pie_label_font_size` โ slice value label size in pixels (leave empty for auto)
- `pie_label_color` โ slice value label color (CSS color or `var(--โฆ)`; auto = white)
- `pie_center_font_size` โ center total size in pixels (leave empty for auto)
- `pie_center_color` โ center total color; the small "Total" sub-label inherits this with reduced opacity
All four accept theme variables, so `pie_label_color: var(--accent-color)` updates with your active theme.
**Past dates** โ using a date picker to scroll back to a period with no data shows an empty ring with a friendly "No data" message instead of returning today's value.

```yaml
chart_mode: pie
height: 200
pie_style: donut # classic | thick | donut | thin
pie_spacing: 4 # 0-15 degrees, gap between slices
pie_3d: true # depth/perspective effect
pie_label_font_size: 14
pie_label_color: var(--primary-text-color)
pie_center_font_size: 32
pie_center_color: var(--accent-color)
show_tooltip_total: true # center total
entities:
- entity: sensor.hvac_energy
aggregate_func: sum
color: "#E24B4A"
- entity: sensor.lighting_energy
aggregate_func: sum
color: "#EF9F27"
- entity: sensor.kitchen_energy
aggregate_func: sum
color: "#1D9E75"
```
### Ranking
Horizontal bars sorted by value (highest first). Each bar shows name, proportional width, value, unit, and share percentage.

```yaml
chart_mode: ranking
height: 200
entities:
- entity: sensor.bedroom_temp
color: "#E24B4A"
- entity: sensor.living_room_temp
color: "#378ADD"
- entity: sensor.kitchen_temp
color: "#EF9F27"
```
### Heatmap
Days ร hours color grid. Each cell represents one hour of one day, colored by intensity. Only the first entity is used.

```yaml
chart_mode: heatmap
hours_to_show: 168
height: 250
entities:
- entity: sensor.temperature
color: "#ff4757"
```
The color range can be controlled three ways:
- **Automatic** โ min/max derived from data
- **Manual bounds** โ set entity `lower_bound` / `upper_bound` for a fixed color scale
- **Color thresholds** โ enable `color_thresholds` for multi-color heatmaps (e.g., blue โ green โ red)
### Calendar
GitHub-contribution-style weekly grid. Each cell = one day. Only the first entity is used.

```yaml
chart_mode: calendar
hours_to_show: 720
height: 200
entities:
- entity: sensor.energy_daily
aggregate_func: sum
color: "#1D9E75"
```
### Radial Bar
Concentric progress arcs โ each entity is a ring showing its value as a percentage of a defined range. The center displays the average.

```yaml
chart_mode: radialbar
height: 250
entities:
- entity: sensor.living_room_temp
color: "#ff4757"
lower_bound: 0
upper_bound: 40
- entity: sensor.bedroom_temp
color: "#378ADD"
lower_bound: 0
upper_bound: 40
- entity: sensor.garage_temp
color: "#2ecc71"
lower_bound: 0
upper_bound: 40
```
Set `lower_bound` / `upper_bound` per entity to define the 0โ100% range. If not set, the entity's historical min/max from the current time window is used. Supports color thresholds for dynamic ring colors.
### Polar Area
Equal-angle slices with variable radius โ larger values produce bigger slices. Like a pie chart but comparing magnitudes instead of shares.

```yaml
chart_mode: polararea
height: 250
entities:
- entity: sensor.living_room_temp
color: "#ff4757"
- entity: sensor.bedroom_temp
color: "#378ADD"
- entity: sensor.garage_temp
color: "#2ecc71"
```
Includes concentric grid circles for reference. Percentage labels appear on slices โฅ 4%. The center shows the total.
### Radar
Spider/polygon chart where each entity forms one spoke. The filled polygon reveals the overall sensor profile at a glance.

```yaml
chart_mode: radar
height: 300
entities:
- entity: sensor.temperature
name: "Temperature"
lower_bound: 0
upper_bound: 40
- entity: sensor.humidity
name: "Humidity"
lower_bound: 0
upper_bound: 100
- entity: sensor.co2
name: "COโ"
lower_bound: 400
upper_bound: 2000
- entity: sensor.pm25
name: "PM2.5"
lower_bound: 0
upper_bound: 50
```
Requires at least 3 entities. Each entity's value is normalized to its `lower_bound` / `upper_bound` range. Polygon grid rings provide reference levels. Colored dots at each vertex show the exact position, with value labels nearby. Supports color thresholds for per-dot colors.
### Chart Mode Compatibility
Not all card options apply to every mode. The visual editor hides irrelevant options automatically.
| Feature | Timeline | Scatter | Pie | Ranking | Radial Bar | Polar Area | Radar | Heatmap | Calendar |
|---------|----------|---------|-----|---------|------------|------------|-------|---------|----------|
| Y / X axes | โ
| โ
| โ | โ | โ | โ | โ | Own axes | Own axes |
| Grid | โ
| โ
| โ | โ | โ | Grid circles | Polygon grid | โ | โ |
| Stacked | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Offset | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Annotations | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Zoom brush | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Scroll | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Sparkline | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Range Band | โ
| โ | โ | โ | โ | โ | โ | โ | โ |
| Entity limit | โ | 2 | โ | โ | โ | โ | 3+ | 1 | 1 |
| Entity graph_type | line/step/bar | โ | โ | โ | โ | โ | โ | โ | โ |
| lower/upper_bound | Y axis range | โ | โ | โ | 0โ100% range | โ | Normalization | Color scale | Color scale |
---
## ๐ Feature Guides
Date Picker, Energy Sync, Zoom, Sparkline, Annotations, and 18 more
๐
Date Picker
A built-in date navigation panel that lets users browse historical data by Day, Week, Month, or Year โ without leaving the dashboard.
### Setup
```yaml
type: custom:statistics-graph-chart-card
show_date_picker: true
date_picker_position: top
entities:
- entity: sensor.temperature_living
color: "#ff6b35"
```
### Navigation
The date picker bar shows the current period label with arrow buttons to move forward/backward:

- **D / W / M / Y** โ switch between Day, Week, Month, and Year views
- **โ โถ** โ navigate to the previous/next period
- **๐
** โ open the calendar popup for direct date selection
### Calendar & Presets
Click the calendar icon to open a panel with:
- **Calendar grid** โ click two dates to select a custom range
- **Quick presets** โ Today, Yesterday, This/Last Week, This/Last Month, This/Last Year, Last 7 Days, Last 30 Days, Last 12 Months
The calendar stays open after selection so you can adjust the range. Click the ๐
icon again to close it.
### Group Sync
Cards with the same `date_picker_group` share their date selection. **You don't need a visible date picker on every card** โ only one card needs `show_date_picker: true`. Other cards in the same group will follow along automatically.
```yaml
# Card 1: Has the visible date picker โ this is the "controller"
show_date_picker: true
date_picker_group: bedroom
# Card 2: No visible picker โ just follows Card 1
date_picker_group: bedroom
# Card 3: Also follows Card 1
date_picker_group: bedroom
```
Changing the date on Card 1 updates all three cards. Cards 2 and 3 show no picker UI but their data range follows the group selection.
This is ideal for dashboards where you want one date picker controlling multiple charts without repeating the picker bar on every card.
### Customizing Modes
Control which period buttons appear with `date_picker_modes`:
```yaml
# Show only Month and Year
date_picker_modes:
- month
- year
# Lock to Month โ buttons hidden, navigation centered
date_picker_modes:
- month
```
When only one mode is listed, the D/W/M/Y buttons are hidden entirely and the navigation (โ label โถ) is centered for a minimal look. The ๐
calendar icon stays visible on the right.
### Window Step
`date_picker_step` controls how many units make up one "window". Default `1` = the legacy behavior (each click moves one day, one week, one month, etc.). When you set it higher, the picker becomes a **rolling N-unit window** and prev/next buttons jump a full N units at a time.
```yaml
# Last 4 weeks, prev/next jumps 4 weeks
show_date_picker: true
date_picker_step: 4
date_picker_modes:
- week
```
```yaml
# Last 30 days, prev/next jumps 30 days
date_picker_step: 30
date_picker_modes:
- day
```
The label adapts automatically: `step > 1` shows the date range (`Mar 11 โ Apr 7`), `step = 1` keeps the existing single-period labels (`April 2026`, `Apr 1 โ Apr 7`).
> **Editor:** General Settings โ Overlays โ *Window Step* (appears next to *Visible Modes* when the date picker is enabled)
### Behavior
| Period | X-axis range | Live updates |
|---|---|---|
| **Today** | 00:00 โ end of day | โ
Active |
| **Yesterday** | 00:00 โ 23:59 | โ Paused |
| **This Week** | Monday 00:00 โ end of week | โ
Active |
| **Last 7 Days** | 7 days ago โ now | โ
Active |
| **Custom range** | Start โ End | Depends on whether end is today |
### Editor
General Settings โ Overlays โ **Date Picker** toggle. Position and Group options appear on the same row. The **Group** field is always editable โ even when the Date Picker toggle is off โ so you can assign a group to cards that don't show their own picker. When enabled, a **Visible Modes** section appears below with D/W/M/Y checkboxes.
### Notes
- Cannot be used together with `energy_date_sync` โ enabling one disables the other
- Date picker state is persisted in `localStorage` and restored on page reload
- When viewing the current period, the X-axis extends to the end of the period with empty space after the current time
- Cards with only `date_picker_group` (no `show_date_picker`) use their normal `hours_to_show` until a sync event arrives from a card in the same group
โก Energy Date Sync
Syncs the card's time range with Home Assistant's Energy dashboard date picker or the [energy-period-selector-plus](https://github.com/flixlix/energy-period-selector-plus) custom card.

### Setup
```yaml
type: custom:statistics-graph-chart-card
energy_date_sync: true
entities:
- entity: sensor.energy_consumption
color: "#ff4757"
aggregate_func: sum
- entity: sensor.solar_production
color: "#2ecc71"
aggregate_func: sum
```
Place the card on the same dashboard as an Energy date picker. When the user selects a day, week, month, or custom range, this card automatically updates to show the same period.
### Behavior
| Date selection | X-axis range | Live updates |
|---|---|---|
| **Today** | 00:00 โ current time | โ
Active โ graph updates in real time |
| **Yesterday** | 00:00 โ 23:59 | โ Paused โ historical data is frozen |
| **This week** | Monday 00:00 โ current time | โ
Active |
| **Last week** | Monday 00:00 โ Sunday 23:59 | โ Paused |
| **This month** | 1st 00:00 โ current time | โ
Active |
| **Custom range** | Start โ End (clamped to now if end is in the future) | Depends on whether end is today |
### Compatible with
- HA's built-in Energy dashboard date picker (DAY / WEEK / MONTH / YEAR)
- [energy-period-selector-plus](https://github.com/flixlix/energy-period-selector-plus) custom card
- Any card that uses HA's energy data collection system
### Editor
General Settings โ Overlays โ **Energy Date Sync** toggle.
### Notes
- When `energy_date_sync` is active, it overrides `hours_to_show` and the interval picker selection
- The card subscribes to HA's energy data collection on the WebSocket connection โ no polling needed
- If the Energy panel hasn't loaded yet, the card retries every 2 seconds for up to 60 seconds
๐
Show Full Period
Extends the X-axis to cover a complete calendar period, leaving empty space after the current time. A dashed vertical "now" line marks where live data ends.
```yaml
graph_start_hour: 0
hours_to_show: 24
show_full_period: true # X-axis: 00:00 โ 23:59, empty after now
```
The end of the period is determined by `graph_start`:
| `graph_start` | X-axis extends to |
|---------------|-------------------|
| off | End of today (next midnight) |
| `week` | End of week (next Monday 00:00) |
| `month` | End of month (1st of next month) |
| `year` | End of year (Jan 1st next year) |
### With Energy Date Sync
`show_full_period` also works with `energy_date_sync: true`. When the energy date picker selects a current period (today, this week, this month), the X-axis extends to the full period end. Past periods display in full as before.
```yaml
energy_date_sync: true
show_full_period: true # energy picker "This Month" โ X-axis: Apr 1 โ May 1
```
This is especially useful for:
- **Imported data** (energy, gas) that arrives with a few days delay โ the graph shows the gap instead of filling it with the last known value
- **Day comparison** with offset โ today's card shows a partial day with empty space; yesterday's card (offset: 24) shows a complete day
- **Weekly/monthly dashboards** โ see the full period at a glance with the "now" marker
- **Energy dashboard** โ combine with `energy_date_sync` to see the full billing period
> **Editor:** General Settings โ **X-Axis** tab โ *Show Full Period* checkbox

๐
Long-Range Views
Visualize data over weeks, months, and years with calendar-aware grouping and native HA statistics.
### Weekly, Monthly, and Yearly Grouping
```yaml
group_by: week
graph_start: month # this month's weeks
aggregate_func: change # consumption per week
graph_type: bar
```
```yaml
group_by: month
graph_start: year # start from Jan 1
```
```yaml
group_by: year
hours_to_show: 87600 # ~10 years
aggregate_func: change # annual consumption
graph_type: bar
```
When `group_by` is set to `date`, `week`, `month`, or `year`, the card fetches data using native HA statistics periods (`period: 'day'`, `'week'`, `'month'`). Year mode fetches monthly data and aggregates client-side. This enables the `change` aggregate field and bypasses the database retention limit โ you can display a full year of data even if your recorder purge is set to 10 days.
### Auto-Routing to Long-Term Statistics
Even in `interval` mode with short ranges (`hours_to_show โค 24`), the card auto-routes to long-term statistics in two cases:
1. **Any entity declares `statistic_id` explicitly** โ the user vouches that the entity has long-term statistics available. Useful for entities that exist only in the statistics database (Gazpar, Linky, etc.) or for forcing the route.
2. **`hours_to_show > 240`** (โ 10 days, the typical recorder retention) โ statistics is the only source that can serve the range, so the card switches automatically.
In both cases the route is **conditional on every relevant entity having long-term statistics available** โ meaning a `state_class` of `measurement`, `total`, or `total_increasing`, or an explicit `statistic_id`. If any entity in the card lacks LTS, the route falls back to the regular history API to keep that entity working.
When the requested range exceeds 10 days but some entities lack LTS, a console warning is printed once listing the offending entities and explaining how to enable `state_class` in HA.
### Graph Start Anchoring
When `graph_start` is set, `hours_to_show` is ignored โ the calendar period directly determines the start:
| Value | Behavior |
|-------|----------|
| `week` | Start from Monday 00:00 |
| `month` | Start from the 1st of the month |
| `year` | Start from January 1st |
> **Editor:** General Settings โ Display โ Graph Navigation โ *Graph Start*
### X-Axis Interval
Manual control over tick spacing:
```yaml
x_axis_interval: 2h # Every 2 hours (00:00, 02:00, 04:00โฆ)
x_axis_interval: 1d # Daily (midnight)
x_axis_interval: 1w # Weekly (Mondays)
x_axis_interval: 1M # Monthly (1st of month)
```
Available presets in the editor: Auto, 1Hโ12H, 1D, 2D, 7D, 1W, 2W, 1M, 3M.
> **Editor:** General Settings โ X-Axis โ *X Axis Interval*
### Smart X-Axis Labels
The X-axis automatically adapts to the `group_by` setting:
- **Week** โ Ticks on Mondays: "3 Mar", "10 Mar"
- **Month** โ Ticks on the 1st: "Jan", "Feb" (with year when spanning multiple years)
- **Date** โ Daily ticks: "3 Mar", "4 Mar"
- **Hour** โ Hourly ticks; midnight shows date instead of "00:00"
In `interval` mode, midnight labels also show the date for any view longer than 12 hours.
๐๏ธ Gauge Display
Replace the numeric state row with a half-circle gauge arc. Set `show_state: gauge` on any entity.

```yaml
entities:
- entity: sensor.temperature
show_state: gauge
color: "#ff4757"
lower_bound: 15 # gauge minimum
upper_bound: 30 # gauge maximum
```
The gauge arc sweeps 270ยฐ from `lower_bound` to `upper_bound`. The center shows the current value + unit, bottom edges show min/max labels. Multiple gauge entities display side-by-side: 1 entity = large gauge, 2+ = compact.
`color_thresholds` work with gauge โ the arc color changes dynamically based on value.
The graph below the gauge continues to show the historical trend as usual.
โจ Sparkline Mode
Card-level `sparkline: true` strips all chrome and renders ultra-compact inline graphs. Only available in Timeline mode.

```yaml
sparkline: true
entities:
- entity: sensor.temperature
color: "#ff4757"
- entity: sensor.humidity
color: "#378ADD"
grid_options:
columns: 12
rows: 2
```
Each entity becomes one row: name + value + trend icon on the left, tiny graph on the right. Removed: header, icon, toolbar, axes, grid, tooltip, legend, annotations. Preserved: entity colors, line smoothing, fill, trend icons, live streaming, color thresholds, and rise/fall colors.
๐ Brush Zoom
Click and drag on any Timeline mode graph to zoom into a specific time range. No configuration needed โ it's always available.

### How it works
1. **Click and drag** horizontally โ a blue selection overlay appears with formatted timestamps at both edges
2. **Release** โ the graph zooms into the selected range, recalculating Y axis, grid, statistics (Min/Avg/Max), extrema labels, and legend values
3. **Reset** โ double-click the graph, or click the **"Reset zoom"** button in the top-right corner
**Key details:**
- **No API calls on zoom** โ the full dataset is preserved in memory; zooming only filters and re-renders existing data. Reset is instant.
- **Progressive zoom** โ zoom again within an already-zoomed view to drill deeper into spikes or anomalies
- **Touch support** โ works on mobile: touch and drag to select
- **Minimum 15px selection** โ prevents accidental zoom from regular clicks or taps
- **Time formatting** โ selection labels show time only for ranges under 24H, date + time for longer ranges
- **Interval picker aware** โ changing the time range via the interval picker resets any active zoom and fetches fresh data
Timeline mode only.
๐ Stacked Mode
Card-level `stacked: true` stacks entities on top of each other (Timeline mode only). Bar entities stack vertically. Line/area entities stack as bands. Entities on the same Y axis and graph type are stacked together. The tooltip shows a "Total" row.
```yaml
stacked: true
entities:
- entity: sensor.solar_production
color: "#f39c12"
- entity: sensor.grid_import
color: "#e74c3c"
- entity: sensor.battery_discharge
color: "#3498db"
```
### Stacked Groups
By default, all bar entities stack into a single column. Use `stack_group` to create **named groups** โ entities within the same group stack on top of each other, while different groups sit side by side.
```yaml
stacked: true
group_by: date
entities:
- entity: sensor.solar_production
graph_type: bar
stack_group: energy
color: "#2ecc71"
- entity: sensor.grid_import
graph_type: bar
stack_group: energy
color: "#e74c3c"
- entity: sensor.cost_peak
graph_type: bar
stack_group: cost
color: "#f39c12"
- entity: sensor.cost_offpeak
graph_type: bar
stack_group: cost
color: "#3498db"
```
This renders two side-by-side bar groups per time slot: an "energy" stack (solar + grid) and a "cost" stack (peak + off-peak). Backward compatible โ if no `stack_group` is set, all entities stack together as before.
> **Editor:** Per-entity โ Appearance tab โ *Stack Group* text field (visible when Stacked is enabled)
๐ท๏ธ Compact Legend
Card-level `show_legend: true` adds a compact color-coded entity name key below the graph. Just colored dots and names โ no values, no stats. Wraps to multiple lines on narrow cards.
```yaml
show_legend: true
entities:
- entity: sensor.memory
name: "Memory"
color: "#f39c12"
show_state: false
- entity: sensor.disk
name: "Disk"
color: "#85b7eb"
show_state: false
- entity: sensor.cpu
name: "CPU"
color: "#00bcd4"
show_state: false
```
This produces: `โ Memory โ Disk โ CPU` in a centered wrapping row below the graph. Combine with `show_state: false` on entities to maximize graph area while still identifying colors.
For per-entity statistics (Min, Avg, Max, Last), use the entity-level **Legend** toggle instead โ see [Entity Legend Stats](#per-entity-legend-stats).

๐ Per-Entity Legend Stats
Each entity's Legend toggle (`show_in_legend: true`) now lets you choose which statistics to display. Select any combination of Min, Avg, Max, and Last.
```yaml
entities:
- entity: sensor.temperature
show_in_legend: true
legend_stats:
- avg
- last
- entity: sensor.humidity
show_in_legend: true
legend_stats:
- min
- max
```
The editor shows four checkboxes (Min, Avg, Max, Last) inside the Legend section. Default is `[min, avg, max]` for backward compatibility.
โฌ๏ธ State Row Position
Entity state rows can now be placed **below** the graph instead of above. The `align_state` option accepts six positions:
| Value | Position |
|---|---|
| `left` *(default)* | Above graph, left-aligned |
| `center` | Above graph, centered |
| `right` | Above graph, right-aligned |
| `bottom-left` | Below graph, left-aligned |
| `bottom-center` | Below graph, centered |
| `bottom-right` | Below graph, right-aligned |
```yaml
entities:
- entity: sensor.temperature
align_state: bottom-left
- entity: sensor.humidity
align_state: left # stays above the graph
```
Mix and match โ some entities above, some below. Useful when you want the graph to be the first thing visible, with values underneath.
โ๏ธ Independent Y2 Axis
The primary (left) and secondary (right) Y axis labels can be toggled independently:
```yaml
show_y_axis: true # primary โ left side
show_y2_axis: false # secondary โ right side hidden
entities:
- entity: sensor.temperature
y_axis: primary
- entity: sensor.humidity
y_axis: secondary # still plotted, just no labels on right
```
Useful when the secondary axis labels are distracting or when you want to maximize horizontal graph space. Both entities continue to be plotted against their respective axes โ only the labels are hidden.
โ๏ธ Independent Y-Axis
Overlay sensors with completely different units on a single graph for trend comparison. Each `independent` entity gets its own hidden scale based on its data's min/max range. No axis labels are shown โ only the visual trend matters.
```yaml
entities:
- entity: sensor.temperature
y_axis: primary # Left axis, shared scale, visible labels
color: "#ff4757"
- entity: sensor.humidity
y_axis: secondary # Right axis, shared scale, visible labels
color: "#378ADD"
- entity: sensor.illuminance
y_axis: independent # Own hidden scale: 0โ10000 lux
color: "#f39c12"
- entity: sensor.pressure
y_axis: independent # Own hidden scale: 980โ1020 hPa
color: "#2ecc71"
```
There is no limit on the number of independent entities. Each one is scaled individually. Primary and secondary entities continue to share their respective axis scales.
> **Editor:** Per-entity โ **Data** tab โ *Y Axis* dropdown โ "Independent"
๐ Value Transform
Apply a JavaScript expression to every data point before graphing. The transform has access to the current value and series-level statistics, making it possible to normalize, compare, and reshape data in ways that weren't possible before.
### Available variables
| Variable | Description |
|---|---|
| `x` | Current data point value |
| `first` | First value in the visible time window |
| `last` | Last value in the visible time window |
| `min` | Minimum value across the series |
| `max` | Maximum value across the series |
| `avg` | Average value across the series |
| `index` | Position of the current point (0, 1, 2โฆ) |
All variables are computed after `value_factor` is applied, before the transform runs.
### Normalize to zero
Display cumulative meter readings as relative consumption starting from zero:
```yaml
entities:
- entity: sensor.gas_meter
value_transform: "return x - first;"
```
A gas meter reading `2200, 2210, 2225, 2240` becomes `0, 10, 25, 40`.
### Splitting a sensor into export/import
A common use case: a single power sensor reports positive values for export and negative values for import. Use two entity entries with different transforms to separate them:
```yaml
entities:
- entity: sensor.grid_power
name: "Grid Export"
color: "#2ecc71"
value_transform: "return x > 0 ? x : 0"
- entity: sensor.grid_power
name: "Grid Import"
color: "#e74c3c"
value_transform: "return x < 0 ? -x : 0"
```
### Common expressions
| Expression | What it does |
|---|---|
| `return x - first` | Normalize to zero (cumulative โ relative) |
| `return ((x - first) / first) * 100` | Percentage change from start |
| `return (x - min) / (max - min)` | Min-max normalization (scale to 0โ1) |
| `return x - avg` | Deviation from average |
| `return x > 0 ? x : 0` | Keep only positive values (zero out negatives) |
| `return x < 0 ? -x : 0` | Keep only negative values, flip to positive |
| `return Math.abs(x)` | Absolute value |
| `return x * 1.1` | Add 10% markup |
| `return x - 273.15` | Convert Kelvin to Celsius |
| `return (x * 9/5) + 32` | Convert Celsius to Fahrenheit |
| `return Math.round(x / 100) * 100` | Round to nearest hundred |
### Editor
Entity โ General โ **Value Transform** โ a monospace text input field. Enter the expression directly (e.g., `return x - first`).
### Notes
- The expression must be valid JavaScript and include a `return` statement
- If the expression errors or returns a non-number, the original value is used unchanged
- Applied to every data point individually โ both historical and live values
- Works with all chart modes, aggregation functions, and other entity options
- Context variables (`first`, `min`, etc.) are only available when processing a full data series โ in the state row live value display, all context variables equal `x`
๐ Range Band
The Range Band feature draws a shaded min/max area behind each line entity, showing how much the value fluctuated within each aggregation bucket.

### How it works
When `points_per_hour` aggregates multiple raw data points into a single graph point, the displayed value is typically the average (or whichever `aggregate_func` you've chosen). The range band shows the **full min โ max spread** of raw values that were combined โ so you can see both the trend and the volatility.
```yaml
entities:
- entity: sensor.outdoor_temperature
show_range_band: true
color: "#ff4757"
- entity: sensor.indoor_temperature
show_range_band: false
color: "#378ADD"
```
### Use cases
- **Temperature**: narrow band = stable climate, wide band = fluctuating (e.g. HVAC cycling)
- **Energy**: see consumption spikes vs steady draw within each time bucket
- **Sensor noise**: distinguish real signal changes from noisy sensor readings
### Editor
Entity โ General โ **Range Band** toggle (next to Show Average).
### Tooltip
When hovering, an additional row shows the range: `Range: 21.2 โ 22.8 ยฐC`.
๐ Annotations
Add reference lines, event markers, and highlight bands to the graph (Timeline mode only). Configure via the editor (General Settings โ Overlays โ Annotations) or YAML.


```yaml
annotations:
- type: threshold # horizontal dashed line
value: 22.5
label: "Target"
color: "#1D9E75"
- type: threshold # dynamic value from entity
value: sensor.climate_setpoint
label: "Setpoint"
color: "#f39c12"
- type: band # horizontal shaded band
value: 20
value_end: 23
label: "Comfort zone"
color: "#1D9E75"
- type: band # dynamic band from entity attributes
value: sensor.comfort.min_temp
value_end: sensor.comfort.max_temp
label: "Dynamic comfort"
color: "#3498db"
- type: event # vertical marker at state transitions
entity: binary_sensor.heating
state: "on"
label: "Heating on"
color: "#D85A30"
- type: span # vertical band for active periods
entity: binary_sensor.heating
state: "on"
color: "#D85A30"
```
| Type | Description |
|------|-------------|
| `threshold` | Horizontal dashed line at a fixed value, entity state, or entity attribute |
| `band` | Horizontal shaded band between `value` and `value_end`. Both accept numbers, entity IDs, or `entity.attribute` paths |
| `event` | Vertical marker at each state transition of a binary entity |
| `span` | Vertical shaded band for the duration a binary entity is in a specific state |
Threshold and band values accept: `22.5` (number), `sensor.x` (entity state), `sensor.x.attribute` (entity attribute with nested path support).
Use `show_values: false` on any threshold or band to hide the value label while keeping the line/band visible:
```yaml
annotations:
- type: band
value: 20
value_end: 25
label: "Comfort"
color: "#1D9E75"
show_values: false # band visible, no text labels
```
๐ Tooltip Sync
Synchronize hover crosshairs across multiple cards on the same dashboard page. When you hover over one card, all synced cards show their tooltip and crosshair at the **same timestamp** โ even if they display different entities or different time ranges.
This is a **card-level** feature (not entity-level), because what's shared is a timestamp, not an entity value. All entities on a synced card show their values at that moment simultaneously.

### Setup
Enable Tooltip Sync on each card you want to participate, and give related cards the same Sync Group name:
```yaml
# Card 1 โ Bedroom Temperature
type: custom:statistics-graph-chart-card
tooltip_sync: true
tooltip_sync_group: "bedroom"
entities:
- entity: sensor.bedroom_temperature
# Card 2 โ Bedroom Humidity (syncs with Card 1)
type: custom:statistics-graph-chart-card
tooltip_sync: true
tooltip_sync_group: "bedroom"
entities:
- entity: sensor.bedroom_humidity
# Card 3 โ Kitchen Temperature (independent)
type: custom:statistics-graph-chart-card
tooltip_sync: true
tooltip_sync_group: "kitchen"
entities:
- entity: sensor.kitchen_temperature
# Card 4 โ Energy (no sync at all)
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.energy
```
In this setup:
- Cards 1 and 2 sync with each other (both in "bedroom" group)
- Card 3 syncs only with other "kitchen" cards
- Card 4 has no sync โ hovering over it broadcasts nothing, and it ignores broadcasts from others
### Sync Group Rules
| Sync Group value | Behavior |
|---|---|
| `"bedroom"` | Syncs only with other cards that have `tooltip_sync_group: "bedroom"` |
| `"kitchen"` | Syncs only with "kitchen" cards |
| *(empty / not set)* | Syncs with **all** tooltip-synced cards on the page, regardless of their group |
| `tooltip_sync: false` | Card does not participate in sync at all |
> **Tip:** The group name is completely arbitrary โ use room names, floor numbers, or any string you like. It just needs to match across the cards you want to link.
### How It Works
1. You hover over Card A โ a `sgc-tooltip-sync` event is dispatched on `window` containing the hovered timestamp, the sync group name, and the card's unique instance ID
2. All other cards with Tooltip Sync enabled listen for this event
3. If the group matches (or either card has no group), the receiving card calls `_showTooltipAtTime(timestamp)` โ which positions its crosshair and tooltip at the matching time position
4. When you move the mouse away, a hide event clears all synced tooltips
Cards with different `hours_to_show` ranges still sync correctly โ the shared language is the **timestamp**, not the pixel position. A card showing 24H and a card showing 7D will both jump to 2:35 PM if that's where your mouse is.
Timeline mode only.
โ๏ธ Time Offset
Compare the same sensor across different time periods by adding multiple entity entries with different `offset` values. Each offset shifts that entity's data backward in time while keeping it aligned on the same graph.
```yaml
hours_to_show: 168
entities:
- entity: sensor.energy_consumption
name: "This week"
offset: 0
color: "#ff4757"
- entity: sensor.energy_consumption
name: "Last week"
offset: 168
color: "#378ADD"
- entity: sensor.energy_consumption
name: "2 weeks ago"
offset: 336
color: "#2ecc71"
```
### How it works
- `offset: 168` means "fetch data from 168 hours (7 days) before the current display window"
- The fetched data is time-shifted forward to align with the current window on the X axis
- All rendering features work at full quality โ line, bar, step, fill, gradient, points, tooltips, stacking, zoom
- Each entity with an offset gets its own API call with the correct time range
### Common offset values
| Offset | Period |
|---|---|
| `24` | Yesterday |
| `168` | Last week |
| `336` | 2 weeks ago |
| `720` | Last month (~30 days) |
| `8760` | Last year |
### Dynamic Offset via Helper Entity
Instead of a fixed number, you can point `offset` to any HA entity whose state is a number (in hours). The card reads the entity's current state and re-fetches history automatically when it changes.
```yaml
entities:
- entity: sensor.energy_consumption
name: "Current"
- entity: sensor.energy_consumption
name: "Comparison"
offset: input_number.comparison_offset
color: "#378ADD"
```
This works with any entity type โ `input_number`, template sensors, or any sensor that outputs a numeric state. Combine with HA template sensors for fully dynamic comparisons:
```yaml
# In HA configuration.yaml
template:
- sensor:
- name: "Dynamic Offset"
state: "{{ 24 if now().weekday() < 5 else 168 }}"
unit_of_measurement: "h"
```
### Editor
Entity โ General โ Data Settings โ **Offset** (in hours).
### Notes
- Offset entities do not receive live WebSocket updates (they show historical data)
- The state row, sparkline, and gauge correctly display the last value from the offset time window โ not the live entity state
- Works with all chart modes that support multiple entities
- Can be combined with `value_transform`, `value_factor`, and all other entity options
- Each offset generates a separate cache entry, so switching between views is fast
๐ท๏ธ Template Names
Entity names support HA-style `{{ }}` templates that resolve dynamically using `hass.states`:
```yaml
name: "{{ state_attr('sensor.room', 'friendly_name') }}"
name: "{{ states('sensor.power') }} W"
name: "{{ state_attr('sensor.temperature', 'device_class') | capitalize }}"
name: "Room: {{ state_attr('sensor.room', 'friendly_name') | upper }}"
```
### Supported functions
| Function | Description |
|----------|-------------|
| `states('entity_id')` | Current state value |
| `state_attr('entity_id', 'attribute')` | Entity attribute value |
| `is_state('entity_id', 'value')` | Returns `"true"` or `"false"` |
### Supported filters
Filters are chained with `|`, just like Jinja2:
| Filter | Example | Result |
|--------|---------|--------|
| `capitalize` | `temperature` โ | `Temperature` |
| `upper` | `salon` โ | `SALON` |
| `lower` | `SALON` โ | `salon` |
| `title` | `living room` โ | `Living Room` |
| `trim` | `" text "` โ | `"text"` |
| `int` | `"22.5"` โ | `"22"` |
| `float` | `"22"` โ | `"22"` |
| `round(n)` | `22.567 \| round(1)` โ | `"22.6"` |
| `replace('a','b')` | `replace('_',' ')` | Replaces all occurrences |
| `default('val')` | Fallback if empty/unknown | |
| `truncate(n)` | Cuts to n chars + `โฆ` | |
Multiple filters can be chained: `{{ state_attr('sensor.x', 'type') | replace('_', ' ') | title }}`
๐ Battery Icon
Display a battery level indicator on the card. When a header exists (title or icon), the battery appears in the top-right corner. When there's no header, it appears on the right side of the state row.

```yaml
battery_entity: sensor.temperature_battery
battery_low_threshold: 20
```
Color adapts to battery level:
| Level | Color |
|-------|-------|
| >50% | Green |
| 25โ50% | Yellow |
| lowโ25% | Orange |
| Below threshold | Red |
The low threshold defaults to 20% and accepts a number, entity ID (`sensor.x`), or entity attribute (`sensor.x.attribute`). Hover shows the entity friendly name and exact percentage.
The icon and percentage text scale proportionally with the **Header & Battery Size** setting (`card_header_size`). This applies in both header and state row positions.
> **Editor:** General Settings โ **Display** tab โ *Battery*
๐ก Attribute Data Source
Read chart data directly from an entity attribute instead of history. The attribute must contain an array of objects with time and value fields. The X-axis automatically extends into the future when data contains future timestamps.
Ideal for energy spot prices, weather forecasts, and solar production predictions. No history or statistics API calls are made for these entities.
```yaml
entities:
- entity: sensor.epex_spot_price
data_attribute: data
data_time_field: start_time
data_value_field: price_per_kwh
value_factor: 2
graph_type: step
name: "Electricity Price"
```
Common configurations:
| Integration | `data_attribute` | `data_time_field` | `data_value_field` |
|---|---|---|---|
| EPEX Spot | `data` | `start_time` | `price_per_kwh` |
| Nordpool | `raw_today` | `start` | `value` |
| Tibber | `price_info` | `startsAt` | `total` |
| Forecast.Solar | `detailedForecasts` | `period_start` | `pv_estimate` |
Compatible with existing `value_factor`, `value_transform`, `aggregate_func`, and `group_by`. The time and value field names support nested paths via dot notation (e.g. `forecast.0.temperature`).
### Time Unit
By default, the time field is parsed as an ISO date string. Set `data_time_unit` to interpret it differently โ perfect for sensors that expose monthly summaries, hourly profiles, day-of-year datasets, or Unix timestamps without generating artificial timestamps.
| Unit | Range | Behavior |
|---|---|---|
| `iso` (default) | string / epoch ms | `new Date(t)` โ existing behavior |
| `epoch_seconds` | number | Unix timestamp in seconds |
| `epoch_ms` | number | Unix timestamp in milliseconds |
| `month_of_year` | 1..12 | First day of that month in `data_time_year` (default: current year) |
| `day_of_year` | 1..366 | That day in `data_time_year` |
| `week_of_year` | 1..53 | Monday of that ISO week in `data_time_year` |
| `hour_of_day` | 0..23 | That hour of today |
Example โ a sensor exposing monthly yield expectations as `[{Month: 1, Expectation: 320}, {Month: 2, Expectation: 489}, ...]`:
```yaml
type: custom:statistics-graph-chart-card
group_by: month
graph_start: year
hours_to_show: 8760
entities:
- entity: sensor.sma_month_yield_expectation
data_attribute: Expectation
data_time_field: Month # 1..12
data_value_field: Expectation
data_time_unit: month_of_year # interpret as Jan..Dec
graph_type: bar
aggregate_func: max
```
Renders 12 bars labelled JanโDec on the X-axis. Tooltip shows the actual month + value. All other features (date picker, group_by, fill, theming) work normally because the parser converts the numeric category into a real `Date` internally.
> **Editor:** Per-entity โ **Data** tab โ *Attribute Data Source* โ *Time Unit* dropdown and *Reference Year* input
> **Editor:** Per-entity โ **Data** tab โ *Attribute Data Source*
๐ Invert Bars (Butterfly Charts)
Per-entity `invert: true` draws bars downward from the zero line. Tooltip, state row, and extrema labels show positive values. Combined with `stacked: true`, creates butterfly charts for energy import/export, network in/out, and similar comparisons.
```yaml
stacked: true
entities:
- entity: sensor.grid_import
graph_type: bar
aggregate_func: change
color: "#f39c12"
name: Import
- entity: sensor.grid_export
graph_type: bar
aggregate_func: change
invert: true
color: "#3498db"
name: Export
```
Inverted entities automatically form their own stacking group โ normal bars stack upward from zero, inverted bars stack downward independently. The Y-axis expands symmetrically to accommodate both directions.
> **Editor:** Per-entity โ **Data** tab โ *Invert (Mirror)* checkbox
๐ External Statistics
Display data from imported statistics that don't have a regular entity in Home Assistant. This covers energy data from integrations like Gazpar, Linky, Tibber, and others that import directly into HA's statistics database.
### Background
Some HA integrations don't create `sensor.*` entities. Instead, they write data directly into the `statistics` and `statistics_meta` database tables using HA's `async_import_statistics()` API. These statistics have IDs with a colon separator (e.g. `gazpar:gazpar_consumption`) and are visible on the Energy dashboard and the built-in Statistics Graph card, but not in the entity registry.
### Setup
Use `statistic_id` instead of (or alongside) `entity`:
```yaml
entities:
- entity: ""
statistic_id: "gazpar:gazpar_consumption"
name: "Gas Consumption"
color: "#f39c12"
aggregate_func: sum
- entity: ""
statistic_id: "linky:linky_consumption"
name: "Electricity"
color: "#378ADD"
aggregate_func: sum
- entity: sensor.indoor_temperature
name: "Temperature"
color: "#ff4757"
```
You can mix external statistics with regular entities on the same card.
### How it works
- The card detects external statistics by checking for a `:` in the `statistic_id`
- Data is fetched via HA's `recorder/statistics_during_period` WebSocket API โ the same API the Energy dashboard uses
- Since there is no live state, the state row displays the last known value from the statistics data
- All card features work: tooltip, legend, axes, stacking, offset, zoom, color thresholds, etc.
### Editor
Entity โ General โ **Statistic ID** input field (monospace, below the entity picker). Set the entity picker to empty and fill in the statistic ID.
### Finding your statistic IDs
1. Go to **Developer Tools โ Statistics** in HA
2. Search for the integration name (e.g. "gazpar")
3. The statistic ID is shown in the list (e.g. `gazpar:gazpar_consumption`)
---
## ๐ก Examples
Ready-to-use YAML configurations
### Basic: Single Sensor
```yaml
type: custom:statistics-graph-chart-card
card_header: Bedroom
hours_to_show: 12
entities:
- entity: sensor.bedroom_temperature
name: Temperature
color: "#ff6b35"
icon: mdi:thermometer
```
---
### ๐ก๏ธ Multi-Entity with Dual Axes
Combine temperature and humidity on the same card without the scales conflicting.
```yaml
type: custom:statistics-graph-chart-card
card_header: Climate
card_icon: mdi:home-thermometer
hours_to_show: 24
lower_bound_secondary: "~0"
upper_bound_secondary: "~100"
entities:
- entity: sensor.temperature
name: Temperature
color: "#ff6b35"
y_axis: primary
icon: mdi:thermometer
- entity: sensor.humidity
name: Humidity
color: "#00bcd4"
y_axis: secondary
icon: mdi:water-percent
```
---
### โก Bar Chart with Legend
```yaml
type: custom:statistics-graph-chart-card
card_header: Energy Today
entities:
- entity: sensor.daily_energy
name: Consumption
graph_type: bar
color: "#2ecc71"
show_in_legend: true
aggregate_func: sum
group_by: hour
```
---
### ๐จ Color Thresholds
Colorize the graph based on value ranges. The `transition` option controls whether color changes smoothly or switches instantly at each threshold.
```yaml
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.outdoor_temperature
name: Outdoor Temp
color: threshold
state_color: threshold
color_thresholds:
enabled: true
transition: smooth # or: hard
values:
- value: 0
color: "#3498db"
- value: 15
color: "#2ecc71"
- value: 25
color: "#f39c12"
- value: 35
color: "#e74c3c"
```
Setting `color: threshold` propagates threshold colors to the state row dot as well. Setting `state_color: threshold` colors the displayed value text.
**Gradient fill is threshold-aware.** When `gradient: true` is enabled alongside `color_thresholds`, the fill area under the line is rendered as a vertical gradient whose colors match the line โ the gradient stops sample threshold colors at chart top, zero line, and chart bottom. For a chart that crosses zero with two threshold bands (e.g. purple above zero, green below), the fill blends from purple at the top through transparent at the zero line down to green at the bottom, just like the line itself.
---
### ๐ Rise/Fall Colors
Color each graph segment green when rising and red when falling โ without needing to define any value thresholds. The trend icon on the state row reflects the same direction. `trend_period_hours` controls how sensitive the detection is.
```yaml
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.stock_price
name: Price
rise_fall_colors:
enabled: true
increase: "#2ecc71"
decrease: "#e74c3c"
stable: "#95a5a6"
show_trend_icon: true
trend_period_hours: 2
```
---
### โ Average Line
Draw a dashed reference line at the mean value over the visible time window. Useful for spotting trends at a glance.
```yaml
type: custom:statistics-graph-chart-card
hours_to_show: 24
entities:
- entity: sensor.outdoor_temperature
name: Temperature
color: "#ff6b35"
show_average: true
# Multiple entities each show their own average in their own color
- entity: sensor.indoor_temperature
name: Indoor
color: "#00bcd4"
show_average: true
```
---
### ๐ Attribute Reading
Read a specific attribute instead of the main entity state. Supports dot notation for nested paths.
```yaml
type: custom:statistics-graph-chart-card
entities:
# Simple attribute
- entity: weather.home
name: Humidity
attribute: humidity
icon: mdi:water-percent
# Nested attribute (e.g. first forecast entry)
- entity: weather.home
name: Forecast Temp
attribute: forecast.0.temperature
icon: mdi:thermometer
```
---
### ๐ State Map โ Non-Numeric Entities
Use `state_map` to graph entities with string states like `input_boolean`, `binary_sensor`, or `input_select`. States are mapped to numbers in the order they are listed, starting at 0.
**The Y-axis automatically shows the original state names instead of numeric indexes** โ so a washing machine graph displays `idle`, `running`, `done` on the axis, not `0`, `1`, `2`. Tooltips and state rows match.
You can optionally provide friendly display labels with the `label` field โ useful when the raw state is technical (`armed_home`) but you want a cleaner axis (`Home`):
```yaml
type: custom:statistics-graph-chart-card
entities:
# binary_sensor โ 0 (off) / 1 (on), axis shows "off" / "on"
- entity: binary_sensor.front_door
name: Front Door
color: "#9b59b6"
graph_type: step
state_map:
- value: "off"
- value: "on"
# With friendly labels โ axis shows "Idle" / "Running" / "Done"
- entity: sensor.washing_machine
name: Washing Machine
graph_type: step
state_map:
- value: "idle"
label: Idle
- value: "running"
label: Running
- value: "done"
label: Done
# input_select โ 0 / 1 / 2 / 3
- entity: input_select.heating_mode
name: Heating Mode
state_map:
- value: "off"
- value: "eco"
- value: "comfort"
- value: "boost"
```
In the visual editor, the State Map textarea accepts a simple `value, label` syntax โ one per line:
```
off, Idle
on, Running
```
> Auto-detected for `binary_sensor`, `input_boolean`, and any `input_select` entity in step mode โ you don't need to define a `state_map` for those, the card detects available states automatically and labels the axis accordingly.
---
### ๐ Fixed Value Reference Line
Draw a flat horizontal line at the current value of an entity. Useful for showing targets or limits alongside historical data.
```yaml
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.room_temperature
name: Temperature
color: "#ff6b35"
- entity: input_number.target_temperature
name: Target
color: "#2ecc71"
fixed_value: true
show_fill: false
line_width: 1.5
```
---
### ใฐ๏ธ Soft Bounds
Use a `~` prefix to create a soft bound โ the axis will prefer the value but expand if data exceeds it. Hard bounds (no prefix) force the axis edge regardless of data.
```yaml
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.battery_level
name: Battery
lower_bound: "~0" # prefer 0 as minimum; expands if data goes below
upper_bound: "~100" # prefer 100 as max; expands if data exceeds
```
---
### ๐ก Dynamic Y Axis Bounds
Bind the Y axis min/max to another sensor for a fully dynamic range.
```yaml
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.power_output
name: Power
lower_bound: 0
upper_bound: sensor.max_capacity
```
---
### ๐ Tap Actions
Trigger actions when tapping an entity's state row.
```yaml
type: custom:statistics-graph-chart-card
entities:
# Open entity detail dialog
- entity: sensor.temperature
tap_action:
action: more-info
# Navigate to another dashboard
- entity: sensor.energy
tap_action:
action: navigate
navigation_path: /lovelace/energy
# Call a service
- entity: binary_sensor.pump
tap_action:
action: call-service
service: switch.toggle
service_data:
entity_id: switch.pump
```
---
### โฉ Sparse Data with Points Per Hour
For sensors that update infrequently (e.g. weather), use a higher `points_per_hour` with forward-fill. Empty buckets inherit the last known value, producing a clean step-line instead of scattered dots.
```yaml
type: custom:statistics-graph-chart-card
points_per_hour: 12
hours_to_show: 24
entities:
- entity: weather.home
attribute: humidity
name: Humidity
smooth: false # step-like appearance is more accurate for infrequent updates
```
---
### ๐๏ธ Interval Picker & Attribute Switcher
Add on-card controls for quick time range switching and live attribute exploration โ no need to open the editor.
```yaml
type: custom:statistics-graph-chart-card
card_header: Weather Station
hours_to_show: 24
show_interval_picker: true
interval_picker_position: left
show_attribute_list: true
attribute_list_position: right
entities:
- entity: weather.home
name: Temperature
attribute: temperature
color: "#ff6b35"
- entity: weather.home
name: Humidity
attribute: humidity
color: "#00bcd4"
```
The interval picker displays buttons for the default set: 1H, 2H, 4H, 8H, 12H, 24H, and 7D. Clicking a button temporarily overrides `hours_to_show`; clicking again deselects it and returns to the original range.
To customize which buttons appear, use `interval_options`:
```yaml
# Show only the intervals you need โ fits on one row on mobile
show_interval_picker: true
interval_options:
- "2H"
- "12H"
- "24H"
- "7D"
- "30D"
```
Available labels: `1H`, `2H`, `4H`, `8H`, `12H`, `24H`, `3D`, `7D`, `14D`, `30D`, `90D`, `6M`, `1Y`. The editor also provides a **Visible Intervals** checkbox grid under the Interval Picker toggle (General Settings โ Overlays).
The attribute list shows a dropdown per entity with a color-coded dot. Select any numeric attribute to instantly re-graph with that data โ the graph, state row, and tooltip all update live.
Both controls share a single toolbar row and wrap automatically on narrow cards.
---
### ๐ Scrollable Graph
Load a wide time range but show only a portion at a time โ scroll to explore.
```yaml
type: custom:statistics-graph-chart-card
card_header: Weekly Overview
hours_to_show: 168 # 7 days of data
max_visible_interval: 24 # show 24h at a time
scroll_mode: wheel # or: scrollbar
entities:
- entity: sensor.temperature
color: "#ff6b35"
```
The graph starts scrolled to the right (most recent data). Y-axis labels stay fixed while the graph content scrolls underneath. Scroll position is preserved across HA state updates.
| `scroll_mode` | Behavior |
|---------------|----------|
| `scrollbar` | Thin visible scrollbar *(default)* |
| `wheel` | Mouse wheel scrolls horizontally, no visible scrollbar |
On mobile/touch devices, swipe always works regardless of the scroll mode setting.
> ๐ก Combines well with the **Interval Picker** โ select "7D" to get a wide range, then scroll through it with a 6-hour visible window.
---
### โ๏ธ Icon Position
Place the header icon on the right side for a different layout feel.
```yaml
type: custom:statistics-graph-chart-card
card_header: Living Room
card_icon: mdi:thermometer
card_icon_position: right # default: left
entities:
- entity: sensor.temperature
color: "#ff6b35"
```
---
### ๐ Full Example
A complete card showing most features together.
```yaml
type: custom:statistics-graph-chart-card
card_header: Home Climate
card_icon: mdi:home-thermometer
card_icon_color: "#ff6b35"
align_header: left
hours_to_show: 24
points_per_hour: 6
height: 180
show_grid: true
show_tooltip: true
animate_graph: false
update_interval: 60
entities:
- entity: sensor.living_temperature
name: Temperature
color: "#ff6b35"
icon: mdi:thermometer
y_axis: primary
show_in_legend: true
show_extrema: click
show_average: true
show_trend_icon: true
trend_period_hours: 2
decimals: 1
gradient: true
state_adaptive_color: true
color_thresholds:
enabled: true
transition: smooth
values:
- value: 18
color: "#3498db"
- value: 22
color: "#2ecc71"
- value: 28
color: "#e74c3c"
- entity: sensor.living_humidity
name: Humidity
color: "#00bcd4"
icon: mdi:water-percent
y_axis: secondary
show_in_legend: true
decimals: 0
lower_bound: "~0"
upper_bound: "~100"
```
---
## ๐ Reference
Aggregation functions, date formats, bounds, tap actions
### ๐งฎ Aggregation Functions
| Value | Description |
|-------|-------------|
| `avg` | Mean of all points in the bucket *(default)* |
| `min` | Lowest value |
| `max` | Highest value |
| `last` | Most recent value |
| `first` | Oldest value |
| `median` | Middle value |
| `sum` | Sum of all values (useful for energy) |
| `delta` | Last minus first (net change) |
| `diff` | Max minus min (spread) |
---
### ๐ Date Formats
Set `datetime_format` at the card level to control how timestamps appear on the X-axis, tooltips, and extrema labels. `system` follows HA's locale setting. All other formats are applied regardless of locale โ useful when your dashboard is shared across regions or when you need a more compact display.
> **Note:** In earlier versions, `datetime_format` was an entity-level option. It has been promoted to a card-level setting. Entity-level values still work for backward compatibility and override the card setting when present.
#### Smart X-Axis Labels
When using the default `system` format, the X-axis automatically adapts