ApexCharts card - A highly customizable graph card

You could achieve this with color thresholds, but I would start by changing the curve to stepline instead of smooth

Is there a way to make the y-axis label integers (or at least limit all these decimal places)?

layout_options:
  grid_columns: 10
experimental:
  disable_config_validation: true
type: custom:apexcharts-card
header:
  show: true
  title: Battery Discharge vs Mileage
apex_config:
  chart:
    height: 250
  stroke:
    width: 3
    curve: stepline
  grid:
    strokeDashArray: 0
    borderColor: rgba(150, 150, 150, 0.2)
    xaxis:
      lines:
        show: true
    yaxis:
      lines:
        show: true
  yaxis:
    - id: left-axis
      opposite: false
      min: 0
      max: 120
      title:
        text: Distance (miles)
        style:
          fontSize: 14px
          fontWeight: normal
          fontFamily: Arial
          color: "#888"
      labels:
        style:
          colors: "#888"
          fontSize: 14px
          fontFamily: Arial
          fontWeight: normal
      axisBorder:
        show: true
        color: "#e0e0e0"
        width: 2
    - id: right-axis
      opposite: true
      min: 0
      max: 100
      title:
        text: Battery Charge (%)
        style:
          fontSize: 14px
          fontWeight: normal
          fontFamily: Arial
          color: "#888"
      labels:
        style:
          colors: "#888"
          fontSize: 14px
          fontFamily: Arial
          fontWeight: normal
      axisBorder:
        show: true
        color: "#e0e0e0"
        width: 2
  xaxis:
    axisBorder:
      show: true
      color: "#e0e0e0"
      height: 2
update_interval: 30s
graph_span: 48h
series:
  - entity: sensor.volvo_ex30_trip_meter_automatic
    name: Distance (Manual)
    yaxis_id: left-axis
  - entity: sensor.volvo_ex30_battery_charge_level
    name: Battery
    transform: "return (x === '0.0') ? null : x;"

Hello everyone,
Is there a way to change the background color of datalabels or the text color of datalabels for one series?
My problem: I have a series where the color is white and the background color of the data label is also white… with white text… :worried:
I’ve searched everywhere but haven’t found anything to change this.

This card is nice, but i have a question:

I use it for my 3d printer temperatures. Is it possible to use a span from entities?
I have a entity which i want to use as start time (the time the print started). I also have an entity with the ETA which i want to use as end time. So i have a time span from print start to print end and have a now bar which pushes between it.

Is that possible?

Hi everyone

I’m having some issues using ApexCharts.

I’m trying to make a charts over the last 4 years of wood consumption

As you can see on the picture the date for january is hidden behind y axis
And there is such strange data from a thirteenth month

graph_span: 1y
span:
  start: year

I just started to use ApexChart so if someone can just let me know what i’m doing wrong.

Alos do you think it’s possible to start the year on september instead of January ?

Thanks for your help

Here is the full code of my card

type: custom:apexcharts-card
header:
  show: true
  title: Pellets • Comparatif mensuel (2026 vs 2023-2024)
graph_span: 1y
span:
  start: year
now:
  show: false
series:
  - entity: sensor.pellets_sacs_total
    name: "2025"
    type: column
    color: "#F39C12"
    statistics:
      type: change
      period: month
      align: start
  - entity: sensor.pellets_sacs_total
    name: "2025"
    type: line
    color: "#3498DB"
    stroke_width: 3
    offset: "-1y"
    statistics:
      type: change
      period: month
      align: start
  - entity: sensor.pellets_sacs_total
    name: "2024"
    type: line
    color: "#2ECC71"
    stroke_width: 3
    offset: "-2y"
    statistics:
      type: change
      period: month
      align: start
  - entity: sensor.pellets_sacs_total
    name: "2023"
    type: line
    color: "#9B59B6"
    stroke_width: 3
    offset: "-3y"
    statistics:
      type: change
      period: month
      align: start
apex_config:
  legend:
    show: true
    position: top
    onItemClick:
      toggleDataSeries: true
    onItemHover:
      highlightDataSeries: true
  tooltip:
    shared: true
    intersect: false
  xaxis:
    tickAmount: 12
    labels:
      format: MMM
      rotate: -30
      hideOverlappingLabels: false
      showDuplicates: false
  plotOptions:
    bar:
      columnWidth: 100%


