ApexCharts card - A highly customizable graph card

Any help on this?

Hello, would it be possible:

  1. Show sum of column on mouse hover?
  2. Hide the date and time tab when the another one is already shown :slight_smile:

Thanks!

image

type: custom:apexcharts-card
header:
  show: true
  show_states: true
  colorize_states: true
graph_span: 2d
span:
  start: day
now:
  show: true
  label: Teď
series:
  - entity: sensor.current_spot_electricity_buy_price
    name: Celková cena
    color: black
    show:
      in_header: raw
      in_chart: false
    float_precision: 2
  - entity: sensor.cena_tarifu
    type: column
    name: Cena tarifu
    color: green
    float_precision: 2
    group_by:
      func: sum
      duration: 1hour
    data_generator: |
      return entity.attributes.datum.map((peak, index) => {
        return [new Date(peak).getTime(), entity.attributes.hodnota[index] * 1.21];
      });
  - entity: sensor.current_spot_electricity_price
    type: column
    color: orange
    name: Spot
    float_precision: 2
    group_by:
      func: sum
      duration: 1hour
    show:
      in_header: before_now
    data_generator: |
      return Object.entries(entity.attributes).map(([date, value], ) => {
        return [new Date(date).getTime(), value* 1.21];
      });
stacked: true
apex_config:
  legend:
    show: false

No I didn’t, still comparing the meters with two cards side-by-side

Hi @haraldh - Like this:

1 Like

Hi everyone,

this is how I solved it:

type: custom:apexcharts-card
graph_span: 10d
span:
  end: day
show:
  last_updated: true
header:
  show: true
  title: Playstation-Spielzeit
  show_states: true
  colorize_states: true
apex_config:
  chart:
    type: area
    height: 225
  stroke:
    show: true
    width: 1.5
  xaxis:
    labels:
      format: dd.MM
  fill:
    type: gradient
    gradient:
      shadeIntensity: 0.1
      opacityFrom: 0.25
      opacityTo: 0.9
  dataLabels:
    background:
      borderWidth: 0
      opacity: 0
      foreColor: white
    style:
      fontSize: 11px
    formatter: |
      EVAL:function(value) {
      // Check sign of given number
        var number = value
        var sign = (number >= 0) ? 1 : -1;
      // Set positive value of number of sign negative
        number = number * sign;
      // Separate the int from the decimal part
        var hour = Math.floor(number);
        var decpart = number - hour;
        var min = 1 / 60;
      // Round to nearest minute
        decpart = min * Math.round(decpart / min);
        var minute = Math.floor(decpart * 60) + '';
      // Add padding if need
        if (minute.length < 2) {
        minute = '0' + minute; 
        }
      // Add Sign in final result
        sign = sign == 1 ? '' : '-';
      // Concate hours and minutes
        time = sign + hour + ':' + minute;
        return time;
      // source: https://speedysense.com/convert-float-to-time-in-javascript/
      }
  plotOptions:
    bar:
      borderRadius: 3
      columnWidth: 80%
      dataLabels:
        position: bottom
  tooltip:
    x:
      format: dd. MMMM 'yy
series:
  - color: steelblue
    entity: sensor.playtime_ps5
    type: column
    group_by:
      func: last
      duration: 1d
    show:
      datalabels: true
      as_duration: hour

image

Hello everyone,

