lovelace-plotly-graph-card
lovelace-plotly-graph-card copied to clipboard
Feature request: programmable y axis limits
It would be great if we could change the autoscale behavior. For example one of the following (or all) would be nice:
- Exclude certain entities from the automatically computed axis limits.
- Specify either a hard coded lower or upper bound for an axis, but have the other bound automatically computed.
- Specify a function for automatical computation of limits, for example:
range:
- max(entities)
- max( min(entities), 20 )
- Potentially have 'range selector' buttons like we have for the x-axis, but then for various settings. For example button 1 could represent fixed range of 0 - 20, button 2 could be from 12-30, button 3 could be automatic computation, button 4 could be automatic computation with a certain entity excluded, etc.
Yes, I really wish plotly had that option. Here's the relevant request https://github.com/plotly/plotly.js/issues/887
One workaround is for me to update the ranges AFTER the user interaction, which will make the UI very jumpy
I suppose that universal functions can handle at least a big part of this, provided one can disable the autoscaling feature.
I haven't tried it yet, but i think so, yes. Using vars or getFromConfig. If you try it please let me know how it went!
I couldn't resist:
type: custom:plotly-graph-dev
hours_to_show: current_week
entities:
- entity: sensor.senseair_temperature
- entity: sensor.durchgang_thermometer_temperature
layout:
uirevision: $fn () => Math.random() // force rescale on scroll
yaxis:
range: |
$fn ({ getFromConfig }) => {
const all = getFromConfig("entities").flatMap(({ y }) => y);
return [
Math.max(12, Math.min(...all)), // cap to lowest value, but at least 12
Math.min(18, Math.max(...all)), // cap to highest value, but at most 18
]
}
This only works if you use a single yaxis.
You can also:
- filter the
y
values by x[i] being insidegetFromConfig('visible_range')
(if you this to only be applied to what is currently visible) - put this in the default yaxes, and only take the entities whose yaxis index matches the one from
"y" + path.match(/layout\.yaxis(.*)\..*/)[1];
(if you have multiple yaxes and want to cap them independently)
I tried this and it works, but the code gets too contrived to serve as an example.
Here the limits are 15 and 22:
It works but the jumps are very unpleasent
I'll study transitions a bit more. This has potential:
Also for some custom made range selectors (the buttons on top to switch between say day and week=
This looks great! it is exactly what i meant! I'll have to play around with the code you shared a bit to understand the syntax a bit better, but great work regardless! Instead of creating 'all', what would be the syntax to create a variable related to a specified list of entities?
I'm surprised by how fast you axii update btw. is this recorded from a dashboard in homeassistant? For me if i increase the timespan of the plot to more then a day (from lets say my default 2 hours) , for sure i'm waiting much longer (eg. 20-30s) before the graph is 'populated' on the new part of the time range. did you do anything clever with that? or should i just sample less often? (i now sample temperatures every 2mins)
Happy to hear! and even more happy that the universal functions cover this so nicely. I didn't have this in mind so good that @FrnchFrgg mentioned it.
Instead of creating 'all', what would be the syntax to create a variable related to a specified list of entities?
flatMap
is equivalent to mapping followed by flattening (convert an array of arrays into a flat array). Instead of throwing all in the same bag, you can deal with each entity separately in each axis. The generic solution is too cryptic, and a tailored solution depends on how your yaml looks like :). I hope this example is good enough for you for the time being.
I'm surprised by how fast you axii update [...] For me if i increase the timespan of the plot to more then a day
yes, that's just too much data. (and I have a fast computer) You can try using statistics or the resample filter to help with that. I suggest you look at the auto mode for the statistics period too (it adapts the granularity of the data depending on the magnitude of the visible range, and it is configurable)
Transferred to discussion #233
Been playing around with the statistics, speeds up the rendering significantly! thanks for the suggestion. It seems however as if the 'auto' period setting doesn't really use 100 data points (or are they shared between all entities?) When switching to a 7 day period, I get a very coarse trace (see below). Is this the expected behavior?
for the following yaml: `type: custom:plotly-graph entities:
- entity: weather.buienradar::temperature name: Buitentemperatuur line: width: 3
- entity: sensor.bme280_temperature name: Office BME280 line: color: red
- entity: sensor.scd41_temperature name: Bedroom SCD41 line: color: fuchsia width: 2
- entity: sensor.shtc3_temperature_1 name: Office 1 SHTC3 line: color: darkred
- entity: sensor.shtc3_temperature_2 name: Office 2 SHTC3 line: color: orangered
- entity: sensor.temperature_shtc3_bathroom name: Bathroom SHTC3 line: color: MediumPurple
- entity: sensor.temperature_shtc3_a name: Kitchen SHTC3 line: color: yellow
- entity: sensor.temperature_shtc3_b name: Livingroom SHTC3 line: color: Palegoldenrod
- entity: sensor.temperature_shtc3_c name: Babyroom SHTC3 line: color: springgreen hours_to_show: 5 title: Temperature refresh_interval: 1 defaults: entity: statistic: mean period: auto unit_of_measurement: °C show_value: true line: width: 1 layout: legend: orientation: h 'y': -0.6 height: 450 uirevision: $fn () => Math.random() // force rescale on scroll yaxis: range: | $fn ({ getFromConfig }) => { const all = getFromConfig("entities").flatMap(({ y }) => y); return [ Math.max(18, Math.min(...all)), // cap to lowest value, but at least 18 Math.min(22, Math.max(...all)), // cap to highest value, but at most 22 ] } xaxis: rangeselector: 'y': 1.05 x: -0.1 buttons: - count: 1 step: hour - count: 5 step: hour - count: 24 step: hour - count: 2 step: day - count: 7 step: day `
Oh, you are right, I changed it a while back and it seems I forgot to update the readme. I'll fix the default behavior in the next release.
In the meanwhile, you can configure at which zoom level each period is used (search for period: auto
in the readme).
Please use a code block for the yaml in posts:
```yaml
your_yaml: here
```
V3.3.0 has the corrected defaults for the auto period, minimum 100 datapoints at each level :)
Also, I see you are using the range selector. You may be interested in the custom one linked in the readme ( in the range selector section) it can also scroll and it is animated
Thanks! I have noticed it working now. I'm a bit confused now by the documentation however. related to this block in the readme:
type: custom:plotly-graph
entities:
- entity: sensor.temperature
statistic: mean
period:
0m: 5minute
100h: hour
100d: day
100w: week
100M: month # note uppercase M for month. Lowercase are minutes
compared with this one which has a bit more comments:
type: custom:plotly-graph
entities:
- entity: sensor.temperature
statistic: mean
period:
0s: 5minute
24h: hour # when the visible range is ≥ 1 day, use the `hour` period
7d: day # from 7 days on, use `day`
6M: week # from 6 months on, use weeks. Note Uppercase M! (lower case m means minutes)
1y: month # from 1 year on, use `month
Am I right to assume that anywhere in between 100h and 99d, the statistics for 'day' wil be used. So actually in that case we would have 2376 samples rather than the 100 datapoints?
also, I initially though that this integration was computing the statistics, but from this it appears to me that plotly doesn't compute the statistics, but rather takes this from the HA recorder (which maybe only tracks statistics for the given periods (hour, day, week, month etc.)). Is that correct?
takes this from the HA recorder (which maybe only tracks statistics for the given periods (hour, day, week, month etc.)).
That's correct 👍
Am I right to assume that anywhere in between 100h and 99d, the statistics for 'day' wil be used. So actually in that case we would have 2376 samples rather than the 100 datapoints?
almost. The statistic for hours
will be used (not days), and yes 2376 samples will be on screen. Potentially 23 more if you zoom out to almost but not quite 1000 days.
In that case you can just say: period: auto
which sets that exact default
In that case you can just say:
period: auto
which sets that exact default
Yes that was what I was using, I just wanted to understand what was happening. I now understand why it does not take exactly 100 samples in that default scenario, which is what I was expecting. I think my confusion was caused by the misunderstanding of how the statistics where 'computed'. Thanks for the great support by the way!
fyi added rescaling to just visible area as comment in #233