Open-source project
dbuezas/lovelace-plotly-graph-card avatar
dbuezas/lovelace-plotly-graph-card

lovelace-plotly-graph-card gives Home Assistant a real Plotly chart

Highly customisable Lovelace card to plot interactive graphs. Brings scrolling, zooming, and much more!

662 stars34 forksTypeScriptMIT

At a glance

What is it?
lovelace-plotly-graph-card is a Home Assistant custom card that renders sensor history as an interactive Plotly graph, with scrolling, zooming, multiple axes and per-entity fill and line styling, and it goes well beyond the built-in History card in what it can do. The trade is that most of its configuration lives in YAML, and the visual editor only covers the basics.
Who is it for?
Adopt lovelace-plotly-graph-card if you run Home Assistant and want charts you can scroll, zoom and restyle per series, since it hands you the full Plotly layout and config objects instead of the fixed presentation of the standard History card.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the card replaces in a Home Assistant dashboard

lovelace-plotly-graph-card is a Home Assistant custom card that plots interactive graphs, and the project's own description says it brings scrolling, zooming and much more. The card type is custom:plotly-graph, and it is registered through the Home Assistant Community Store, with a HACS badge in the README and a hacs.json in the repository root.

The comparison that matters is with the built-in History card. The README says the visual config editor available is for Basic Configs, and adds a parenthetical that the editor of the standard History Card is being reused. Cheap, yes, but it works fine, with the instruction to use yaml for advanced functionality. That is the trade in one sentence: a card that can do far more than the History card, with a visual editor that covers only the basics and a YAML surface for everything else.

The feature set is where the card earns its place. It takes entities, plots them, and exposes the axes and layout to configuration. It supports multiple Y axes with alignment, per-entity line and fill styling, range selector buttons, and it is built on Plotly, which means the layout and config objects are Plotly's own.

The project is TypeScript, MIT licensed, and the release history is very recent: v4.0.2 on 2026-10-13, v4.0.1 on 2026-10-11 and v4.0.0 on 2026-10-10, with the last push on 2026-10-14. The topic list includes navigate.

There is also supporting documentation worth knowing about: an index of examples with images that lets you browse configurations by looking at the pictures, a web app for YAML syntax validation and autocomplete, and a thread on the Home Assistant community forum.

The basic card configuration and the window it shows

The smallest useful configuration is short, and the example in the README shows exactly which keys matter:

yaml
type: custom:plotly-graph
entities:
  - sensor.monthly_internet_energy
  - sensor.monthly_teig_energy
  - sensor.monthly_office_energy
  - sensor.monthly_waschtrockner_energy
hours_to_show: 24
refresh_interval: 10

The type key registers the custom card with Home Assistant. The entities list names the sensors to plot, and the entity list is where per-series configuration goes in the advanced form, since each entry can carry its own styling and its own Y axis. hours_to_show sets the time window, and the examples elsewhere in the README show it accepting both a plain number, meaning hours, and a suffixed form such as 1h or 12h. refresh_interval is in seconds.

That is the whole basic surface. Everything beyond it, and there is a lot, is YAML.

The Y axis behaviour is documented in a way that suggests it has caused trouble, and it is worth reading before you configure it. The visual editor's min_y_axis and max_y_axis settings control the main Y-axis range, and either bound can be omitted to keep that side automatic. Bounds are entered in data units, including on logarithmic axes, and non-finite bounds and non-positive logarithmic bounds are ignored. If the minimum exceeds the maximum, both editor bounds are ignored, and if a single bound would reverse the automatically calculated range, that bound is ignored as well.

Three more options interact with that. logarithmic_scale selects a logarithmic main Y-axis, and when it is false or omitted Plotly chooses the axis type automatically unless explicitly configured. fit_y_data expands the automatic range to include both the data and the editor bounds rather than treating the bounds as fixed limits. And autorange_after_scroll recalculates the main Y-axis after every render, overriding fixed editor bounds, while bounds included by fit_y_data remain included. Explicit Plotly axis types, ranges, autorange settings and autorangeoptions take precedence over the corresponding editor settings.

Aligning zero across overlaid axes

The align_zero option is the one that shows the card thinking about real dashboard design rather than just forwarding configuration to Plotly.

The problem it solves: when you overlay two linear Y axes, each is scaled independently, so zero sits at a different height on each. A temperature axis running from 20 to 25 degrees and a power axis running from 0 to 100 kilowatts will have their zero lines in different places, and any visual correlation you try to read between them is an artefact of the scaling rather than of the data.

yaml
type: custom:plotly-graph
align_zero: true
entities:
  - entity: sensor.power
    yaxis: y
  - entity: sensor.electricity_price
    yaxis: y2

