Plotly interactive Graph Card

That leads to no refresh happening anymore at all, weirdly.

I realize this is a very old thread, but was wondering if this integration had the ability to export data to a CSV? It is a great graph, but would be nice to be able to export to CSV

Hi,
I’m using this pie chart to display my load sources of the day:

type: custom:plotly-graph
view_layout:
  position: sidebar
title: Load Energy Sources
entities:
  - entity: sensor.load_energy
    type: pie
    hole: 0.4
    values: |-
      $ex [
        Number(hass.states["sensor.battery_energy_out_old"].state).toFixed(2),
        Number(hass.states["sensor.simulated_grid_energy_import_meter"].state).toFixed(2),
        Number(hass.states["sensor.self_consumed_solar_energy_day"].state).toFixed(2)
      ]
    labels:
      - Battery Charge
      - Grid Offpeak
      - Self-Consumed Solar
    marker:
      colors:
        - rgb(151, 90, 182)
        - rgb(84, 144, 194)
        - rgb(255, 155, 48)
    textinfo: value+percent
hours_to_show: 1
refresh_interval: auto
layout:
  height: 410
  margin:
    t: 60
  showlegend: false
  annotations:
    - text: |-
        $fn ({hass}) =>
          "<span style='font-size: 24px;'><span style='color: rgb(255, 155, 48'>"
          + Number(hass.states['sensor.self_consumed_solar_energy_day'].state).toFixed(1) + "</span></span>kWh<br>"
          +  "</span><span style=''>Self-Consumed Solar</span><br>"
      xref: paper
      yref: paper
      xanchor: center
      yanchor: center
      x: 0.05
      'y': 1.2
      showarrow: false
    - text: |-
        $fn ({hass}) =>
          "<span style='font-size: 24px;'><span style='color: rgb(151, 90, 182)'>"
          + Number(hass.states['sensor.battery_energy_out_old'].state).toFixed(1) + "</span></span>kWh<br>"
          +  "</span><span style=''>Battery</span><br>"
      xref: paper
      yref: paper
      xanchor: center
      yanchor: center
      x: 0.5
      'y': 1.2
      showarrow: false
    - text: |-
        $fn ({hass}) =>
          "<span style='font-size: 24px;'><span style='color: rgb(84, 144, 194)'>"
          + Number(hass.states['sensor.grid_energy_in'].state).toFixed(1) + "</span></span>kWh<br>"
          +  "</span><span style=''>Grid</span><br>"
      xref: paper
      yref: paper
      xanchor: center
      yanchor: centre
      x: 0.9
      'y': 1.2
      showarrow: false
    - text: |-
        $fn ({hass}) =>
          "<span style='font-size: 24px;'><span style='color: rgb(84, 144, 194)'>"
          + Number(hass.states['sensor.load_energy'].state).toFixed(1) + "</span></span>kWh<br>"
          +  "</span><span style=''>Load</span><br>"
      xref: paper
      yref: paper
      xanchor: center
      yanchor: centre
      x: 0.5
      'y': 0.5
      showarrow: false
updatemenus:
  - buttons:
      - label: 1 Day
        method: restyle
        args:
          - hours_to_show: 24
      - label: 2 Days
        method: restyle
        args:
          - hours_to_show: 48
      - label: 7 Days
        method: restyle
        args:
          - hours_to_show: 168
      - label: 14 Days
        method: restyle
        args:
          - hours_to_show: 336
      - label: <
        method: animate
        args:
          - layout:
              xaxis.range:
                - -1
                - -1
      - label: '>'
        method: animate
        args:
          - layout:
              xaxis.range:
                - 1
                - 1
    direction: left
    pad:
      r: 10
      t: 10
    showactive: true
    type: buttons
    x: 1
    xanchor: right
    'y': 1.2
    yanchor: top

I would like to have to option to scroll back and see data from yesterday or last 30 days or this year.
Like this:


