Skip to content

Commit

Permalink
Add presets and xaxes defaults (#526)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcbr authored Jan 20, 2025
1 parent 966afa4 commit eafceb2
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 11 deletions.
108 changes: 107 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ hours_to_show: current_day

## Default trace & axis styling

default configurations for all entities and all yaxes (e.g yaxis, yaxis2, yaxis3, etc).
default configurations for all entities and all xaxes (e.g xaxis, xaxis2, xaxis3, etc) and yaxes (e.g yaxis, yaxis2, yaxis3, etc).

```yaml
type: custom:plotly-graph
Expand All @@ -934,6 +934,8 @@ defaults:
fill: tozeroy
line:
width: 2
xaxes:
showgrid: false # Disables vertical gridlines
yaxes:
fixedrange: true # disables vertical zoom & scroll
```
Expand Down Expand Up @@ -1040,6 +1042,110 @@ config:

When using `hours_to_show: current_week`, the "First day of the week" configured in Home Assistant is used

## Presets

If you find yourself reusing the same card configuration frequently, you can save it as a preset.

### Setup

Presets are loaded from the global `PlotlyGraphCardPresets` JS object (such that they can be shared across different dashboards).
The recommended way to add or modify presets is to set up a `plotly_presets.js` script in the `www` subdirectory of your `config` folder.
```js
window.PlotlyGraphCardPresets = {
// Add your presets here with the following format (or check the examples below)
// PresetName: { PresetConfiguration }
};
```
To ensure this file is loaded on every dashboard, add the following lines to your `configuration.yaml`.
```yaml
frontend:
extra_module_url:
- /local/plotly_presets.js
```
You might have to clear your browser cache or restart HA for changes to take effect.

### Examples

The preset configuration should be defined as a JS object instead of the YAML format used by the card.
Below is an example YAML configuration that is split into several corresponding presets.

<table>
<tr>
<th>YAML configuration</th>
<th>Preset configurations</th>
</tr>
<tr style="vertical-align:top">
<td>

```yaml
hours_to_show: current_day
time_offset: -24h
defaults:
entity:
hovertemplate: "$fn ({ get }) => `%{y:,.1f} ${get('.unit_of_measurement')}<extra>${get('.name')}</extra>`"
xaxes:
showspikes: true
spikemode: across
spikethickness: -2
```
</td>
<td>
```js
window.PlotlyGraphCardPresets = {
yesterday: { // Start of preset with name 'yesterday'
hours_to_show: "current_day",
time_offset: "-24h",
},
simpleHover: { // Start of preset with name 'simpleHover'
defaults: {
entity: {
hovertemplate: ({get}) => `%{y:,.1f} ${get(".unit_of_measurement")}<extra>${get(".name")}</extra>`,
},
},
},
verticalSpikes: { // Start of preset with name 'verticalSpikes'
defaults: {
xaxes: {
showspikes: true,
spikemode: "across",
spikethickness: -2,
},
},
},
};
```

</td>
</tr>
</table>

### Usage

To use your defined templates, simply specify the preset name under the `preset` key.
You can also specify a list of preset names to combine several of them.

E.g. with the above preset definitions, we can show yesterday's temperatures.
```yaml
type: custom:plotly-graph
entities:
- sensor.temperature1
- sensor.temperature2
preset: yesterday
```
Or show a simplified hover tooltip together with vertical spikes.
```yaml
type: custom:plotly-graph
entities:
- sensor.temperature1
- sensor.temperature2
preset:
- simpleHover
- verticalSpikes
```
# deprecations:
### `no_theme`
Expand Down
56 changes: 48 additions & 8 deletions src/parse-config/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Config, InputConfig } from "../types";
import { parseColorScheme } from "./parse-color-scheme";
import { getEntityIndex } from "./parse-config";
import getThemedLayout, { HATheme } from "./themed-layout";
declare const window: Window & { PlotlyGraphCardPresets?: Record<string, InputConfig> };
const noop$fn = () => () => {};
const defaultEntityRequired = {
entity: "",
Expand Down Expand Up @@ -59,6 +60,7 @@ const defaultYamlRequired = {
raw_plotly: false,
defaults: {
entity: {},
xaxes: {},
yaxes: {},
},
layout: {},
Expand All @@ -68,6 +70,15 @@ const defaultYamlRequired = {

//

const defaultExtraXAxes: Partial<Plotly.LayoutAxis> = {
// automargin: true, // it makes zooming very jumpy
type: "date",
autorange: false,
overlaying: "x",
showgrid: false,
visible: false,
};

const defaultExtraYAxes: Partial<Plotly.LayoutAxis> = {
// automargin: true, // it makes zooming very jumpy
side: "right",
Expand Down Expand Up @@ -98,6 +109,12 @@ const defaultYamlOptional: {
type: "date",
// automargin: true, // it makes zooming very jumpy
},
...Object.fromEntries(
Array.from({ length: 28 }).map((_, i) => [
`xaxis${i + 2}`,
{ ...defaultExtraXAxes },
])
),
yaxis: {
// automargin: true, // it makes zooming very jumpy
},
Expand Down Expand Up @@ -144,29 +161,52 @@ const defaultYamlOptional: {
},
};

function getPresetYaml(presets: string | string[] | undefined, skips?: Set<string>): Partial<InputConfig> {
if (!window.PlotlyGraphCardPresets || presets === undefined) return {};
if (!Array.isArray(presets)) presets = [presets];
if (presets.length == 0) return {};
if (skips === undefined) skips = new Set<string>();
const nestedPresets: string[] = [];
const presetYamls = presets.map((preset) => {
const yaml = window.PlotlyGraphCardPresets![preset] ?? {};
if (yaml.preset !== undefined) {
if (!Array.isArray(yaml.preset)) yaml.preset = [yaml.preset];
nestedPresets.push(...yaml.preset);
}
return yaml;
});
const newPresets = nestedPresets.filter((preset) => !skips.has(preset));
const nestedYaml = getPresetYaml(newPresets, new Set([...skips, ...presets]));
return merge({}, ...presetYamls, nestedYaml);
}

export function addPreParsingDefaults(
yaml_in: InputConfig,
css_vars: HATheme
): InputConfig {
// merging in two steps to ensure ha_theme and raw_plotly_config took its default value
let yaml = merge({}, yaml_in, defaultYamlRequired, yaml_in);
const preset = getPresetYaml(yaml.preset);
for (let i = 1; i < 31; i++) {
const yaxis = "yaxis" + (i == 1 ? "" : i);
yaml.layout[yaxis] = merge(
{},
yaml.layout[yaxis],
yaml.defaults.yaxes,
yaml.layout[yaxis]
);
for (const d of ["x", "y"]) {
const axis = d + "axis" + (i == 1 ? "" : i);
yaml.layout[axis] = merge(
{},
yaml.layout[axis],
yaml.defaults[d + "axes"],
preset.defaults?.[d+ "axes"] ?? {},
yaml.layout[axis]
);
}
}

yaml = merge(
{},
yaml,
{
layout: yaml.ha_theme ? getThemedLayout(css_vars) : {},
},
yaml.raw_plotly_config ? {} : defaultYamlOptional,
preset,
yaml
);

Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export type InputConfig = {
} & Partial<Plotly.PlotData>)[];
defaults?: {
entity?: Partial<Plotly.PlotData>;
xaxes?: Partial<Plotly.Layout["xaxis"]>;
yaxes?: Partial<Plotly.Layout["yaxis"]>;
};
on_dblclick?: Function;
Expand All @@ -74,6 +75,7 @@ export type InputConfig = {
minimal_response?: boolean; // defaults to true
disable_pinch_to_zoom?: boolean; // defaults to false
autorange_after_scroll?: boolean; // defaults to false
preset?: string | string[];
};

export type EntityConfig = EntityIdConfig & {
Expand Down
15 changes: 13 additions & 2 deletions yaml-editor/src/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -73274,7 +73274,7 @@
],
"type": "object"
},
"With$fn<{entity?:Partial<Plotly.PlotData>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>": {
"With$fn<{entity?:Partial<Plotly.PlotData>|undefined;xaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>": {
"properties": {
"entity": {
"anyOf": [
Expand All @@ -73287,6 +73287,17 @@
}
]
},
"xaxes": {
"anyOf": [
{
"pattern": "^[\\s]*\\$(ex|fn)\\s[\\s\\S]+$",
"type": "string"
},
{
"$ref": "#/definitions/With$fn<Partial<Partial<Plotly.LayoutAxis>>>"
}
]
},
"yaxes": {
"anyOf": [
{
Expand Down Expand Up @@ -100647,7 +100658,7 @@
"type": "string"
},
{
"$ref": "#/definitions/With$fn<{entity?:Partial<Plotly.PlotData>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>"
"$ref": "#/definitions/With$fn<{entity?:Partial<Plotly.PlotData>|undefined;xaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;yaxes?:Partial<Partial<Plotly.LayoutAxis>>|undefined;}>"
}
]
},
Expand Down

0 comments on commit eafceb2

Please sign in to comment.