ApexCharts card - A highly customizable graph card

Yeah - the problem seems to be that there is no way to set the center point or origin for area graphs (that I can find anyway) - zero is just assumed and it looks like it would take multiple workarounds to get the display I’m trying for. Maybe I’ll put in a feature request for this.

Is it possible to show all values when hovering? It does show all values when you have group by last:

group_by:
  func: last

Without that it only shows 1 value:

I tried setting the tooltip options, but it doesn’t seem to do anything:

apex_config:
  tooltip:
    shared: true
    intersect: false

Hey, I am having problem with the style for my apex card. For some reason when I do the style as I should in the apex charts style-element, it simply refuses to use it. But if I do it the way I shouldnt do it, with card_mod, then it works. The problem is that the chart background flashes and shakes for a moment when it reloads. I would prefer to do it using the style: element, but why doesnt it work?

I added both examples in the same code, naturally I only try them one at a time.

type: custom:apexcharts-card
            style: |
               ha-card {                   
                    border: none;   
                    margin-top: 10px;
                    margin-left: 0px;
                    background: transparent;
                }     
            chart_type: donut
            show:
              loading: false
            header:
              title: ''
              show_states: false
              colorize_states: true
              show: false
            series:
              - entity: sensor.qubino_3_phase_smart_meter_electric_consumption_kwh
                name: Climate
                statistics:
                  type: change
                  period: day
              - entity: sensor.easee_lifetime_energy
                name: Easee
                statistics:
                  type: change
                  period: day
              - entity: sensor.ovrigt_lifetime_energy
                name: Övrigt
                statistics:
                  type: change
                  period: day
                unit: kWh
              - entity: sensor.diskmaskin_lifetime_energy
                name: Diskmaskin
                statistics:
                  type: change
                  period: day
              - entity: sensor.frysbox_lifetime_energy
                name: Frysbox
                statistics:
                  type: change
                  period: day
              - entity: sensor.honshus_lifetime_energy
                name: Honshus
                statistics:
                  type: change
                  period: day  
            color_list:
              - '#F18303'  # Climate
              - '#EA23FB'  # Easee
              - '#4287f5'  # Övrigt
              - '#42f5d1'  # Diskmaskin
              - '#42f584'  # Frysbox
              - '#f5a142'  # Honshus
              
            graph_span: 24h
            span:
              start: day           
              offset: 1d
              
            apex_config:
              card:
                background: transparent
              chart:
                height: 310px
                width: 310px              
                animations:
                  enabled: false
              stroke:
                show: true
                width: 0
                curve: smooth
              plotOptions:
                pie:
                  donut:
                    size: '65%'                  
                    labels:
                      show: true             
                      total:
                        fontFamily: "Amazon Ember Light, sans-serif"
                        fontSize: 30px
                        show: true
                        showAlways: true
                        label: Total                      
                       
              dataLabels:
                enabled: false           
                  
              legend:     
                show: false
            card_mod:
              style: |  
                .apexcharts-datalabel-value {
                  font-family: "Amazon Ember Bold" !important;
                  font-size: 24px !important;
                }
                 ha-card {                   
                    border: none;   
                    margin-top: 10px;
                    margin-left: 0px;
                    background: transparent;
                }

I am trying to create a graph that progressively shows the monthly consumption of various energy devices. Unfortunately, since I am still a beginner with apexchart, I still can’t figure out how to configure this graph. I have sensors that tell me the energy consumption of the previous month and I would like to have a column-type graph with y and x axis that show the months and the Kwh consumed.
Has anyone already made such a graph or can help me create it?
Thanks in advance.

I thought I’d share my code for electricity pricing. Maybe it’ll make someone happy :slight_smile:

NOTE! I made two cards where an input helper and automation hides one and shows the other at 13:00 (when the prices for the next day normally are available).

NOTE2! I’m no programmer but a tinkerer so bear that in mind :wink:

This is what my price template sensor looks like:

- platform: rest
  name: "Tibber Combined Prices"
  resource: https://api.tibber.com/v1-beta/gql
  payload: '{"query": "{viewer {homes {currentSubscription{priceInfo{today {total startsAt} tomorrow {total startsAt}}}}}}"}'
  headers:
    Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Content-Type: application/json
  method: POST
  value_template: >
    {% set prices = value_json.data.viewer.homes[0].currentSubscription.priceInfo.today %} {% if prices | length > 0 %}
      {{ prices[now().hour].total }}
    {% else %}
      0
    {% endif %}
  json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
  json_attributes:
  - today
  - tomorrow
  unit_of_measurement: "SEK/kWh"
  device_class: monetary
  state_class: measurement
  scan_interval: 30

And outputs:

state_class: measurement
today: 
- total: 1.6816
  startsAt: '2025-03-14T00:00:00.000+01:00'
