dbuezas/lovelace-plotly-graph-card

[FR] All axis same Zero line

Saentist opened this issue · 13 comments

When there is a left and right set values they both have ZERO line but is on different location in graph.
Is there a option to have option to share same Zero line to graphs will be good visualisation option.

Additional context
image

Same issue, fix would be nice, thx.
Screenshot 2024-07-10 213234

@dbuezas any timeline?

@Saentist make a feature request to plotly itself

There is a manual workaround for this, but it's a bit clumsy. You have to set the range for each y axis manually, and the important part is that the ratio between maximum and minimums has to be the same for all axes in order for the zero line to coincide.

For example, yaxis 1 has the range -10 to 100. Yaxis 2 with a range -4 to 40 would have a coinciding zero line, but one with a range -10 to 40 would not. You may also need to set the flag tickmode: sync on the second axis to ensure that both axes have the same number of ticks.

@caiusseverus
I have from 0 ... + something
and -something to + something.
But in case they are from different type, with I guess make thing graph to merge different types just in visualization area and ignore ZERO location.

Can you include some example of your suggestion.

Yes, here's an example:

image

Note that all axes have ranges with a scale factor of -4 between the minimum and maximum, so y1 is -1.25 to 5, y2 is -5 to 20, and y3 is -0.1 to 0.4.

Here's what it looks like if I remove the manually set ranges

image

All three axes now have different zero lines and the tick marks no longer line up. There is no way that I'm aware of to force it to use the same zero line while automatically scaling.

@caiusseverus post YAML code if possible.
Can you add also for example Sun Elevation

I don't know what I would do with sun elevation on that graph. Here is the yaml though:

type: custom:plotly-graph
title: Electricity Consumption
hours_to_show: current_day
config:
  displayModeBar: false
layout:
  height: 750
  dragmode: false
  legend:
    orientation: h
    itemsizing: constant
    font:
      size: 8
  xaxis:
    visible: true
    fixedrange: true
    domain:
      - 0
      - 0.95
  yaxis:
    visible: true
    fixedrange: true
    title: Consumption (kWh)
    tickmode: linear
    range:
      - -5
      - 20
  yaxis2:
    visible: true
    fixedrange: true
    overlaying: 'y'
    side: right
    position: 1
    title: £/kWh
    rangemode: tozero
    tickmode: sync
    range:
      - -0.1
      - 0.4
  yaxis3:
    visible: true
    fixedrange: true
    title: Cost (£)
    overlaying: 'y'
    side: left
    anchor: free
    autoshift: true
    rangemode: tozero
    tickmode: sync
    range:
      - -1.25
      - 5
  yaxis9:
    visible: false
    fixedrange: true
  annotations:
    - text: >-
        $fn ({ hass }) =>

        "<span style='font-size: 24px;'><span style='color: orange'>"

        + Number(hass.states['sensor.unit_avg_day'].state) + "</span></span>
        £/kWh<br>"

        + "</span><span style=''> Weighted Average Unit Price</span><br>"
      xref: x domain
      yref: y domain
      xanchor: center
      yanchor: center
      x: 0.1
      'y': 0.95
      showarrow: false
