From 1402802031ee7a06e5e2732712492c4b397f490e Mon Sep 17 00:00:00 2001 From: Petar Petrov Date: Fri, 31 Jan 2025 18:42:51 +0200 Subject: [PATCH] Echarts: auto scale Y in log charts (#23994) * Echarts: auto scale Y in log charts * fix statistics chart log scale --- .../chart/state-history-chart-line.ts | 46 +++++++++++++------ src/components/chart/statistics-chart.ts | 41 +++++++++++++---- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts index ec614ab3f1..92d7b5ace5 100644 --- a/src/components/chart/state-history-chart-line.ts +++ b/src/components/chart/state-history-chart-line.ts @@ -190,11 +190,24 @@ export class StateHistoryChartLine extends LitElement { ) { const dayDifference = differenceInDays(this.endTime, this.startTime); const rtl = computeRTL(this.hass); - const minYAxis = - // log(0) is -Infinity, so we need to set a minimum value - this.logarithmicScale && typeof this.minYAxis === "number" - ? Math.max(this.minYAxis, 0.1) - : this.minYAxis; + let minYAxis: number | ((values: { min: number }) => number) | undefined = + this.minYAxis; + let maxYAxis: number | ((values: { max: number }) => number) | undefined = + this.maxYAxis; + if (typeof minYAxis === "number") { + if (this.fitYData) { + minYAxis = ({ min }) => Math.min(min, this.minYAxis!); + } + } else if (this.logarithmicScale) { + minYAxis = ({ min }) => (min > 0 ? min * 0.95 : min * 1.05); + } + if (typeof maxYAxis === "number") { + if (this.fitYData) { + maxYAxis = ({ max }) => Math.max(max, this.maxYAxis!); + } + } else if (this.logarithmicScale) { + maxYAxis = ({ max }) => (max > 0 ? max * 1.05 : max * 0.95); + } this._chartOptions = { xAxis: { type: "time", @@ -221,14 +234,8 @@ export class StateHistoryChartLine extends LitElement { yAxis: { type: this.logarithmicScale ? "log" : "value", name: this.unit, - min: - this.fitYData && typeof minYAxis === "number" - ? ({ min }) => Math.min(min, minYAxis!) - : minYAxis, - max: - this.fitYData && typeof this.maxYAxis === "number" - ? ({ max }) => Math.max(max, this.maxYAxis!) - : this.maxYAxis, + min: this._clampYAxis(minYAxis), + max: this._clampYAxis(maxYAxis), position: rtl ? "right" : "left", scale: true, nameGap: 2, @@ -694,6 +701,19 @@ export class StateHistoryChartLine extends LitElement { this._entityIds = entityIds; this._datasetToDataIndex = datasetToDataIndex; } + + private _clampYAxis(value?: number | ((values: any) => number)) { + if (this.logarithmicScale) { + // log(0) is -Infinity, so we need to set a minimum value + if (typeof value === "number") { + return Math.max(value, 0.1); + } + if (typeof value === "function") { + return (values: any) => Math.max(value(values), 0.1); + } + } + return value; + } } customElements.define("state-history-chart-line", StateHistoryChartLine); diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts index f35d1cdcbb..9c7ea82e0d 100644 --- a/src/components/chart/statistics-chart.ts +++ b/src/components/chart/statistics-chart.ts @@ -218,6 +218,24 @@ export class StatisticsChart extends LitElement { private _createOptions() { const splitLineStyle = this.hass.themes?.darkMode ? { opacity: 0.15 } : {}; const dayDifference = this.daysToShow ?? 1; + let minYAxis: number | ((values: { min: number }) => number) | undefined = + this.minYAxis; + let maxYAxis: number | ((values: { max: number }) => number) | undefined = + this.maxYAxis; + if (typeof minYAxis === "number") { + if (this.fitYData) { + minYAxis = ({ min }) => Math.min(min, this.minYAxis!); + } + } else if (this.logarithmicScale) { + minYAxis = ({ min }) => (min > 0 ? min * 0.95 : min * 1.05); + } + if (typeof maxYAxis === "number") { + if (this.fitYData) { + maxYAxis = ({ max }) => Math.max(max, this.maxYAxis!); + } + } else if (this.logarithmicScale) { + maxYAxis = ({ max }) => (max > 0 ? max * 1.05 : max * 0.95); + } this._chartOptions = { xAxis: { type: "time", @@ -252,14 +270,8 @@ export class StatisticsChart extends LitElement { position: computeRTL(this.hass) ? "right" : "left", // @ts-ignore scale: true, - min: - this.fitYData && typeof this.minYAxis === "number" - ? ({ min }) => Math.min(min, this.minYAxis!) - : this.minYAxis, - max: - this.fitYData && typeof this.maxYAxis === "number" - ? ({ max }) => Math.max(max, this.maxYAxis!) - : this.maxYAxis, + min: this._clampYAxis(minYAxis), + max: this._clampYAxis(maxYAxis), splitLine: { show: true, lineStyle: splitLineStyle, @@ -556,6 +568,19 @@ export class StatisticsChart extends LitElement { return val; } + private _clampYAxis(value?: number | ((values: any) => number)) { + if (this.logarithmicScale) { + // log(0) is -Infinity, so we need to set a minimum value + if (typeof value === "number") { + return Math.max(value, 0.1); + } + if (typeof value === "function") { + return (values: any) => Math.max(value(values), 0.1); + } + } + return value; + } + static styles = css` :host { display: block;