dbuezas / lovelace-plotly-graph-card

Highly customisable Lovelace card to plot interactive graphs. Brings scrolling, zooming, and much more!
392 stars 19 forks source link

Adaptive min/max filter #457

Open Elarion245 opened 3 weeks ago

Elarion245 commented 3 weeks ago

Describe the solution you'd like I am plotting an entity which has many datapoints, as it changes once every second (power consumption). I am currently plotting it as follows:

type: custom:plotly-graph
title: Ungetrackte Leistung
entities:
  - entity: sensor.wohnung_ungetrackte_leistung
    fill: tozeroy
    line:
      color: blue
hours_to_show: 24
refresh_interval: 30
period: auto
layout:
  xaxis:
    rangeselector:
      "y": 1.2
      buttons:
        - count: 10
          step: minute
        - count: 1
          step: hour
        - count: 3
          step: hour
        - count: 6
          step: hour
        - count: 12
          step: hour
        - count: 1
          step: day

This works on my laptop, but my phone browser already complains. Also, it takes very long to load. I now tried implementing a min/max filter, as follows:

type: custom:plotly-graph
title: Ungetrackte Leistung
entities:
  - entity: sensor.wohnung_ungetrackte_leistung
    fill: tozeroy
    line:
      color: blue
    filters:
      fn: |
        ({ ys, xs }) => ({
          let interval = 10;

          let resampledY = [];
          let resampledX = [];

          for (let i = 0; i < ys.length; i += interval) {
            let subsetY = ys.slice(i, i + interval);  
            let subsetX = xs.slice(i, i + interval);

            let minVal = Math.min(...subsetY); 
            let maxVal = Math.max(...subsetY);

            resampledY.push(minVal);
            resampledY.push(maxVal);

            resampledX.push(subsetX[subsetX.length - 1]);
            resampledX.push(subsetX[subsetX.length - 1]);
          }

          return { xs: resampledX, ys: resampledY };
        })
autorange_after_scroll: true
hours_to_show: 24
refresh_interval: 30
period: auto
layout:
  xaxis:
    rangeselector:
      "y": 1.2
      buttons:
        - count: 10
          step: minute
        - count: 1
          step: hour
        - count: 3
          step: hour
        - count: 6
          step: hour
        - count: 12
          step: hour
        - count: 1
          step: day

This seems to work (I guess), but it does not speed up things and has one drawback: if I set the plot to a shorter time-scale, obviously the filter is kept active. Ideally I would like to be able so configure the intervall adaptively based on the selection of the window.

How would it be defined in yaml?

type: custom:plotly-graph
entities:
  - entity: sensor.wohnung_ungetrackte_leistung
     filters:
         min_max: [1,1,1,2,5,10] // define interval for each configured range selector
dbuezas commented 3 weeks ago

Have you tried https://github.com/dbuezas/lovelace-plotly-graph-card?tab=readme-ov-file#statistics-support

Elarion245 commented 3 weeks ago

Thanks for your lightning fast response! In fact I have tried the statistics. With it, the plot loads very fast, which is nice. The downside is that even with the auto setting for the period, it is too agressive for small time ranges (10min-3h don't need any downsampling). the 1day plot however looks good with it. As such I concluded that it wasn'n optimal. Also I did not know if I could also achieve min/max and not just either or?

dbuezas commented 3 weeks ago

You can configure the step size for each period https://github.com/dbuezas/lovelace-plotly-graph-card?tab=readme-ov-file#step-function-for-auto-period

But if you want more resolution it will be slow because of the amount of data that is fetched.

As a workaround you could maybe add another (internal) entity for dense short term history and make it's visibility react to the size of the visible range to avoid it being fetched.

Here's how to combine them https://github.com/dbuezas/lovelace-plotly-graph-card/discussions/415.

Regarding min/max, you are right that you can fetch them individually, but you can always combine them "manually"

Let me know how it goes! :)

Elarion245 commented 3 weeks ago

This looks very interesting. Two thoughts of mine though: The 5min is too long for the short term range. Also, I wonder if the max filter is the right choice, as I would also like to keep the mins.

I just tried to set the intervall as Math.ceil(ys.length/3600)

This should ensure to have an appropriate amount of data for all ranges. I am still not sure though if my min max filter implementation works at all.

Anyhow, I'll try to experiment with your suggestion. Thank you. It would still be great for you to consider the min_max filter as improvement 😊