How can I display the legend in a single line?

type: custom:apexcharts-card
graph_span: 36mo
style:
  width: 100%
  padding: 0px !important
  margin: 0px !important
header:
  show: false
  floating: true
  title: 燃气用量历史统计
  show_states: false
all_series_config:
  stroke_width: 7
  show:
    in_header: false
    legend_value: false
series:
  - entity: sensor.ran_qi_zhang_dan_lie_biao
    type: column
    name: 2023年
    unit: m³
    color: "#4CAF50"
    data_generator: |
      const data = entity.attributes.enhanced_bill_list;
      if (data) {
        const parsed = JSON.parse(data);
        return parsed
          .filter(item => item.billYear === 2023)
          .map(item => {
            let dateStr = item.billYm;
            if (dateStr.includes('年')) {
              dateStr = dateStr.replace('年', '-').replace('月', '');
            }
            const date = new Date(dateStr + '-01');
            const extra = `${item.thisReadTime}<br>${item.lastReadTime}`;
            return [date.getTime(), parseFloat(item.gasAmt) || 0, extra];
          })
          .sort((a, b) => a[0] - b[0]);
      }
      return [];
  - entity: sensor.ran_qi_zhang_dan_lie_biao
    type: column
    name: 2024年
    unit: m³
    color: "#2196F3"
    data_generator: |
      const data = entity.attributes.enhanced_bill_list;
      if (data) {
        const parsed = JSON.parse(data);
        return parsed
          .filter(item => item.billYear === 2024)
          .map(item => {
            let dateStr = item.billYm;
            if (dateStr.includes('年')) {
              dateStr = dateStr.replace('年', '-').replace('月', '');
            }
            const date = new Date(dateStr + '-01');
            const extra = `${item.thisReadTime}<br>${item.lastReadTime}`;
            return [date.getTime(), parseFloat(item.gasAmt) || 0, extra];
          })
          .sort((a, b) => a[0] - b[0]);
      }
      return [];
  - entity: sensor.ran_qi_zhang_dan_lie_biao
    type: column
    name: 2025年
    unit: m³
    color: "#FF9800"
    data_generator: |
      const data = entity.attributes.enhanced_bill_list;
      if (data) {
        const parsed = JSON.parse(data);
        return parsed
          .filter(item => item.billYear === 2025)
          .map(item => {
            let dateStr = item.billYm;
            if (dateStr.includes('年')) {
              dateStr = dateStr.replace('年', '-').replace('月', '');
            }
            const date = new Date(dateStr + '-01');
            const extra = `${item.thisReadTime}<br>${item.lastReadTime}`;
            return [date.getTime(), parseFloat(item.gasAmt) || 0, extra];
          })
          .sort((a, b) => a[0] - b[0]);
      }
      return [];
  - entity: sensor.ran_qi_zhang_dan_lie_biao
    type: line
    name: 月账单
    unit: 元
    color: "#FF5722"
    stroke_width: 1
    curve: smooth
    yaxis_id: y2
    data_generator: |
      const data = entity.attributes.enhanced_bill_list;
      if (data) {
        const parsed = JSON.parse(data);
        return parsed
          .map(item => {
            let dateStr = item.billYm;
            if (dateStr.includes('年')) {
              dateStr = dateStr.replace('年', '-').replace('月', '');
            }
            const date = new Date(dateStr + '-01');
            const extra = `${item.thisReadTime}<br>${item.lastReadTime}`;
            return [date.getTime(), parseFloat(item.billAmt) || 0, extra];
          })
          .sort((a, b) => a[0] - b[0]);
      }
      return [];