entities:
  - entity: sensor.electricity
    name: Today
    filters:
      - derivate
      - integrate: null
      - resample: 1m
      - map_y: parseFloat(y)
      - store_var: kwh
    line:
      color: rgba(52,152,219,1)
      width: 2
      shape: spline
    show_value: true
  - entity: sensor.electricity
    time_offset: 1d
    name: '-1d'
    filters:
      - derivate
      - integrate: null
    line:
      color: rgba(52,152,219,0.5)
      width: 2
      shape: spline
      dash: dot
    show_value: true
  - entity: sensor.octopus_current
    internal: false
    name: Price
    connectgaps: true
    texttemplate: ' %{y:.4f}'
    line:
      color: rgba(255,0,0,1)
      width: 1
      shape: hv
    yaxis: y2
    show_value: true
  - entity: sensor.octopus_current
    internal: false
    name: Price -1d
    time_offset: 1d
    connectgaps: true
    line:
      color: rgba(255,0,0,0.75)
      width: 1
      dash: dot
      shape: hv
    yaxis: y2
  - entity: sensor.octopus_energy_cost_tracker_electricity_cost
    name: Cost
    yaxis: y3
    line:
      color: green
      width: 2
      shape: spline
    show_value: true
    filters:
      - filter: i>1
      - resample: 1m
      - map_y: parseFloat(y)
      - store_var: cost
  - entity: sensor.octopus_energy_cost_tracker_electricity_cost
    name: Cost -1d
    time_offset: 1d
    yaxis: y3
    line:
      color: rgba(0,255,0,0.4)
      width: 2
      shape: spline
      dash: dot
    filters:
      - filter: i>1
    show_value: true
  - entity: sensor.svt_cost_today
    name: SVT cost
    yaxis: y3
    line:
      color: darkorange
      width: 2
      shape: spline
    filters:
      - filter: i>1
    show_value: true
  - entity: sensor.live_electricity_usage
    yaxis: y1
    fill: tozeroy
    line:
      color: rgba(100,75,50,0.25)
    filters:
      - multiply: 0.001
  - entity: ''
    name: Now
    showlegend: false
    line:
      width: 1
      dash: dot
      color: deepskyblue
    x: $fn () => [Date.now(), Date.now()]
    'y': $fn () => [0,1]
view_layout:
  position: main

@caiusseverus cannot make it work with my config, any suggestions accepted
image

type: custom:plotly-graph
defaults:
  entity:
    show_value: true
  yaxes:
    visible: true
    showgrid: true
  yaxis2:
    visible: true
    fixedrange: true
    overlaying: 'y'
    side: left
    position: 1
    title: radiation
    rangemode: tozero
    tickmode: sync
    range:
      - -0.1
      - 1000
  yaxis3:
    visible: true
    fixedrange: true
    title: watt
    overlaying: 'y'
    side: left
    anchor: free
    autoshift: true
    rangemode: tozero
    tickmode: sync
    range:
      - -1.25
      - 12000
hours_to_show: 12
autorange_after_scroll: true
refresh_interval: 10
title: Средна стойност за деня
layout:
  legend:
    orientation: h
    itemsizing: constant
    font:
      size: 10
  xaxis:
    visible: true
    fixedrange: false
    domain:
      - 0
      - 0.95
    rangeselector:
      'y': 1.1
      buttons:
        - count: 30
          step: minute
        - count: 3
          step: hour
        - count: 6
          step: hour
        - count: 12
          step: hour
        - count: 1
          step: day
        - count: 3
          step: day
        - count: 7
          step: day
entities:
  - entity: sensor.ups_input_voltage
    name: UPS V
  - entity: sensor.ups_nominal_input_voltage
    name: 230V
  - entity: sensor.upsa_nominal_input_voltage
    name: 220V
  - entity: sensor.clamp_meter_voltage_2
    name: clamp V
  - entity: sensor.clamp_meter_power_2
    name: clamp power
    filters:
      - multiply: -1
    yaxis: y3
    fill: tozeroy
  - entity: sensor.output_1_wattage
    name: MIN600Tl-x
    yaxis: y3
    fill: tozeroy
    line:
      color: lightgreen
  - entity: sensor.8266_growatt_grid_active_power
    name: 4200TL-XE
    line:
      color: green
    fill: tozeroy
  - entity: sensor.esp8266_sun_elevation
    name: sun pos
  - entity: sensor.sp2_watt
    name: fridge
    fill: tozeroy
    yaxis: y3
    filters:
      - multiply: -1
  - entity: sensor.smartplug3_power
    name: serv
    yaxis: y3
    fill: tozeroy
    filters:
      - multiply: -1
  - entity: sensor.power
    name: LG
    filters:
      - multiply: -1
  - entity: sensor.solar_radiation
    name: Sun radiation
    yaxis: y2
    line:
      - color: red
  - entity: sensor.toko_price
    name: тарифа