- total: 1.5257
  startsAt: '2025-03-14T01:00:00.000+01:00'
- total: 1.4815
  startsAt: '2025-03-14T02:00:00.000+01:00'
- total: 1.4296
  startsAt: '2025-03-14T03:00:00.000+01:00'
- total: 1.4513
  startsAt: '2025-03-14T04:00:00.000+01:00'
- total: 1.6382
  startsAt: '2025-03-14T05:00:00.000+01:00'
- total: 2.1335
  startsAt: '2025-03-14T06:00:00.000+01:00'
- total: 2.3233
  startsAt: '2025-03-14T07:00:00.000+01:00'
- total: 2.3022
  startsAt: '2025-03-14T08:00:00.000+01:00'
- total: 1.9305
  startsAt: '2025-03-14T09:00:00.000+01:00'
- total: 1.6164
  startsAt: '2025-03-14T10:00:00.000+01:00'
- total: 1.5235
  startsAt: '2025-03-14T11:00:00.000+01:00'
- total: 1.2628
  startsAt: '2025-03-14T12:00:00.000+01:00'
- total: 1.2555
  startsAt: '2025-03-14T13:00:00.000+01:00'
- total: 1.023
  startsAt: '2025-03-14T14:00:00.000+01:00'
- total: 1.2322
  startsAt: '2025-03-14T15:00:00.000+01:00'
- total: 1.7844
  startsAt: '2025-03-14T16:00:00.000+01:00'
- total: 2.1814
  startsAt: '2025-03-14T17:00:00.000+01:00'
- total: 2.2797
  startsAt: '2025-03-14T18:00:00.000+01:00'
- total: 2.1378
  startsAt: '2025-03-14T19:00:00.000+01:00'
- total: 1.7863
  startsAt: '2025-03-14T20:00:00.000+01:00'
- total: 1.6056
  startsAt: '2025-03-14T21:00:00.000+01:00'
- total: 1.6238
  startsAt: '2025-03-14T22:00:00.000+01:00'
- total: 1.5004
  startsAt: '2025-03-14T23:00:00.000+01:00'

tomorrow: 
- total: 0.8713
  startsAt: '2025-03-15T00:00:00.000+01:00'
- total: 0.882
  startsAt: '2025-03-15T01:00:00.000+01:00'
- total: 0.8006
  startsAt: '2025-03-15T02:00:00.000+01:00'
- total: 0.7454
  startsAt: '2025-03-15T03:00:00.000+01:00'
- total: 0.7372
  startsAt: '2025-03-15T04:00:00.000+01:00'
- total: 0.7403
  startsAt: '2025-03-15T05:00:00.000+01:00'
- total: 0.7468
  startsAt: '2025-03-15T06:00:00.000+01:00'
- total: 0.5125
  startsAt: '2025-03-15T07:00:00.000+01:00'
- total: 0.4735
  startsAt: '2025-03-15T08:00:00.000+01:00'
- total: 0.4686
  startsAt: '2025-03-15T09:00:00.000+01:00'
- total: 0.47
  startsAt: '2025-03-15T10:00:00.000+01:00'
- total: 0.4718
  startsAt: '2025-03-15T11:00:00.000+01:00'
- total: 0.4684
  startsAt: '2025-03-15T12:00:00.000+01:00'
- total: 0.4663
  startsAt: '2025-03-15T13:00:00.000+01:00'
- total: 0.467
  startsAt: '2025-03-15T14:00:00.000+01:00'
- total: 0.4768
  startsAt: '2025-03-15T15:00:00.000+01:00'
- total: 0.483
  startsAt: '2025-03-15T16:00:00.000+01:00'
- total: 0.4878
  startsAt: '2025-03-15T17:00:00.000+01:00'
- total: 0.4974
  startsAt: '2025-03-15T18:00:00.000+01:00'
- total: 0.4925
  startsAt: '2025-03-15T19:00:00.000+01:00'
- total: 0.4874
  startsAt: '2025-03-15T20:00:00.000+01:00'
- total: 0.4824
  startsAt: '2025-03-15T21:00:00.000+01:00'
- total: 0.4721
  startsAt: '2025-03-15T22:00:00.000+01:00'
- total: 0.4645
  startsAt: '2025-03-15T23:00:00.000+01:00'

unit_of_measurement: SEK/kWh
device_class: monetary
friendly_name: Tibber Combined Prices

The automation:

alias: Klocka är >13:00
description: ""
triggers:
  - trigger: time
    at: "13:00:00"
conditions: []
actions:
  - action: input_boolean.turn_on
    metadata: {}
    data: {}
    target:
      entity_id: input_boolean.klockan1300
mode: single

And here is my apex code. It