With align_zero set to true, zero is placed at the same height on automatically scaled, overlaid linear Y axes. Axes whose data does not cross zero are extended to include it, so a 20 to 25 degree temperature range becomes 0 to 25 degrees or wider. That is the correct behaviour, because a reader looking at two overlaid axes assumes the crossing point of the lines is meaningful.

The details are careful. Visible series with numeric data participate, hiding a series recalculates the alignment without clipping data, and hidden helper axes are ignored. The option is off by default, and it may add one Plotly relayout after rendering. It only affects overlaid linear axes with unrestricted autorange, leaving user zoom, fixed ranges and independent subplots unchanged. With autorange_after_scroll enabled, the main Y-axis is autoranged and can align even if its configuration specifies a range.

The per-entity yaxis key is what makes this usable, since it is how a series is assigned to the secondary axis rather than the main one.

Per-entity styling and passing Plotly layout through

The styling example shows the mechanism, and it is worth reading closely because it demonstrates that the card does not define its own styling vocabulary. It forwards Plotly's.

yaml
type: custom:plotly-graph
entities:
  - entity: sensor.office_plug_wattage
  # see examples: https://plotly.com/javascript/line-and-scatter/
  # see full API: https://plotly.com/javascript/reference/scatter/#scatter
  - entity: sensor.freezer_plug_power
    fill: tozeroy
    line:
      color: red
      dash: dot
      width: 1

layout:
  plot_bgcolor: lightgray
  height: 400
config:
  scrollZoom: false

hours_to_show: 1h
refresh_interval: 10 # in seconds

The fill key with a tozeroy value and the nested line object with color, dash and width are Plotly trace attributes, not card options. The layout key holds a Plotly layout, so plot_bgcolor and height go straight through. And the config key holds a Plotly config, which is where scrollZoom false turns off the scroll-to-zoom interaction that would otherwise fight with the dashboard's own scrolling on a touch screen.

That last point is a real design consideration for a card living inside a scrollable dashboard. The card brings scrolling and zooming, but a Plotly graph that captures every wheel event makes the dashboard underneath unusable, so the config passthrough is how you arbitrate between them.

The range selector example shows the same pattern at the axis level, with a rangeselector under xaxis carrying a y value and a buttons list, and the README links to the Plotly documentation for both the range slider examples and the layout.xaxis.rangeselector API reference. Learning Plotly's own API is effectively a prerequisite, and the card is the bridge rather than the abstraction.

Installing the card into a Home Assistant instance

There are two installation paths, and the recommended one is the Home Assistant Community Store, which is HACS.

The HACS route is two steps: install HACS, then search for and install Plotly Graph Card. The README also points at a badge that opens the Home Assistant instance directly to the repository inside the Community Store.

The manual route starts at the Releases page, and the instruction is to download all the .js files of the release into <config>/www/plotly-graph-card/. The reason all of them matter is stated plainly: the card loads the other files only when a chart needs them, so a partial download gives you a card that works for some plots and fails for others. From a terminal on Home Assistant, the README gives a one-liner that creates the directory, queries the GitHub releases API for the latest release, extracts the browser_download_url values and downloads each one:

sh
   mkdir -p /config/www/plotly-graph-card && cd /config/www/plotly-graph-card
   curl -s https://api.github.com/repos/dbuezas/lovelace-plotly-graph-card/releases/latest | grep -o '"browser_download_url": *"[^"]*"' | cut -d'"' -f4 | xargs -n1 curl -sLO

Then the card has to be registered as a resource in Home Assistant, and there are two ways. The UI route is Settings, then Dashboards, then the More Options icon, then Resources, then Add Resource, with the URL set to /local/plotly-graph-card/plotly-graph-card.js and the resource type set to JavaScript Module. The README includes the note that if you do not see the Resources menu you need to enable Advanced Mode in your User Profile. The YAML equivalent adds a resources entry to the lovelace section:

yaml
        - url: /local/plotly-graph-card/plotly-graph-card.js
          type: module

The resource registration step is the part people miss, and it is also the part that a dashboard designer needs to understand: the card is not a Home Assistant built-in, it is a JavaScript module served from the www directory and loaded by the frontend.

The development setup and the test scripts behind it

The repository is a modern TypeScript project with Bun as the package manager, and the package manifest is explicit about it. The engines field requires node >=22.12.0, and for npm, pnpm and yarn it says please use bun install. There is a bun.lock and a bunfig.toml at the root, and the scripts show a build.mjs entry point with a hot-reload mode for development.

The script list is worth reading because it shows how the card is verified. The lint setup uses oxfmt and oxlint, with the lint:check script running the formatter check and the linter with type-aware checking and warnings denied, ignoring the yaml-editor directory, which has its own separate lint script. The unit tests run under vitest, and there are named subsets for the cache, for the statistics and for the date ranges.