I think you are going to have difficulties because you have so many entities overlaid on the same plot. You need to assign every entity to an axis, and then set the range for each axis so that the ranges have the same ratio between max and min. You may have to use a fixed scale rather than auto range after scroll.

For example you have yaxis2 with range -0.1 to 1000 and yaxis3 with range -1.25 to 12000. If you change yaxis 3 to -1.2 to 12000 or -1.25 to 12500 then both have the same ratio of -10000. You also haven't specified the range for yaxis1, so that will change with the data.

I would suggest separating some of these plots out into their own axes using the grid function, then you can group like data together, eg all voltages, all powers etc. Here is a thread that shows an example of that: #430

4 show Volts
4 Watts
1 Radiation
1 angle
1 electric tariff
@caiusseverus If set range limit to yaxes: all start to be broken showing unproportionable
p.s.
still cannot make left and right values scale as your example.
image

p.p.s.
If put yaxis: y4 in place marked with ###
no graph at all
image

editing tool needed ;(

type: custom:plotly-graph
defaults:
  entity:
    show_value: true
  yaxes:
    visible: true
    showgrid: true
    range:
      - -10000
      - 10000
  yaxis2:
    visible: true
    fixedrange: true
    overlaying: 'y'
    side: left
    position: 10
    title: radiation
    tickmode: sync
    range:
      - -0.1
      - 1000
  yaxis3:
    visible: true
    fixedrange: true
    title: watt
    overlaying: 'y'
    side: left
    anchor: free
    autoshift: true
    tickmode: sync
    range:
      - -1.25
      - 12000
  yaxis4:
    title: Volts
    overlaying: 'y'
    visible: true
    showgrid: true
    side: right
    anchor: free
    autoshift: true
    tickmode: sync
    range:
      - -10
      - 260
hours_to_show: 12
autorange_after_scroll: true
refresh_interval: 10
title: Средна стойност за деня
layout:
  legend:
    orientation: h
    itemsizing: constant
    font:
      size: 10
  xaxis:
    visible: true
    fixedrange: false
    domain:
      - 0
      - 0.95
    rangeselector:
      'y': 1.1
      buttons:
        - count: 30
          step: minute
        - count: 3
          step: hour
        - count: 6
          step: hour
        - count: 12
          step: hour
        - count: 1
          step: day
        - count: 3
          step: day
        - count: 7
          step: day
entities:
  - entity: sensor.ups_input_voltage
    name: UPS V
    yaxis: y4
  - entity: sensor.ups_nominal_input_voltage
    name: 230V
    yaxis: y4
  - entity: sensor.upsa_nominal_input_voltage
    name: 220V
    yaxis: y4
  - entity: sensor.clamp_meter_voltage_2
    name: clamp V
    ##################
  - entity: sensor.clamp_meter_power_2
    name: clamp power
    filters:
      - multiply: -1
    yaxis: y3
    fill: tozeroy
  - entity: sensor.output_1_wattage
    name: MIN600Tl-x
    yaxis: y3
    fill: tozeroy
    line:
      color: lightgreen
  - entity: sensor.8266_growatt_grid_active_power
    name: 4200TL-XE
    line:
      color: green
    fill: tozeroy
  - entity: sensor.esp8266_sun_elevation
    name: sun pos
  - entity: sensor.sp2_watt
    name: fridge
    fill: tozeroy
    yaxis: y3
    filters:
      - multiply: -1
  - entity: sensor.smartplug3_power
    name: serv
    yaxis: y3
    fill: tozeroy
    filters:
      - multiply: -1
  - entity: sensor.power
    name: LG
    filters:
      - multiply: -1
  - entity: sensor.solar_radiation
    name: Sun radiation
    yaxis: y2
    line:
      - color: red
  - entity: sensor.toko_price
    name: тарифа

Officially plotly.py marked non sharing zero line as BUG

All I can suggest is start from blank and add one entity at a time, allocating them each to axes as you add them. You should be able to see if it's working as intended. Trying to sort out all those different plots in one go is going to be a lot more difficult. If you don't want to delete everything completely, then comment out all the entities with a # at the beginning of the lines and uncomment them as you go.