-
Notifications
You must be signed in to change notification settings - Fork 3
Examples
- Basic: Single Sensor
- 🌡️ Multi-Entity with Dual Axes
- ⚡ Bar Chart with Legend
- 🎯 Period Highlight
- 🎨 Color Thresholds
- 📈 Rise/Fall Colors
- 🎨 Color Templates
- ➖ Average Line
- 🔗 Attribute Reading
- 🔀 State Map — Non-Numeric Entities
- 📏 Fixed Value Reference Line
- 〰️ Soft Bounds
- 📡 Dynamic Y Axis Bounds
- 👆 Tap Actions
- 🌅 Dynamic Graph Hours
- ⏩ Sparse Data with Points Per Hour
- 🎚️ Interval Picker & Attribute Switcher
- 🔍 Scrollable Graph
↔️ Icon Position- 🏆 Full Example
type: custom:statistics-graph-chart-card
card_header: Bedroom
hours_to_show: 12
entities:
- entity: sensor.bedroom_temperature
name: Temperature
color: "#ff6b35"
icon: mdi:thermometerCombine temperature and humidity on the same card without the scales conflicting.
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-percenttype: 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: hourshow_in_legend: true prints the stats row; choose which numbers with legend_stats — any combination of min, avg, max, last, sum and, new in v3.32, live (the entity's state right now, whatever period the chart shows).
On bar charts, hovering a bar shades the background of the entire period under the cursor — a soft band spanning the full bar slot — so it is immediately clear which period a tooltip or value belongs to. It is most useful with several entities drawn side by side, where the thin gaps between adjacent periods otherwise make the boundaries hard to read.
type: custom:statistics-graph-chart-card
period_highlight: true
period_highlight_color: rgba(128,128,128,0.3) # optional; empty = subtle theme grey
graph_type: bar
group_by: date
entities:
- sensor.garage_temp
- sensor.kids_room_temp
- sensor.living_room_temp- Off by default. Enable with
period_highlight: true. -
period_highlight_coloraccepts any CSS color (hex, rgba, name) or variable. You can also set the--sgc-period-highlight-colorCSS variable from a theme orcard_mod. Leave it empty for a subtle theme grey. - The band follows the hovered period, so it lines up exactly with the bar group beneath it.
- Works whether or not
show_tooltipis enabled — turn the tooltip off and you still get the period band on hover. - In the visual editor it lives in the Tooltip section.
- Available in Timeline mode (bar and line charts).
Colorize the graph based on value ranges. Two independent settings control the behavior:
-
Direction — which axis the colors are painted along:
-
vertical(default) — Y-axis gradient. The entire chart is colored based on value height. -
horizontal— per-segment coloring along the time axis. Each line segment gets the color matching its data value.
-
-
Transition — how colors change at threshold boundaries:
-
smooth(default) — gradual interpolation between adjacent threshold colors. -
hard— instant color switch exactly at the threshold value.
-
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.outdoor_temperature
name: Outdoor Temp
color: threshold
state_color: threshold
color_thresholds:
enabled: true
direction: vertical # or: horizontal
transition: smooth # or: hard
values:
- value: 0
color: "#3498db"
- value: 15
color: "#2ecc71"
- value: 25
color: "#f39c12"
- value: 35
color: "#e74c3c"All four direction × transition combinations are available from the editor under Colors → Color Thresholds.
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.
Dynamic thresholds from entities. Both the value and the color of each threshold entry can be an entity reference instead of a fixed literal. Use sensor.x for an entity's state or sensor.x.attribute for one of its attributes (nested attribute paths are supported). This lets thresholds track other sensors — a seasonal comfort target, a calculated limit, or a color served by a template sensor — and they update live as those entities change, without waiting for the next data refresh.
color_thresholds:
enabled: true
values:
- value: sensor.heating_setpoint # threshold follows a sensor's state
color: "#3498db"
- value: sensor.comfort.upper # or one of its attributes
color: sensor.theme_colors.warn # the color can be entity-driven tooColor each graph segment green when rising and red when falling — without needing to define any value thresholds. trend_period_hours controls how sensitive the detection is.
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.stock_price
name: Price
rise_fall_colors:
enabled: true
increase: "#2ecc71"
decrease: "#e74c3c"
stable: "#95a5a6"
trend_period_hours: 2Use Jinja2 templates in any color field to manage colors centrally. Create a single template sensor with all your entity colors, and every card updates when you change it.
Setup: Create a central color sensor
# configuration.yaml → template section
template:
- sensor:
- name: "Entity Colors"
unique_id: entity_colors_map
state: "ok"
attributes:
entities: >-
{{
{
"Temperature": "#FF6B6B",
"Humidity": "#2ecc71",
"Solar": "#f1c40f"
}
}}Usage in card YAML:
entities:
- entity: sensor.temperature
color: "{{ state_attr('sensor.entity_colors','entities')['Temperature'] | default('#ff4757') }}"
icon_color: "{{ states('input_select.theme_accent') }}"Templates are evaluated server-side by HA via WebSocket subscriptions — colors update automatically when dependencies change, with no polling. In the editor, typing {{ in any color field dims the picker automatically.
Works with color, point_colors, icon_color, state_color, and all card-level color options (y_axis_color, x_axis_color, y_grid_color, x_grid_color, card_icon_color).
Draw a dashed reference line at the mean value over the visible time window. Useful for spotting trends at a glance.
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: trueRead a specific attribute instead of the main entity state. Supports dot notation for nested paths.
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:thermometerSince v3.32 you no longer have to hand-write a
name:just to tell two attributes of the same entity apart. Setinclude_attribute_name: trueat card level forHome · Humidity, oruse_only_attribute_name: truefor justHumidity— applied to the state row, legend, tooltip, stats and exports. Rows that plot the entity state itself, and rows with an explicitname:, are left alone.
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. The chart tooltip shows the matching entry's label too (nearest entry when values are aggregated) — improved in v3.29: timeline tooltips previously showed the numeric index.
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):
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 value, label, color syntax — one line per state, with the label and color both optional. Any CSS color works (name, hex, or var(--…)):
off, Idle, grey
on, Running, green
These colors are used as the segment color in state_timeline mode (and for the dot/marker elsewhere). Colors set in YAML — color: under a state_map entry — are preserved when you re-open the card in the editor.
Auto-detected for
binary_sensor,input_boolean, and anyinput_selectentity in step mode — you don't need to define astate_mapfor those, the card detects available states automatically and labels the axis accordingly.
state_map also works as a pure axis-label list for numeric sensors: entries that never match the state are ignored for data (the numeric value passes through), but the axis and tooltip still use them as labels. Combined with value_transform, this turns a wind-direction sensor (0–360°) into a compass chart — no custom formatter functions needed:
type: custom:statistics-graph-chart-card
title: Daily Wind Direction
graph_start: day
group_by: interval
points_per_hour: 2 # 30-minute buckets
show_y_axis: true
y_axis_ticks: 8 # a label every 45° (N, NE, E, …); use 16 for all sectors
entities:
- entity: sensor.wind_direction
name: Wind Direction
aggregate_func: avg
decimals: 0
unit: ""
value_transform: "return 16 - (((x % 360) + 360) % 360) / 22.5;"
state_map: # axis labels, bottom → top (index 0..16)
- value: ""
- value: "NNW"
- value: "NW"
- value: "WNW"
- value: "W"
- value: "WSW"
- value: "SW"
- value: "SSW"
- value: "S"
- value: "SSE"
- value: "SE"
- value: "ESE"
- value: "E"
- value: "ENE"
- value: "NE"
- value: "NNE"
- value: "N"The transform maps 0° (N) to the top of the axis and the tooltip shows the compass name of the hovered value (SSW, not 202°). The empty first entry keeps N from being printed twice (0° and 360° are the same direction).
Two honest limitations of the recipe:
-
The last sliver before due north (≈349°–360°) rounds onto that unlabeled wrap entry, so the tooltip shows a small number there instead of
N. If northerly winds dominate your site, give the first entryvalue: "N"instead — the tooltip then always readsN, at the cost of the axis printingNat the bottom rather than the top. -
Averaging compass degrees is circular math done linearly: a bucket whose samples straddle the 0°/360° seam (e.g. 350° and 10°) averages to ~180° and gets labeled
S. This artifact is inherent toavgon wind degrees — the apexcharts setup this recipe replaces has exactly the same behavior.
Draw a flat horizontal line at the current value of an entity. Useful for showing targets or limits alongside historical data.
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.5Use 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.
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 exceedsBind the Y axis min/max to another sensor for a fully dynamic range.
type: custom:statistics-graph-chart-card
entities:
- entity: sensor.power_output
name: Power
lower_bound: 0
upper_bound: sensor.max_capacityTrigger actions when tapping an entity's state row.
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
# Fire DOM event (browser_mod popup, YAML only)
- entity: sensor.power
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
content:
type: custom:mini-graph-card
entity: sensor.powerFilter data to specific hours each day using sensor values. Ideal for solar panels (sunrise to sunset) or business hours.
type: custom:statistics-graph-chart-card
graph_start_hour: sensor.sunrise_hour
graph_end_hour: sensor.sunset_hour
hours_to_show: 168
show_date_picker: true
entities:
- entity: sensor.solar_powerCreate template sensors that output fractional hours:
template:
- sensor:
- name: "Sunrise Hour"
unique_id: sunrise_hour
state: >
{% set dt = state_attr('sun.sun', 'next_rising') | as_datetime | as_local %}
{{ dt.hour + dt.minute / 60 }}
- name: "Sunset Hour"
unique_id: sunset_hour
state: >
{% set dt = state_attr('sun.sun', 'next_setting') | as_datetime | as_local %}
{{ dt.hour + dt.minute / 60 }}When viewing multiple days, data outside the specified hours is hidden and lines break naturally between days. Both graph_start_hour and graph_end_hour accept fixed numbers (6, 22, 6.5 for 06:30) or entity IDs.
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.
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 updatesAdd on-card controls for quick time range switching and live attribute exploration — no need to open the editor.
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:
# 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. The dropdown uses Home Assistant's own translated attribute names, the same wording include_attribute_name / use_only_attribute_name put in the series label, so the picker and the label can't disagree — and if you switch those options on, the label follows whatever attribute you pick here.
Both controls share a single toolbar row and wrap automatically on narrow cards.
Load a wide time range but show only a portion at a time — scroll to explore.
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.
Place the header icon on the right side for a different layout feel.
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"A complete card showing most features together.
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
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"