ApexCharts card - A highly customizable graph card

The 1st problem:
not sure… I have seen this with me a few (!) times. I myself cannot reproduce it on-the-spot, could be cache, laptop/client app…etc. …no easy reproduction: no easy answer

2nd problem

FWIW, time in home assistant is set up properly.

Try to reproduce it with an ootb card, e.g. statistics, or the history one. I know apex to be properly following the datetime.

Main recommendation: remove all (!) non data related configuration, i.e. just series no grouping etc. and then add things until you (may?) find the issue

5 Minute Delta Method Verified and updated in below post. Provides accurate and live updates for HOURLY RAINFALL

1 Like

If you like to add multiple yaxis to your chart, so you can combine even more entities, you will likely have fiddled a lot with the settings of those axis to avoid too much overlapping entities and visual clutter.

For example, at some point I had a chart with a secondary yaxis set to a max of 200%, which ensured I was drawing percentages only in the bottom half of the chart whilst other entities would stay in the top half.

By using a custom formatter function you can hide the unnecessary axis labels, removing more visual clutter and creating the effect of sticking two charts on top of each other and sharing a single x-axis.


apex_config:
  labels:
    formatter: >
      EVAL: function (value, index) {if (index > 8) {return value + '°C'} return ''}

This example hides the first 8 labels and adds a unit to the ones shown. You can also put the condition on the value but by using the index you can change the min max settings without messing up the formatting.

1 Like

FWIW, time in home assistant is set up properly.

There are two relevant settings in HA, one is in general system settings, another in your account / profile.

I ended up doing this, simply add all the entities you want to use with the brush to a single chart, add multiple y-axis, choose your min-max settings wisely and apply this trick to clean up. The end result is even cleaner as you now have a single x-axis. The disadvantage is you need to carefully manage the min max settings and cannot let them adjust freely based on the data you are plotting.

Hello,

I am trying to create a chart from a fitness integration tracking my exercise duration for the week, and preferably by exercise name. Unfortunately, I do not know how to address the variables since one does not have an id. I tried to create sensors, but I only get dates, and null/undefined responses for anything else.

Here is an example of the data:

{
“2025-09-08”: {
“totalSessions”: 1,
“totalDuration”: 1838,
“totalDurationFormatted”: “30m”,
“sessions”: [
{
“startTime”: 1757369934,
“endTime”: 1757371772,
“duration”: 1838,
“durationFormatted”: “30m”,
“exerciseType”: “79”,
“exerciseName”: “Walking”,
“title”: “Walking 6:18:54 PM Sep 8, 2025”,
“notes”: null,
“segments”:
}
]
},
“2025-09-10”: {
“totalSessions”: 1,
“totalDuration”: 1708,
“totalDurationFormatted”: “28m”,
“sessions”: [
{
“startTime”: 1757540267,
“endTime”: 1757541975,
“duration”: 1708,
“durationFormatted”: “28m”,
“exerciseType”: “79”,
“exerciseName”: “Walking”,
“title”: “Walking 5:37:47 PM Sep 10, 2025”,
“notes”: null,
“segments”:
}
]
},
“2025-09-12”: {
“totalSessions”: 4,
“totalDuration”: 6078,
“totalDurationFormatted”: “1h 41m”,
“sessions”: [
{
“startTime”: 1757716410,
“endTime”: 1757718120,
“duration”: 1710,
“durationFormatted”: “28m”,
“exerciseType”: “79”,
“exerciseName”: “Walking”,
“title”: null,
“notes”: null,
“segments”:
},
{
“startTime”: 1757716526,
“endTime”: 1757718142,
“duration”: 1616,
“durationFormatted”: “26m”,
“exerciseType”: “79”,
“exerciseName”: “Walking”,
“title”: “Walking 6:35:26 PM Sep 12, 2025”,
“notes”: null,
“segments”:
},
{
“startTime”: 1757735155,
“endTime”: 1757736467,
“duration”: 1312,
“durationFormatted”: “21m”,
“exerciseType”: “79”,
“exerciseName”: “Walking”,
“title”: “Walking 11:45:55 PM Sep 12, 2025”,
“notes”: null,
“segments”:
},
{
“startTime”: 1757735160,
“endTime”: 1757736600,
“duration”: 1440,
“durationFormatted”: “24m”,
“exerciseType”: “79”,
“exerciseName”: “Walking”,
“title”: null,
“notes”: null,
“segments”:
}
]
}

Thank you in advance.

And what are you trying to show, i.e. what would you expect on x- axes and what value(s) on y?
EDIT: and please provide a properly (!) formatted correct/complete json or show how it looks like in your sensor


here is how the data looks.

I would like to track how many minutes I’ve exercised in a week, so x-axis would be minutes/seconds and y-axis would be exercise. It would be nice to have the exercises categorized by type, similar to the sleep stages here Health Connect to Home Assistant but I would honestly be so happy with tracking the number of minutes exercised per week. thank you.

You could use your total duration sensor and do something similar to the Daily or 30 day rain graph here.

yes, but how would I address the sensors? my problem is that the dates don’t have an id

Is it possible to remove seconds and milliseconds in the header by limiting to hours and minutes? Sensor values shows 3h 15m but header value shows that along with seconds and milliseconds

Am not home, not tested and donot have your data plus not manually copying from screen.
Your data_generator should run something like

let output = [];
for (key, value in entity.attributes.excercise)
{
  output.push([new Date(key),value.totalDuration])
}
return output

Just doing it on the total, the graph will arrange into buckets over time. So whet ever that total value is at any point in time, will exist in the buckets. Ignore the other attribute values.

@RomRider Could you please assist if this is possible?

try this:

    data_generator: |
      let output = [];
      for (const [k, v] of Object.entries(entity.attributes.exercise))
      {
        output.push([new Date(k),v['totalDuration']])
      }
      return output;

trying to explain: as_duration: TYPE takes the value from the sensor, assumes it is the as_duration TYPE and then use that. If the value has a lot of decimals then it will go to the very end.
If you want it differently then you need to round the sensor value.

A hardcoded example, below returns 15.2 as value and the yaml says to treat it as hour
so 15.2 hours, the display will then show 15h 12m
and value 15.222 will return 15h 13m 19s 200ms
By using transform: return Math.round(x * 100)/100 (x being a value from the sensor, say 15.222 for this moment), it will have return modified value of 15.22 and thus 15h 13m 12s
Hope this makes it clear(er)

type: custom:apexcharts-card
header:
  show: true
  show_states: true
series:
  - entity: input_text.any_sensor
    type: line
    transform: return 15.2
    show: 
      as_duration: hour

this unfortunately is not giving me the data I need, and I have concluded I’m not smart enough to get it working.

Thank you very much for your assistance.

If you seek support then you need to be more clear, above code I tested locally so it does (!) show totalDuration. If you donot want totalDuration then be more clear as stating ‘is not giving me the data I need’ means very little… how would one know what you need if you donot specify it.

I agree this approach with js is technical and may be far from your expertise, but it does not mean that there is no help. Ideally the data would be less complex but I have no clue if this is even feasible. Anyhow…there is still hope but it does require your stamina :slight_smile:

it’s funny, I came back and read your post and gave it another try. Thank you for the encouragement! I think I have almost what I need.
currently I have this:

type: custom:apexcharts-card
graph_span: 7d
show:
  last_updated: true
span:
  offset: "-2d"
header:
  show: true
  title: Daily Exercise
series:
  - entity: sensor.health_connect
    show:
      as_duration: minute
      legend_value: true
    type: column
    data_generator: |
      let output = [];
      for (const [k, v] of Object.entries(entity.attributes.exercise))
      {
        output.push([new Date(k),v['totalDurationFormatted']])
      }
      return output;
yaxis:
  - min: 0
    max: 60

there’s only one value in the sensor currently (stressful week) and the column seems to be three days wide?

This is something with playing around with span/graph_span start/end etc. … check this looong thread for similar things…and nice that it started to work