apex_config:
  chart:
    height: 220
    margin:
      top: 10
      left: 10
      right: 10
      bottom: 10
    toolbar:
      show: true
      tools:
        download: true
        selection: true
        zoom: true
        zoomin: true
        zoomout: true
        pan: true
        reset: true
  plotOptions:
    bar:
      columnWidth: 100%
      borderRadius: 4
  xaxis:
    type: datetime
    tickPlacement: between
    labels:
      datetimeFormatter:
        year: yyyy
        month: M
        day: d MMM
      rotate: -45
    axisTicks:
      show: true
    axisBorder:
      show: true
  yaxis:
    - id: y1
      title:
        text: 用气量 (m³)
      min: 0
      max: 85
    - id: y2
      opposite: true
      title:
        text: 费用 (元)
      min: 0
      max: 220
  tooltip:
    x:
      format: yyyy年M月
    style:
      fontSize: 11px
      padding: 8px
  legend:
    show: true
    position: top
    horizontalAlign: center
    fontSize: 10px
    itemWidth: auto
    width: 100%
    height: auto
    wrap: false
    floating: true
    itemMargin:
      horizontal: 5
      vertical: 2
    offsetX: 40
    offsetY: 5
    onItemClick:
      toggleDataSeries: true
    onItemHover:
      highlightDataSeries: true
  noData:
    text: 暂无数据
    style:
      fontSize: 16px

Hi everyone, I was wandering if it is possible to style/format the extremas values? I have not specified anything and the background appears in the color of the series, font is black and there is a red border. I’ve seen some pictures without border, other font color, but always the background matching the series.

is it possible at all?

Apexcharts graph lost?

I’m using Apexcharts to monitor electricity at spot prices, but recently something weird happened.

The same YAML code that displays the bar graph correctly on Sonoff NSPanel Pro only shows the graph header on the Android phone screen.

I’v tried V2.1.2, but it didn’t solve the issue.

1 Like

Having the same issue. I have a feeling I missed reading something before performing an important update that has been done :slight_smile:

I would like my headers to have the same size as all my other text on the dashboard. Now it looks very out of sync.
I tried the card mod below, and I can see it has impact op the font size for the state value and state name. However, they are still different in size and larger than all the other text on my dashboard.
Can someone point me to what is additionally scaling these boxes?

card_mod:
  style: |
    #state__value {
      font-size: var(--ha-font-size-m) !important;
      font-weight: var(--ha-font-weight-m) !important;
    }
    #state__name {
      font-size: var(--ha-font-size-m) !important;
      font-weight: var(--ha-font-weight-m) !important;
    }    


The upper tekst is state__value, the lower is state__name

Hi all, I’d love some help with a data_generator, I’ve spent hours on this and either I’m not getting it, or what I want to achieve is impossible!

I have a sensor that logs the daily incremental power consumption of a smart plug, resetting every day, which I use it to keep track of my walking pad usage. It’s a template Statistics sensor that looks like this:

I’ve managed to create an ApexChartsCard showing the daily max (so total daily time) as a bar chart:

Bar chart YAML code

`type: custom:apexcharts-card
grid_options:
columns: 12
apex_config:
xaxis:
type: datetime
labels:
format: ddd
chart:
height: 200px
dataLabels:
enabled: true
style:
colors:
- “#FFF
background:
borderWidth: 1
opacity: 1
foreColor: “#000
borderColor: “#FFF
formatter: |
EVAL: (x) => {
if (x>0)
return Math.floor(x) + "h " + Math.round((x-Math.floor(x))*60) + "m ";
}
annotations:
yaxis:
- “y”: 1
borderColor: “#fff
label:
text: 1h Min
borderWidth: 1
style:
color: “#000
background: “#f2a134
- “y”: 2
borderColor: “#fff
label:
text: 2h Ideal
borderWidth: 1
style:
color: “#000
background: “#bbdb44
- “y”: 3
borderColor: “#fff
label:
text: 3h Super
borderWidth: 1
style:
color: “#000
background: “#44ce1b
experimental:
color_threshold: true
graph_span: 1w
span:
start: isoWeek
header:
show: true
title: Daily walking time this week
series:

  • entity: sensor.daily_walking_time
    type: column
    opacity: 0.75
    group_by:
    func: max
    duration: 1d
    fill: zero
    show:
    datalabels: true
    header_color_threshold: true
    as_duration: hour
    color_threshold:
    • value: 2.5
      color: “#44ce1b
    • value: 2
      color: “#bbdb44
    • value: 1.5
      color: “#f7e379
    • value: 1
      color: “#f2a134
    • value: 0.5
      color: “#e51f1f
      yaxis:
  • min: 0.001
    max: 4
    decimals: 0
    apex_config:
    tickAmount: 4
    stepSize: 1
    forceNiceScale: true
    labels:
    formatter: |
    EVAL: (x) => {
    return Math.floor(x) + "h " + Math.round((x-Math.floor(x))*60) + "m ";
    }
    `