How can i do this?

Hi,

is it possible to do calculations in the charts based on two different entities (so not having one entity and e.g. convert from Celsius to Fahrenheit, but e.g. dividing the values of two entities)?

What I want to do is calculate the COP of my heat pump. I have the produced and consumed energy, and I know that I could use template sensors to do the calculation. However, it would be much easier to do the calculation in the chart, so that based on the settings in the chart I can see the daily COPs, monthly COPs, …

Thanks,
Klaus

Yes it is, see the Compute absolute humidity example

The trick is to store the entities in variables and resampling them so the x axis values align by index (i.e the nth element on the first entity represents the same time as the nth on the second one)

Great, thanks. I looked at the examples before posting here, but I missed this …

Trying Plotly to hopefully get what I am after as could not find a way to make it work with other tools. I am trying to get a guide line along with a data feed. The logic is the guide line is the indicator to if we are doing well or not with regards energy usage. Below the line we will run out, above the line we should be OK.
It seem to now have a strange outcome, by changing one setting will show which data is displayed, this is by setting raw_plotly_config: to true or false.

I have no doubt there will be errors in the code and it could be done better. I am just stuck at the moment trying to get both sets of data on one graph. Images below for both examples. Only difference is if raw_plotly_config: is set to true or false


For the x axis, try this:

  - entity: ''
    name: Guide Usage
    x: 
      - $ex new Date(new Date().setHours(7,30))
      - $ex new Date(new Date().setHours(24,30))
    y: 
      - 100
      - 10
    line:
     shape: linear

Perfect, thank you.

Added full code if it is of use to others.

type: custom:plotly-graph
hours_to_show: current_day
layout:
  yaxis:
    fixedrange: true
    range:
      - 10
      - 100
entities:
  - entity: sensor.sigen_energy_storage_system_soc
    name: Usage Today
  - entity: ''
    name: Usage Guide
    x: 
      - $ex new Date(new Date().setHours(7,30))
      - $ex new Date(new Date().setHours(24,30))
    y: 
      - 100
      - 10
    line:
     shape: linear
     dash: dot
     color: green
     width: 2
title: Battery Usage

Chart

Hi,

I’m a beginner with Plotly. I would like to plot my car tire pressure in different temperatures. I have a sensor for the tire pressure and outdoor temperature of the car (which we can assume is the tire temperature).

The syntax is a bit complex for a beginner so help would be appreciated.

Formula to calculate the new pressure is old_pressure * (new_temperature in Kelvin / old_temperature in Kelvin).

Can you post a chart with all involved entities? That would help understand your intent

Thanks for your reply. Here is a quick sketch about the chart (I know the syntax is probably completely wrong):

type: custom:plotly-graph
hours_to_show: current_day
layout:
  xaxis:
    type: number
    autorange: true
entities:
  - entity: ""
    x:
      - -30
      - -25
      - -20
      - -15
      - -10
      - -5
      - 0
      - 5
      - 10
      - 15
      - 20
      - 25
      - 30
      - 35
      - 40
      - 45
      - 50
filters:
  - fn: |-
      ({xs}) => {
        return {
          ys: {{ states('sensor.car_tire_pressure')|float * (x + 273.15) / (states('sensor.car_outside_temperature')|float + 273.15) }}
        };
      },

I mean a simple chart with the involved entities to see how the data looks like

Hi everyone,

I’ve typically used simple charts in Home Assistant so far, but I recently discovered the Plotly card, and I’m a bit overwhelmed by its potential!

I want to create a graph to display my solar production forecast.

Using the template engine, I get:

{% set data = state_attr('sensor.my_solar_production_forecast_today', 'data') %}
{{data}}

[{'timestamp': '2024-10-08 07:43:53', 'value': 0}, {'timestamp': '2024-10-08 07:45:00', 'value': 318688}, ...]

How can I best integrate this data into the Plotly card?

