ApexCharts card - A highly customizable graph card

I think this is related to how apexcharts treats a datetime axis (ignoring tickamount etc) so not sure Romrider can do anything about that.
@lcsiew I think you were on the right track by switching to a category axis. You seem to be missing a block scalar after formatter: you need to add a > or a |

Also, have you tried the simpler


xaxis:
  labels:
    datetimeFormatter:
      day: d MMM

Not entirely sure what you are looking for but I would search this thread for examples of axis annotations

I am trying to modify graph_span and duration using helpers. I continue to get an error saying that its not a valid range of time. When I test the helpers in template the output is correct.

graph_span: “{{ states(‘input_select.graph_span’) }}”
stacked: true
series:
- entity: sensor.apollo_air_1_17ac3c_pm_0_3_to_1_mm
name: 0.3-1 µm
- entity: sensor.apollo_air_1_17ac3c_pm_1_to_2_5_mm
name: 1-2.5 µm
- entity: sensor.apollo_air_1_17ac3c_pm_2_5_to_4_mm
name: 2.5-4 µm
- entity: sensor.apollo_air_1_17ac3c_pm_4_to_10_mm
name: 4-10 µm
all_series_config:
stroke_width: 2
type: column
group_by:
func: avg
duration: “{{ states(‘input_number.graph_duration’) | int}}m”

It should be simple, but I can’t seem to get it to work.

You cannot use templates on these elements out of the box, you will need to wrap the apex card in something like config-template-card or use a conditional card as explained by @Mariusthvdb who included an example of what you are trying to achieve

can figure out how to change to 24h timezone amsterdam.
Schermafbeelding 2025-10-29 232559

type: custom:apexcharts-card
graph_span: 1d
span:
  start: day
header:
  show: true
  title: Stroomprijs verloop vandaag
  show_states: true
  colorize_states: true
apex_config:
  yaxis:
    forceNiceScale: true
  dataLabels:
    background:
      borderWidth: 0
      opacity: 0
      foreColor: "#03A9F4"
  plotOptions:
    bar:
      borderRadius: 0
      dataLabels:
        position: top
now:
  show: true
  label: Nu
  color: "#0074D9"
series:
  - entity: sensor.enever_stroomprijs_anwb
    show:
      datalabels: true
    float_precision: 2
    type: column
    name: Stroomprijs Anwb
    data_generator: |
      return entity.attributes.data.map((entry) => {
        return [new Date(entry.datum), entry.prijsBE];
      });
yaxis:
  - min: 0
    max: 0.4
    decimals: 2
    apex_config:
      tickAmount: 4

I got it fixed the issue was in virtualbox.
there was setting on to set the time in utc.

Hello,

Autoscale with 3 yaxis dosen’t work. Can anyone support? Or should I post the issue in here?

I posted it here:

Apexcart - yaxis autoscale not working as intended

Thanks everyone!!

Hi there,

I was hoping someone could help me on something Im trying to achieve:

I have multiple sensors, (all following the naming pattern sensor.*_xyz), which have a numeric state and an attribute named 'color', it being a color in the format #001122.

I am trying to create a pie chart with apexCharts and auto-entities (up to this I have managed), but I would like each element to take the color based on the attribute ‘color’.

So far, this is what I have put together, not managing to introduce the color part:

type: custom:auto-entities
card:
  type: custom:apexcharts-card
  chart_type: pie
  stacked: false
  apex_config:
    dataLabels:
      formatter: |
        EVAL:function(value) {
          return value.toFixed(1) + "%";
        }
filter:
  include:
    - options: {}
      domain: sensor
      entity_id: "*_xyz"
    - options:
        color: "#656565"
      entity_id: sensor.others_mqtt
  exclude:
    - options: {}
      state: unknown
    - options: {}
      attributes:
        important: false
sort:
  method: state
  numeric: true
  reverse: true

is this that I’m attempting even doable?

Thank you!

Annotatins - Is there a way to link them to a specific yaxis to get the bouinderis right?

The documentation lists yAxisIndex as the property that deals with that but I did not manage to make that work (I wanted to do a point annotation on a series on a secondary y-axis). In another case I ended up calculating the value of the first axis that was needed to make it look good on the axis the annotation belonged to but that only works when you have full control over both axis.