- type: conditional
  conditions:
    - condition: state
      entity: input_boolean.klockan1300
      state: "off"
  card:
    type: custom:apexcharts-card
    experimental:
      color_threshold: true
    apex_config:
      grid:
        show: true
        borderColor: '#E0E0E0'
      chart:
        height: 200px
      xaxis:
        type: 'datetime'
        tooltip:
          enabled: false
        labels:
          datetimeUTC: false  # Viktigt för att hantera lokal tid korrekt
      tooltip:
        enabled: true
        followCursor: false
        x:
          show: false
        fixed:
          enabled: true
          offsetX: -75
          offsetY: -25
        custom: |
          EVAL:(data) => {
            const { series, seriesIndex, dataPointIndex, w } = data;
            const price = series[seriesIndex][dataPointIndex].toFixed(1);
            const timestamp = new Date(w.globals.seriesX[seriesIndex][dataPointIndex]);

            // Hämta timintervallet (ex. 07:00 - 08:00)
            const startHour = timestamp.getHours().toString().padStart(2, '0');
            const endHour = (timestamp.getHours() + 1).toString().padStart(2, '0');
            const timeRange = `${startHour}:00 - ${endHour}:00`;

            // Färg från color_threshold (ApexCharts sparar den i w.globals.colors)
            const color = w.globals.colors[seriesIndex] || "#FFFFFF"; // Standardfärg om inget hittas

            return `
              <div style="
                background: #2D2D2D;
                padding: 6px 10px;
                border-radius: 8px;
                color: #FFFFFF;
                font-family: Arial, sans-serif;
                text-align: center;
                min-width: 80px;
              ">
                <div style="font-size: 18px; font-weight: bold; color: ${color};">${price} öre</div>
                <div style="font-size: 12px; color: #B0B0B0; margin-top: 2px;">${timeRange}</div>
              </div>
            `;
          }
    header:
      show: true
      title: Elpris
      show_states: true
      colorize_states: true
      standard_format: false
    graph_span: 24h
    now:
      show: true
      color: 9E9E9E
    span:
      start: day
      #offset: +48h
    series:
      - entity: sensor.tibber_combined_prices
        extend_to: false  # Stäng av denna
        unit: öre/kWh
        header_actions:
          tap_action:
            action: none
        show:
          in_header: before_now
          in_chart: true
          name_in_header: false
        color_threshold:
          - value: -50
            color: 1565C0  # Mörkblå (negativa priser – extremt billigt)
          - value: 0
            color: 4DD0E1  # Ljusblå (gratis eller nära 0)
          - value: 10
            color: 43A047  # Mjuk grön (väldigt billigt)
          - value: 25
            color: 4CAF50  # Standardgrön (billigt)
          - value: 50
            color: 7CB342  # Ljusgrön (fortfarande lågt)
          - value: 75
            color: FBC02D  # Gul (nu börjar det bli lite dyrt)
          - value: 100
            color: FF9800  # Orange (högre pris, men normalt vid toppar)
          - value: 125
            color: E65100  # Mörkare orange (dyrt)
          - value: 150
            color: B71C1C  # Röd (mycket dyrt)
          - value: 200
            color: 880E4F  # Mörkröd/lila (extremt dyrt)
          - value: 300
            color: 6A1B9A  # Mörklila (krisnivå)
        type: line
        curve: stepline
        extend_to: false
        stroke_width: 2
        float_precision: 1
        data_generator: |
          const noon = new Date()
          noon.setHours(0, 0, 0, 0)
          const prices = entity.attributes.today;
          const data = [];
          for(let i = 0; i < prices.length; i++) {
            data.push([noon.getTime() + i * 1000 * 3600, prices[i].total * 100])
          }
          return data;
    yaxis:
      - min: ~0
        decimals: 0