Thanks in advance for any guidance - I’m feeling a bit lost here!

See answer in your github discussion: Timestamp in attribute · dbuezas/lovelace-plotly-graph-card · Discussion #458 · GitHub

(updated discussion title)

Ah, sorry!

Here is a quick example with markdown card:

image

Tire pressure
Temperature	Min	Max
Current (17.0 °C) 2.825 2.85
-30	2.367	2.388
-25	2.416	2.437
-20	2.465	2.487
-15	2.513	2.536
-10	2.562	2.585
-5	2.611	2.634
0	2.659	2.683
5	2.708	2.732
10	2.757	2.781
15	2.806	2.83
20	2.854	2.879
25	2.903	2.929
30	2.952	2.978
35	3.0	    3.027
40	3.049	3.076
45	3.098	3.125
50	3.146	3.174
type: markdown
content: >-
	### Tire pressure

	|Temperature|Min|Max|

	|:------|:----|:--------|

	Current ({{ states('sensor.car_outside_temperature', with_unit=True)
	}}) |{{
	[states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min }} |{{
	[states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max }}

	-30 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (-30 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (-30 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	-25 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (-25 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (-25 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	-20 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (-20 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (-20 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	-15 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (-15 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (-15 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	-10 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (-10 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (-10 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	-5 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (-5 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (-5 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	0 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (0 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (0 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	5 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (5 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (5 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	10 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (10 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (10 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	15 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (15 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (15 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	20 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (20 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (20 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	25 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (25 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (25 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	30 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (30 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (30 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	35 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (35 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (35 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	40 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (40 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (40 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	45 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (45 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (45 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

	50 |{{ ([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | min | float * (50 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }} |{{
	([states('sensor.car_tire_pressure_front_left'),
	states('sensor.car_tire_pressure_front_right'),
	states('sensor.car_tire_pressure_rear_left'),
	states('sensor.car_tire_pressure_rear_right')] | max | float * (50 +
	273.15) / (states('sensor.car_outside_temperature')|float +
	273.15))|round(3) }}

That would be something like this.

type: custom:plotly-graph
fn_x: | 
  $ex {
    vars.x = []
    for (let temp = -30; temp <= 50; temp += 5) vars.x.push(temp);
  }
fn_pressures: | 
  $ex {
    vars.pressures = [
      hass.states['sensor.car_tire_pressure_front_left'],
      hass.states['sensor.car_tire_pressure_front_right'],
      hass.states['sensor.car_tire_pressure_rear_left'],
      hass.states['sensor.car_tire_pressure_rear_right'],
    ];
    vars.outside = hass.states['sensor.car_outside_temperature'];
  }
fn_calc: | 
  $ex {
    vars.calc = (temp) => vars.pressures.map(pressure => 
      pressure *
      (temp + 273.15) / 
      (vars.outside + 273.15)
    );
  }
title: |
  $ex `Current (${vars.outside}°C `+
    Math.min(...vars.pressures) + ' ' +
    Math.max(...vars.pressures)
entities:
  - entity: ''
    name: Tire pressure Max
    x: $ex vars.x
    y: $ex Math.max(...vars.x.map(vars.calc))
    fill: tonexty
  - entity: ''
    name: Tire pressure Min
    x: $ex vars.x
    y: $ex Math.min(...vars.x.map(vars.calc))
raw_plotly_config: true
layout:
  xaxis:
    title: °C
  yaxis:
    title: Pressure
1 Like

I have a surprise :slight_smile:

Feedback welcomed!

I managed to convert all types of this card to a json schema that then can be used to VALIDATE and AUTOCOMPLETE yaml configs, and I made a small web app for that


1 Like

I’ve just started digging into plotly in HA. Only just starting to scratch the surface.

Does anyone have suggestions how a might be able to start the graph with the majority of the lines hidden?

Thanks,
John

entities:
  - entity: sensor.x
    visible: legendonly
1 Like