Is there a way to force a shaded area to represent a normal range for expected values?

I currently have a dashed line to represent the median…

type: custom:apexcharts-card
grid_options:
  columns: 18
header:
  title: ""
  show: true
  show_states: true
  colorize_states: true
graph_span: 1h
apex_config:
  annotations:
    yaxis:
      - "y": 17.5
        borderColor: "#64B5F6"
        borderWidth: 1
        strokeDashArray: 5
        label:
          text: ""
          style:
            color: "#64B5F6"
            background: rgba(0, 0, 0, 0.8)
            fontSize: 10px
            fontFamily: Segoe UI Light
          position: left
      - "y": 27.5
        borderColor: "#81C784"
        borderWidth: 1
        strokeDashArray: 5
        label:
          text: ""
          style:
            color: "#81C784"
            background: rgba(0, 0, 0, 0.8)
            fontSize: 10px
            fontFamily: Segoe UI Light
          position: left
      - "y": 49.5
        borderColor: "#9575CD"
        borderWidth: 1
        strokeDashArray: 5
        label:
          text: ""
          style:
            color: "#E57373"
            background: rgba(0, 0, 0, 0.8)
            fontSize: 10px
            fontFamily: Segoe UI Light
          position: left
  yaxis:
    forceNiceScale: true
    min: 0
    max: 55
    tickAmount: 6
    labels:
      style:
        fontSize: 10px
        fontFamily: Segoe UI Light
  xaxis:
    axisBorder:
      show: false
    labels:
      style:
        fontSize: 10px
        fontFamily: Segoe UI Light
  legend:
    show: false
  chart:
    height: 225
  grid:
    show: true
    borderColor: "#404040"
    strokeDashArray: 3
    position: back
  dataLabels:
    enabled: false
  stroke:
    width: 1
  fill:
    type: line
    gradient:
      type: vertical
      shadeIntensity: 0.8
      inverseColors: false
      opacityFrom: 0.5
      opacityTo: 0
      stops:
        - 0
series:
  - entity: sensor.apex_sump_int_lls
    name: Sump (Int)
    type: line
    curve: smooth
    fill_raw: last
    color: "#64B5F6"
    float_precision: 1
    unit: cm
    group_by:
      func: avg
      duration: 3min
  - entity: sensor.apex_sump_ext_lls
    name: Sump (Ext)
    type: line
    curve: smooth
    fill_raw: last
    color: "#81C784"
    float_precision: 1
    unit: cm
    group_by:
      func: avg
      duration: 3min
  - entity: sensor.apex_overflow_lls
    name: Tank Overflow
    type: line
    curve: smooth
    fill_raw: last
    color: "#9575CD"
    unit: cm
    float_precision: 1
    group_by:
      func: avg
      duration: 3min
  - entity: sensor.apex_ato_lls
    name: ATO
    type: line
    curve: smooth
    fill_raw: last
    color: "#E57373"
    unit: cm
    float_precision: 1
    group_by:
      func: avg
      duration: 3min
style: |
  ha-card {
    --ha-card-background: rgba(0, 0, 0, 0.3);
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
    border: 1px solid rgba(255, 255, 255, 0.05);
    border-radius: 12px;
    margin: 8px 8px 28px 8px;
    font-size: 15px;
    text-align: center;
    font-family: Segoe UI Light;
  }
  div#header__title {
    font-size: 15px;
    font-family: Segoe UI Light;
  }
  #state__value > #state {
    font-weight: 100;
  }


Nope. You can only fill down to 0. However…

The series are drawn in order they appear in the series config so you can overlay one fill on top of another.

By setting the fill of a lower series to the same colour as your background colour you can mask off a series above it. It’s not perfect. It will cover everything, including the graph axis lines.

Series config for graph above. The 90% to 10% shading is produced by the 2nd and 3rd series.