following @RomRider’s advice (see #802), I have created vertical lines for sunrise and sunset using the config-template-card.
Since the chart continuously shows the last 25 hours, I have not only integrated the sunrise / sunset lines of the current day (today), but also those of the previous day (yesterday).
However, the chart also includes events that lie just outside the chart span. For example, sunsets on the right-hand side that are about one hour in the future (and therefore not in the chart), or yesterday’s events that are already 26 hours in the past (in a 25h chart), which cross my y-axis on the left side…
Is there a way to prevent these events from being drawn outside the actual chart span?
Here is my code and two screenshots of what it looks like. (P.S. The curve shows the outside temperature, the blue bars in the background show rain phases).

Thanks for any suggestions,
Hannah


type: custom:config-template-card
entities:
  - sensor.sunset
  - sensor.sunrise
  - sensor.sunset_yesterday
  - sensor.sunrise_yesterday
  - sensor.esp_garagendach_temperatur_auen_1
  - switch.shelly_plus1_regenmelder
card:
  type: custom:apexcharts-card
  graph_span: 25h
  span:
    end: hour
  header:
    title: Außentemperatur
    show: true
    show_states: true
    colorize_states: true
  yaxis:
    - id: first
      decimals: 0
      apex_config:
        tickAmount: 4
    - id: second
      opposite: true
      show: false
  series:
    - entity: sensor.esp_garagendach_temperatur_auen_1
      yaxis_id: first
      curve: smooth
      name: Außentemperatur
      unit: °C
      stroke_width: 3
      fill_raw: last
      group_by:
        func: avg
        duration: 5min
      show:
        name_in_header: false
    - entity: switch.shelly_plus1_regenmelder
      transform: 'return x === ''on'' ? 1 : 0;'
      yaxis_id: second
      curve: stepline
      stroke_width: 0
      opacity: 0.2
      type: area
      show:
        in_header: false
  apex_config:
    legend:
      show: false
    annotations:
      xaxis:
        - x: ${new Date(states['sensor.sunrise'].state).getTime()}
          label:
            text: >-
              ${"☀️ " + new Date(new
              Date(states['sensor.sunrise'].state).getTime()).toLocaleTimeString([],{hour:'2-digit',
              minute:'2-digit'})}
            borderWidth: 0
            style:
              background: '#0000'
        - x: ${new Date(states['sensor.sunset'].state).getTime()}
          label:
            text: >-
              ${"🌙 " + new Date(new
              Date(states['sensor.sunset'].state).getTime()).toLocaleTimeString([],{hour:'2-digit',
              minute:'2-digit'})}
            borderWidth: 0
            style:
              background: '#0000'
        - x: ${new Date(states['sensor.sunrise_yesterday'].state).getTime()}
          label:
            text: >-
              ${"☀️ " + new Date(new
              Date(states['sensor.sunrise_yesterday'].state).getTime()).toLocaleTimeString([],{hour:'2-digit',
              minute:'2-digit'})}
            borderWidth: 0
            style:
              background: '#0000'
        - x: ${new Date(states['sensor.sunset_yesterday'].state).getTime()}
          label:
            text: >-
              ${"🌙 " + new Date(new
              Date(states['sensor.sunset_yesterday'].state).getTime()).toLocaleTimeString([],{hour:'2-digit',
              minute:'2-digit'})}
            borderWidth: 0
            style:
              background: '#0000'
    xaxis:
      tickAmount: 5
      labels:
        format: HH
1 Like

Thanks for inspiration, which integration are you using to get the sunsets and sunrises pls?

I use a separate integration that provides the corresponding sun sensors. This makes more possible than with the internal sun integration:
ha-sun2
However, a lot of information is created as attributes in the sensors provided. For the sake of simplicity, I have created my own sensor (sensor.sunset_yesterday) from one of the attributes (sensor.sunset > attribute “yesterday”)

Hmm it seems I am not able to get those nice annotations there. When doing changes in the card I can see them blink on the left side somewhere in the middle horizontally :frowning:

type: custom:config-template-card
entities:
  - sensor.sunset
  - sensor.sunrise
  - sensor.current_spot_electricity_buy_price
  - sensor.current_spot_electricity_price
  - sensor.cena_tarifu
card:
  type: custom:apexcharts-card
  header:
    show: true
    show_states: true
    colorize_states: true
  graph_span: 2d
  span:
    start: day
  now:
    show: true
    label: Teď
  series:
    - entity: sensor.current_spot_electricity_buy_price
      name: Celková cena
      color: black
      show:
        in_header: raw
        in_chart: false
      float_precision: 2
    - entity: sensor.cena_tarifu
      type: column
      name: Cena tarifu
      color: green
      float_precision: 2
      group_by:
        func: avg
        duration: 1hour
      show:
        in_header: before_now
      data_generator: |
        return entity.attributes.datum.map((peak, index) => {
          return [new Date(peak).getTime(), entity.attributes.hodnota[index] * 1.21];
        });
    - entity: sensor.current_spot_electricity_price
      type: column
      color: orange
      name: Spot
      float_precision: 2
      group_by:
        func: avg
        duration: 1hour
      show:
        in_header: before_now
      data_generator: |
        return Object.entries(entity.attributes).map(([date, value], ) => {
          return [new Date(date).getTime(), value* 1.21];
        });
  stacked: true
  apex_config:
    legend:
      show: false
    annotations:
      xaxis:
        - x: ${new Date(states['sensor.sunrise'].state).getTime()}
          label:
            text: >-
              ${"☀️ " + new Date(new
              Date(states['sensor.sunrise'].state).getTime()).toLocaleTimeString([],{hour:'2-digit',
              minute:'2-digit'})}
            borderWidth: 0
            style:
              background: '#0000'
        - x: ${new Date(states['sensor.sunset'].state).getTime()}
          label:
            text: >-
              ${"🌙 " + new Date(new
              Date(states['sensor.sunset'].state).getTime()).toLocaleTimeString([],{hour:'2-digit',
              minute:'2-digit'})}
            borderWidth: 0
            style:
              background: '#0000'

image

Did you finetune this already ?

Did your set a location in HA or manually in ha-sun2 for calculating the sunset/sunrise?
config-template-card integration installed with correct resources?

config-template-card - Yep, installed though HACS,

Location is set in HA and the sensors are giving correct data:

image

I needed to get rid of now section

  now:
    show: true
    label: Teď

and put it into the annotations in order to make all work correctly. Thanks to all!

Hello folks,

I have a problem showing the average of a sensor over 10d time. Value calculated and shown is definitely wrong as it doesn’t change over the days, too. This is my full card yaml, average is the second series names “Durchschnitt”:

type: custom:apexcharts-card
graph_span: 10d
show:
  last_updated: false
span:
  end: day
header:
  show: false
  title: Playstation - v9 wip
  disable_actions: true
all_series_config:
  stroke_width: 1.5
apex_config:
  legend:
    position: bottom
    floating: false
    offsetX: 10
    itemMargin:
      horizontal: 15
    formatter: |
      EVAL:(seriesName, opts) => {
        var arr = opts.w.globals.series[opts.seriesIndex];
        value = arr[arr.length - 1];
        var number = value
        var sign = (number >= 0) ? 1 : -1;
        number = number * sign;
        var hour = Math.floor(number);
        var decpart = number - hour;
        var min = 1 / 60;
        decpart = min * Math.round(decpart / min);
        var minute = Math.floor(decpart * 60) + '';
        if (minute.length < 2) { minute = '0' + minute; }
        sign = sign == 1 ? '' : '-';
        time = sign + hour + ':' + minute;
        return seriesName+": "+time+"h";
      }
  fill:
    type: solid
    gradient:
      type: vertical
      shadeIntensity: 0.1
      opacityFrom: 0.25
      opacityTo: 0.9
  chart:
    height: 250
  xaxis:
    axisBorder:
      show: true
    axisTicks:
      show: false
    labels:
      format: dd.MM
      offsetX: -10
      offsetY: -5
      show: true
  plotOptions:
    bar:
      borderRadius: 3
      columnWidth: 80%
      dataLabels:
        position: bottom
  tooltip:
    enabled: false
    shared: true
    x:
      show: true
      format: dd. MMMM 'yy
    'y':
      show: true
      formatter: |
        EVAL:function(value) {
          var number = value
          var sign = (number >= 0) ? 1 : -1;
          number = number * sign;
          var hour = Math.floor(number);
          var decpart = number - hour;
          var min = 1 / 60;
          decpart = min * Math.round(decpart / min);
          var minute = Math.floor(decpart * 60) + '';
          if (minute.length < 2) { minute = '0' + minute; }
          sign = sign == 1 ? '' : '-';
          time = sign + hour + ':' + minute;
          if (time != '0:00') { return time+"h"; }
          }
  dataLabels:
    background:
      borderWidth: 0
      opacity: 0
      foreColor: white
    style:
      fontSize: 11px
    formatter: |
      EVAL:function(value) {
        var number = value
        var sign = (number >= 0) ? 1 : -1;
        number = number * sign;
        var hour = Math.floor(number);
        var decpart = number - hour;
        var min = 1 / 60;
        decpart = min * Math.round(decpart / min);
        var minute = Math.floor(decpart * 60) + '';
        if (minute.length < 2) { minute = '0' + minute; }
        sign = sign == 1 ? '' : '-';
        time = sign + hour + ':' + minute;
        if (time != '0:00') { return time; }
        // source: https://speedysense.com/convert-float-to-time-in-javascript/
        }
series:
  - entity: sensor.playtime_ps5
    time_delta: '-6h'
    name: Heute
    type: column
    color: steelblue
    opacity: 0.5
    group_by:
      func: last
      duration: 1d
    show:
      datalabels: true
      as_duration: hour
  - entity: sensor.playtime_ps5
    time_delta: '-16h'
    name: Durchschnitt
    type: line
    color: grey
    group_by:
      func: avg
      duration: 10d
  - entity: sensor.playtime_ps5
    time_delta: '-16h'
    name: Soll
    type: line
    color: '#FFC107'
    group_by:
      func: last
      duration: 1d
    data_generator: |
      const now = new Date();
      const soll = 2.333
      const data = [];
      for(let i = 0; i <= 10; i++) {
        data.push([now.getTime() - i*1000*60*60*24, soll])
      }
      return data

This is what my chart shows:
image

  1. I would have expected an average of 1:05h based on shown values, but it isn’t.
  2. Also, it’s always a straight line showing the last calculated 10d average for every day in chart. My expectation was that this would show a curve where for every day the 10d average is shown.

Is my config or my expectation wrong?

thx a lot for your comments,
zavjah

I am having difficulty to scale MWh to kWh. I thought that using the transform and scale would do it, but I don’t see any change to the values displayed. What am I missing? Here is the yaml for my card:

type: custom:apexcharts-card
apex_config:
  chart:
    height: 400px
    foreColor: '#7B7B7B'
    zoom:
      type: x
      enabled: true
      autoScaleYaxis: true
    toolbar:
      show: false
      autoSelected: zoom
update_interval: 30m
header:
  show: true
  title: Today's Energy Prices (€/MWh)
now:
  show: true
  label: now
span:
  start: day
graph_span: 1d
series:
  - entity: sensor.coopernico_base_tarifario_tri_horario
    name: Coopernico Tri Horario
    unit: €/MWh
    float_precision: 5
    transform: return x / 1000; # I thought this line would scale the sensor price
    stroke_width: 2
    type: line
    curve: stepline
    group_by:
      func: avg
      duration: 30m
    show:
      extremas: true
      legend_value: false
    data_generator: >
      return Object.entries(entity.attributes.today_hours).map(([dateString,
      price]) => [ new Date(dateString), price ])
yaxis:
  - id: price
    align_to: 10
    decimals: 1

Has anyone figured out how to get the right side of the Y axis to represent a non-numeric value?
I’m trying to figure out how to make a good wind monitoring chart, but coming up empty. I created anothe topic for it here: Trying to recreate ambientweather charts using apexcharts

Hello,
is possible use color threshodl with hard color change? No mix color between two values.
Thank you.

          experimental:
            color_threshold: true
          series:
            - entity: '[[entity]]'
              color_threshold:
                - value: '[[value_1]]'
                  color: rgb([[color_1]][[color_10]])
                - value: '[[value_2]]'
                  color: rgb([[color_2]])
                - value: '[[value_3]]'
                  color: rgb([[color_3]][[color_30]])

The solution was to not use transform, but to scale the price in the data generator:

 data_generator: >
      return Object.entries(entity.attributes.today_hours).map(([dateString,
      price]) => [ new Date(dateString), price / 1000 ])

Is it possible to have 2 values (and 2 symbols) in the left upper corner ? Just like in home wizard ?

It seems I am running into this HA issue (history_stats sensor does not reset until slightly after midnight for the next day). The problem is that the history_stats sensor doesn’t reset just after midnight. So within the first minute of the new day, the value of the previous day is shown in my graphs:

By the looks of it, the issue doesn’t seem to be solved anytime soon, but it does ‘corrupt’ my graphs. Now I am wondering if I can work around this issue within my apexcharts. My code is as follows:

type: vertical-stack
cards:
  - type: custom:apexcharts-card
    graph_span: 1d
    header:
      show: true
      title: Rainfall Today
      show_states: true
    now:
      show: true
    span:
      start: day
    apex_config:
      chart:
        height: 175px
      legend:
        show: false
    series:
      - entity: sensor.rainfall_today
        type: line
        color: 488fc2
        stroke_width: 2
        extend_to: now
        show:
          name_in_header: false
  - type: custom:apexcharts-card
    graph_span: 1d
    header:
      show: true
      title: Rainfall Yesterday
      show_states: true
    span:
      start: day
      offset: '-1d'
    apex_config:
      chart:
        height: 175px
      legend:
        show: false
    series:
      - entity: sensor.rainfall_today
        type: line
        color: 488fc2
        stroke_width: 2
        extend_to: end
        show:
          name_in_header: false

For the today chart I could set an offset of ‘+1min’, but this changes the x-axis as well (doesn’t start at 00:00). So preferably I end up with the following:

  • Hide the first minute or so of the data (set to zero is ok)
  • Keep the x-axis to start at 00:00; 1 day

If it makes any sense, the history_stats sensor this graph is based on is as follows:

- platform: history_stats
  name: Rainsensor Flips
  unique_id: 0f1c0351-8024-4bd3-ac68-293961fb1192
  entity_id: binary_sensor.aqara_rain_sensor_openening #The aqara sensor
  state: "off"
  type: count
  start: "{{ now().replace(hour=0, minute=0, second=0, microsecond=0) }}"
  end: "{{ now() }}"

Any help is much appreciated!