- type: conditional
  conditions:
    - condition: state
      entity: input_boolean.klockan1300
      state: "on"
  card:
    type: custom:apexcharts-card
    experimental:
      color_threshold: true
    apex_config:
      grid:
        show: true
        borderColor: '#E0E0E0'
      chart:
        height: 200px
      xaxis:
        type: 'datetime'
        tooltip:
          enabled: false
        labels:
          datetimeUTC: false  # Viktigt för att hantera lokal tid korrekt
      tooltip:
        enabled: true
        followCursor: false
        x:
          show: false
        fixed:
          enabled: true
          offsetX: -75
          offsetY: -25
        custom: |
          EVAL:(data) => {
            const { series, seriesIndex, dataPointIndex, w } = data;
            const price = series[seriesIndex][dataPointIndex].toFixed(1);
            const timestamp = new Date(w.globals.seriesX[seriesIndex][dataPointIndex]);

            // Hämta timintervallet (ex. 07:00 - 08:00)
            const startHour = timestamp.getHours().toString().padStart(2, '0');
            const endHour = (timestamp.getHours() + 1).toString().padStart(2, '0');
            const timeRange = `${startHour}:00 - ${endHour}:00`;

            // Färg från color_threshold (ApexCharts sparar den i w.globals.colors)
            const color = w.globals.colors[seriesIndex] || "#FFFFFF"; // Standardfärg om inget hittas

            return `
              <div style="
                background: #2D2D2D;
                padding: 6px 10px;
                border-radius: 8px;
                color: #FFFFFF;
                font-family: Arial, sans-serif;
                text-align: center;
                min-width: 80px;
              ">
                <div style="font-size: 18px; font-weight: bold; color: ${color};">${price} öre</div>
                <div style="font-size: 12px; color: #B0B0B0; margin-top: 2px;">${timeRange}</div>
              </div>
            `;
          }
    header:
      show: true
      title: Elpris
      show_states: true
      colorize_states: true
      standard_format: false
    graph_span: 48h
    now:
      show: true
      color: 9E9E9E
    span:
      start: day
      #offset: +48h
    series:
      - entity: sensor.tibber_combined_prices
        extend_to: false  # Stäng av denna
        unit: öre/kWh
        header_actions:
          tap_action:
            action: none
        show:
          in_header: before_now
          in_chart: true
          name_in_header: false
          extremas: true
        color_threshold:
          - value: -50
            color: 1565C0  # Mörkblå (negativa priser – extremt billigt)
          - value: 0
            color: 4DD0E1  # Ljusblå (gratis eller nära 0)
          - value: 10
            color: 43A047  # Mjuk grön (väldigt billigt)
          - value: 25
            color: 4CAF50  # Standardgrön (billigt)
          - value: 50
            color: 7CB342  # Ljusgrön (fortfarande lågt)
          - value: 75
            color: FBC02D  # Gul (nu börjar det bli lite dyrt)
          - value: 100
            color: FF9800  # Orange (högre pris, men normalt vid toppar)
          - value: 125
            color: E65100  # Mörkare orange (dyrt)
          - value: 150
            color: B71C1C  # Röd (mycket dyrt)
          - value: 200
            color: 880E4F  # Mörkröd/lila (extremt dyrt)
          - value: 300
            color: 6A1B9A  # Mörklila (krisnivå)
        type: line
        curve: stepline
        extend_to: false
        stroke_width: 2
        float_precision: 1
        data_generator: |
          const noon = new Date()
          noon.setHours(0, 0, 0, 0)
          const prices = entity.attributes.today.concat(entity.attributes.tomorrow);
          const data = [];
          for(let i = 0; i < prices.length; i++) {
            data.push([noon.getTime() + i * 1000 * 3600, prices[i].total * 100])
          }
          return data;
    yaxis:
      - min: ~0
        decimals: 0

Hello,

Strange behavior here.
I want to compare energy consumption from current vs last week
When I apply a “-7 days” offset on the first serie (dark gray), the datalabels of the second serie (orange) is fully offset.
If I remove the offset of the first serie, everything is ok.
Has someone got an idea ?
Thx

With offset on the serie (current vs last week consumption)

span:
  start: isoWeek
series:
  - entity: sensor.conso_gaz_jour
    unit: kWh
    type: column
    color: rgb(75, 75, 75)
    offset: "-7d"
    group_by:
      func: max
      duration: 24h
    show:
      datalabels: true
    statistics:
      type: state
      period: day
      align: start
  - entity: sensor.conso_gaz_jour
    unit: kWh
    type: column
    color: orange
    group_by:
      func: max
      duration: 24h
    show:
      datalabels: true

With no offset on the first serie

span:
  start: isoWeek
series:
  - entity: sensor.conso_gaz_jour
    unit: kWh
    type: column
    color: rgb(75, 75, 75)
    group_by:
      func: max
      duration: 24h
    show:
      datalabels: true
    statistics:
      type: state
      period: day
      align: start
  - entity: sensor.conso_gaz_jour
    unit: kWh
    type: column
    color: orange
    group_by:
      func: max
      duration: 24h
    show:
      datalabels: true

The headline value in the chart is not showing a zero after the decimal place, such as “23.0”, it shows “23”. I have set the float_precision: 1. Should I be using a different parameter?

type: custom:apexcharts-card
graph_span: 24h
header:
  show: true
  title: B3 Temp Today vs B3 Window
  show_states: true
span:
  start: minute
  offset: "-24h"
series:
  - entity: sensor.ws_b3_b3_temp
    name: B3 Today
    type: line
    stroke_width: 2
    float_precision: 1
    group_by:
      func: last
      duration: 5m
  - entity: sensor.ws_white_temp
    name: B3 Window
    type: line
    stroke_width: 2
    float_precision: 1
    group_by:
      func: last
      duration: 5m

I had this problem as well… I tried to display the time there but it only showed the hour…