The browser-oriented tests are the interesting part, and they are separate scripts rather than vitest files. There is test:browser, test:autorange, test:loading, test:resize, test:zero-alignment, test:card-lifecycle, test:touch and test:split, each running a node script from the script directory, and playwright is in the dev dependencies. So the card's behaviour around axis autorange, zero alignment, touch gestures, resize handling and the card lifecycle is verified against a real browser rather than a DOM stub, which is a reasonable choice for a component whose whole value is Plotly interaction.

The version field in the manifest reads to-be-set-on-release, so the published version comes from the release process rather than being committed by hand, and the release history of v4.0.0, v4.0.1 and v4.0.2 within four days is consistent with that flow.

Where this card is the wrong tool

Three limitations, and the first is a documentation gap you will hit immediately.

The first is that the configuration surface is Plotly's, not the card's. The README's own links point at the Plotly JavaScript reference for the trace attributes, the layout and the config object, which means that to configure anything beyond the basics you need to know Plotly's API. That is a fair trade for a card aimed at people who want Plotly's capabilities, and a poor one for someone who expected a card with a small set of friendly options. The visual editor does not change this, because the README says it covers Basic Configs only.

The second is the resource installation step, which has a lasting operational cost. The card must be served from the www directory and registered as a JavaScript module resource, and a full Home Assistant resource update or a container recreation can leave the dashboard broken until the resource is re-registered. That is different from a custom card that Home Assistant loads by type alone, and it is a reason to prefer the HACS route if your setup supports it.

The third is that the card is a web frontend component, which constrains where it works. The card loads additional JavaScript modules on demand when a chart needs them, so a dashboard in an environment that restricts script loading, or the Home Assistant mobile companion app with a different frontend, may not behave the same as the desktop dashboard. The repository does not document mobile support either way, so treat it as unverified.

The alternative approach is the built-in History card with the History card plus a community card for advanced cases, and the difference in approach is exactly the trade the README states. The built-in card needs no resource registration and has a proper visual editor, and it renders a fixed presentation. This card renders whatever Plotly can, and it asks you to learn Plotly and to manage the resource yourself. For a dashboard with one or two sensors, the built-in card is the right answer, and for a dashboard with multiple axes, custom fills and range selectors, this card is the one that can do what you want.

Editorial conclusion

Adopt lovelace-plotly-graph-card if you run Home Assistant and want charts you can scroll, zoom and restyle per series, since it hands you the full Plotly layout and config objects instead of the fixed presentation of the standard History card. Do not adopt it if you need a maintained, documented configuration surface, because the visual editor is explicitly described as a reused and limited one, and treat mobile app behaviour as unverified, since the card loads its own JavaScript modules on demand. Verify first that the Plotly features you want are available in the version the card bundles, that your Home Assistant install can serve the resource over /local, and that the axis and autorange behaviour matches your data, in particular the interaction between fit_y_data, autorange_after_scroll and the editor bounds.

Frequently asked questions

How do I install lovelace-plotly-graph-card in Home Assistant?

The recommended route is the Home Assistant Community Store: install HACS, then search for and install Plotly Graph Card. Manually, download all the .js files of the latest release into <config>/www/plotly-graph-card/ and register the resource at /local/plotly-graph-card/plotly-graph-card.js as a JavaScript Module.

What is the difference between the visual editor and YAML for this card?

The README says the visual config editor is available for Basic Configs only and reuses the editor of the standard History Card, with the note to use yaml for advanced functionality. The visual editor's min_y_axis and max_y_axis control the main Y-axis range, with either bound omittable to stay automatic.

What does align_zero do in lovelace-plotly-graph-card?

Setting align_zero to true places zero at the same height on automatically scaled, overlaid linear Y axes, extending axes whose data does not cross zero to include it, so a 20 to 25 degree range becomes 0 to 25 or wider. It is off by default, affects only overlaid linear axes with unrestricted autorange, and may add one Plotly relayout after rendering.

How do I turn off scroll zoom on a plotly-graph card?

Use the config key, which is passed through to Plotly. The README example sets config with scrollZoom: false, alongside a layout key for plot_bgcolor and height. Setting scrollZoom to false stops the graph capturing wheel events, which matters inside a scrollable dashboard.

Does lovelace-plotly-graph-card support the Home Assistant mobile app?

The README does not document mobile support either way, so treat it as unverified. The card loads additional JavaScript modules on demand when a chart needs them, and it must be registered as a JavaScript Module resource, so behaviour in the mobile companion app depends on that loading working.

Official sources

  1. dbuezas/lovelace-plotly-graph-card on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dbuezas-lovelace-plotly-graph-card.svg)](https://hysenlabs.com/projects/dbuezas-lovelace-plotly-graph-card)

Was this useful?