series:
  - entity: sensor.todays_solar_forecast
    name: Forecast
    color: "#e0b400"
    type: line
    stroke_width: 2
    show:
      datalabels: false
  - entity: sensor.todays_solar_forecast_90
    name: 90% Probability
    color: "#e0b400"
    opacity: 0.3
    type: area
    stroke_width: 0
    show:
      in_legend: false
  - entity: sensor.todays_solar_forecast_10
    name: 10% Probability
    color: var(--card-background-color)
    opacity: 1
    type: area
    stroke_width: 0
    show:
      in_legend: false
  - entity: sensor.solar_production_energy
    name: Actual
    color: "#0da035"
    type: line
    stroke_width: 2
    statistics:
      type: state
      period: day
      align: middle
2 Likes

thanks mate :slight_smile:

without reading through the whole topic can someone point me in the direction of defining a time scale on x axis if its possible e.g for 24 hours theres a 2h spacing on x axis. thanks!

Not exactly, the following fills till whatever value is at the end of your chart

plotOptions:
  area:
    fillTo: end

You can bring those back with

Grid:
  Position: Front

And for perfect blending into the background, the default shade of white in HA is #FAFAFA

You can do a lot of cool things with overlaying area series but looking at the code of OP - and if only a block range is needed - you can also add a second y-value to annotations and make it a range instead of a line

Not sure what that does. It always fills to the bottom of the graph. It can’t fill down to another series like Grafana can.

Thanks. This works for me:

apex_config:
  grid:
    position: front

color: var(--card-background-color) works for any background.

As you say, it fills to the bottom, ignoring the xaxis, the alternative is filling till the xaxis (from the top and the bottom). You can indeed not do a range area but the overlaying you described works well, I’ve also combined it with color thresholds to show fill colors changing when crossing the xaxis

Yes, I saw that in your code, that’s even better, but I was referring to the default background color in HA. I saw a different shade of white inside and outside the plotted area, sure that was intentional but some might wonder why and want it to be the same white to blend into the background, if so you can use


color: var(--primary-background-color)

if you believe, reality did show differnt, but I picked up the task again since I wanted to find out why the hell it failed in the past.

And it took me “more but a while” to get that solved.

My primary attempt. an area with got a red line on top and a blue at it’s bottom.
With a card-background color below the lower blue line.

This one failed straight

type: custom:apexcharts-card
experimental:
  color_threshold: true
brush:
  selection_span: 28h
apex_config:
  grid:
    show: false
  legend:
    show: false
all_series_config:
  group_by:
    func: avg
    duration: 15min
  stroke_width: 2
  type: area
header:
  standard_format: false
  show: true
  show_states: true
  colorize_states: true
  title: Fernwärme
series:
  - entity: sensor.esp32heizungsraum_dallas_fern_i
    color: "#ff0000"
    color_threshold:
      - value: 100
        color: "#ff0000"
      - value: 0
        color: "#00aaff"
    opacity: 0.5
    name: Vorlauf
    show:
      extremas: true
  - entity: sensor.esp32heizungsraum_dallas_fern_o
    color: "#00aaff"
    name: Rücklauf
    color_threshold:
      - value: 100
        color: var(--card-background-color)
      - value: 0
        color: var(--card-background-color)
card_mod:
  style: |
    ha-card {
      font-size: 12px;
    }

Then I split the second entity into 2, one for the colored line and a second time for the filled area, but that looked anything but the card background color.

Failed again.

  - entity: sensor.esp32heizungsraum_dallas_fern_o
    type: line
    color: "#00aaff"
    name: Rücklauf
  - entity: sensor.esp32heizungsraum_dallas_fern_o
    type: area
    stroke_width: 0
    color: var(--card-background-color)
    show:
      in_header: false

until I added

    opacity: 1

next to the background-color. And I wonder why this made the differnce.
but not it works. :slight_smile:

Means background-color seems to work as long as not using experimental features.

1 Like

Hello, please can someone help me with writing a transform/generate (?) function to take a value that is sampled every 10 minutes and make a chart of hourly averages over the same day of week? Like average number of samples at 11:00am for Monday is … etc.

I guess I should use data_generator but I have no idea how to process the series of historical entries.

Thank you in advance.

Update:
One idea was to retrieve the statistics via recorder.get_statistics call, then it could be filtered and transformed via transform function. But ApexCharts card does not support calling actions hence this is apparently a no go.

I’m using the color_treshold option.
Is it possible to have one or more levels defined by a sensor state instead of a hardcoded number?