What I’d like to do is to show the same data but on a weekly bases, so I need to aggregate the daily max by week. I thought it wouldn’t be too hard using data_generator, but I can’t for the life of me figure out how to access the sensor data as a series (timestamp, state) so I can do the aggregation in Javascript and then rebuild the series to be used by the chart.

Every example and documentation I found for data_generator seems to imply the historical data is in one of the attributes, but as you can see above this is not the case here. I’ve tried with a simple console.log(entity) in the generator and all I can see is the current state (along with last changed and updated) and the static attributes above. No “data” or anything like that. Have I completely misunderstood the implementation?

BTW, I know I could create another sensor to store the daily max and aggregate that, as I could create one already aggregated per week. I could also (done that a bunch) create a SQL sensor to extract the aggregated data. I was looking for (if possible) a solution that could be implemented in the card and reused, without having to create other sensors. I have a whole bunch of use cases for many different sensors and I’d like to avoid creating many, many additional sensors.

Thank you!

I am trying to implement the apexchart card for my solar income per monthn. I have a sensor for each month. Is it possible to have only one entity per column/bar?
Now if i use all my 12 sensors in series, it seems every month gets a bar for each sensor.

Also the columns/bars are very thin.

Sugges to have a look at data_generator option. You can get all your sensor values from hass.states object available in the javascript generator function. So roughly you would code up to match the date with the month’s sensor. You might be able to make this easier by creating a template helper to have your monthly sensor values as attributes, then you that as your entity in the series, making the data_generator a bit simpler as it would be mapping the attributes to datetime data points of the generator, if that makes sense.

oh, didn’t thought about goning so complex. Thought apex card could solve my task in heaving a graph with a bar for each month and assign a sensor to each bar.
Maybe there is another card which fits better for my task?

If you want just a distribution then perhaps the new stock distrubition card would be the simplest.

Sounds interessting. Is this card implemented in core version, because i do not have this card in my current version 2025.12.4
Frontend: 20251203.3

New in 2026.2

1 Like

In general it does what i want. But i want to display this information as bars for each month in current year. A bar for each sensor. It could also be a card with one bar for each sensor and i give them a label.

I found a bar-card but this seems to have a bug when edit the yaml. This card would do what i want.

It is strange that so many complex cards exist but not such a simple vertical bar card. Saddly my skills are not high enought to build one of my own. Maybe some day.

Update
I could solve it with the linear-gauge-card

Can somebody tell me why this Apexcharts YAML code doesn’t show the graph anymore?

Moreover, when I create a Manual card on the Dashboard, the system says it was successfully saved, but the card doesnät appear on the Dashboard.

type: custom:apexcharts-card
update_interval: 10min
header:
show: false
title: Pörssisähkö, snt/kWh
graph_span: 34h
span:
start: hour
apex_config:
legend:
show: false
annotations:
yaxis:
- “y”: 5
borderColor: “#2ecc71
strokeDashArray: 3
label:
text: 5 snt/kWh
style:
color: “#2ecc71
- “y”: 10
borderColor: “#f1c40f
strokeDashArray: 3
label:
text: 10 snt/kWh
style:
color: “#f1c40f
- “y”: 20
borderColor: “#e74c3c
strokeDashArray: 3
label:
text: 20 snt/kWh
style:
color: “#e74c3c
series:

  • entity: sensor.electricity_prices
    type: column
    name: <5
    color: “#2ecc71
    data_generator: |
    return entity.attributes.data
    .filter(e => e.price <= 5)
    .map(e => [e.start * 1000, e.price]);
  • entity: sensor.electricity_prices
    type: column
    name: 5–10
    color: “#f1c40f
    data_generator: |
    return entity.attributes.data
    .filter(e => e.price > 5 && e.price <= 10)
    .map(e => [e.start * 1000, e.price]);
  • entity: sensor.electricity_prices
    type: column
    name: “>10 snt/kWh”
    color: “#e74c3c
    data_generator: |
    return entity.attributes.data
    .filter(e => e.price > 10)
    .map(e => [e.start * 1000, e.price]);

Does anyone know if conditions can be used in the data_generator? I can’t get if else to work.