diff --git a/frontend/src/queries/nodes/DataVisualization/Components/Charts/LineGraph.tsx b/frontend/src/queries/nodes/DataVisualization/Components/Charts/LineGraph.tsx index 97ac3930b9088..2afd754018be5 100644 --- a/frontend/src/queries/nodes/DataVisualization/Components/Charts/LineGraph.tsx +++ b/frontend/src/queries/nodes/DataVisualization/Components/Charts/LineGraph.tsx @@ -31,7 +31,8 @@ export const LineGraph = (): JSX.Element => { // TODO: Extract this logic out of this component and inject values in // via props. Make this a purely presentational component - const { xData, yData, presetChartHeight, visualizationType, showEditingUI } = useValues(dataVisualizationLogic) + const { xData, yData, presetChartHeight, visualizationType, showEditingUI, chartSettings } = + useValues(dataVisualizationLogic) const isBarChart = visualizationType === ChartDisplayType.ActionsBar || visualizationType === ChartDisplayType.ActionsStackedBar const isStackedBarChart = visualizationType === ChartDisplayType.ActionsStackedBar @@ -254,7 +255,7 @@ export const LineGraph = (): JSX.Element => { }, y: { display: true, - beginAtZero: true, + beginAtZero: chartSettings.yAxisAtZero ?? true, stacked: isAreaChart || isStackedBarChart, ticks: { display: true, @@ -273,7 +274,7 @@ export const LineGraph = (): JSX.Element => { plugins: [dataLabelsPlugin], }) return () => newChart.destroy() - }, [xData, yData, visualizationType, goalLines]) + }, [xData, yData, visualizationType, goalLines, chartSettings]) return (
{ - const { goalLines } = useValues(displayLogic) - const { addGoalLine, updateGoalLine, removeGoalLine } = useActions(displayLogic) + const { goalLines, chartSettings } = useValues(displayLogic) + const { addGoalLine, updateGoalLine, removeGoalLine, updateChartSettings } = useActions(displayLogic) return (
- Goal Line -
+ Chart settings + +
+ Begin Y axis at zero + { + updateChartSettings({ yAxisAtZero: value }) + }} + /> +
+ +
+ Goal line {goalLines.map((goalLine, goalLineIndex) => (
diff --git a/frontend/src/queries/nodes/DataVisualization/dataVisualizationLogic.ts b/frontend/src/queries/nodes/DataVisualization/dataVisualizationLogic.ts index 79d02dd974d13..901745f5f1d09 100644 --- a/frontend/src/queries/nodes/DataVisualization/dataVisualizationLogic.ts +++ b/frontend/src/queries/nodes/DataVisualization/dataVisualizationLogic.ts @@ -5,7 +5,13 @@ import { insightSceneLogic } from 'scenes/insights/insightSceneLogic' import { teamLogic } from 'scenes/teamLogic' import { insightVizDataCollectionId } from '~/queries/nodes/InsightViz/InsightViz' -import { AnyResponseType, ChartAxis, ChartSettingsFormatting, DataVisualizationNode } from '~/queries/schema' +import { + AnyResponseType, + ChartAxis, + ChartSettings, + ChartSettingsFormatting, + DataVisualizationNode, +} from '~/queries/schema' import { QueryContext } from '~/queries/types' import { ChartDisplayType, InsightLogicProps, ItemMode } from '~/types' @@ -124,9 +130,10 @@ export const dataVisualizationLogic = kea([ deleteYSeries: (seriesIndex: number) => ({ seriesIndex }), clearAxis: true, setQuery: (node: DataVisualizationNode) => ({ node }), + updateChartSettings: (settings: ChartSettings) => ({ settings }), setSideBarTab: (tab: SideBarTab) => ({ tab }), }), - reducers({ + reducers(({ props }) => ({ visualizationType: [ ChartDisplayType.ActionsTable as ChartDisplayType, { @@ -196,7 +203,18 @@ export const dataVisualizationLogic = kea([ setSideBarTab: (_state, { tab }) => tab, }, ], - }), + chartSettings: [ + props.query.chartSettings ?? ({} as ChartSettings), + { + updateChartSettings: (state, { settings }) => { + return { ...mergeObject(state, settings) } + }, + setQuery: (state, { node }) => { + return { ...mergeObject(state, node.chartSettings ?? {}) } + }, + }, + ], + })), selectors({ columns: [ (s) => [s.response], @@ -329,19 +347,23 @@ export const dataVisualizationLogic = kea([ ], dataVisualizationProps: [() => [(_, props) => props], (props): DataVisualizationLogicProps => props], }), - listeners(({ props }) => ({ + listeners(({ props, actions }) => ({ + updateChartSettings: ({ settings }) => { + actions.setQuery({ + ...props.query, + chartSettings: { ...(props.query.chartSettings ?? {}), ...settings }, + }) + }, setQuery: ({ node }) => { if (props.setQuery) { props.setQuery(node) } }, setVisualizationType: ({ visualizationType }) => { - if (props.setQuery) { - props.setQuery({ - ...props.query, - display: visualizationType, - }) - } + actions.setQuery({ + ...props.query, + display: visualizationType, + }) }, })), afterMount(({ actions, props }) => { @@ -392,36 +414,32 @@ export const dataVisualizationLogic = kea([ } }, selectedXAxis: (value: string | null) => { - if (props.setQuery) { - const yColumns = - values.selectedYAxis?.filter((n: SelectedYAxis | null): n is SelectedYAxis => Boolean(n)) ?? [] - const xColumn: ChartAxis | undefined = value !== null ? { column: value } : undefined - - props.setQuery({ - ...props.query, - chartSettings: { - ...(props.query.chartSettings ?? {}), - yAxis: yColumns.map((n) => ({ column: n.name, settings: n.settings })), - xAxis: xColumn, - }, - }) - } + const yColumns = + values.selectedYAxis?.filter((n: SelectedYAxis | null): n is SelectedYAxis => Boolean(n)) ?? [] + const xColumn: ChartAxis | undefined = value !== null ? { column: value } : undefined + + actions.setQuery({ + ...props.query, + chartSettings: { + ...(props.query.chartSettings ?? {}), + yAxis: yColumns.map((n) => ({ column: n.name, settings: n.settings })), + xAxis: xColumn, + }, + }) }, selectedYAxis: (value: (SelectedYAxis | null)[] | null) => { - if (props.setQuery) { - const yColumns = value?.filter((n: SelectedYAxis | null): n is SelectedYAxis => Boolean(n)) ?? [] - const xColumn: ChartAxis | undefined = - values.selectedXAxis !== null ? { column: values.selectedXAxis } : undefined - - props.setQuery({ - ...props.query, - chartSettings: { - ...(props.query.chartSettings ?? {}), - yAxis: yColumns.map((n) => ({ column: n.name, settings: n.settings })), - xAxis: xColumn, - }, - }) - } + const yColumns = value?.filter((n: SelectedYAxis | null): n is SelectedYAxis => Boolean(n)) ?? [] + const xColumn: ChartAxis | undefined = + values.selectedXAxis !== null ? { column: values.selectedXAxis } : undefined + + actions.setQuery({ + ...props.query, + chartSettings: { + ...(props.query.chartSettings ?? {}), + yAxis: yColumns.map((n) => ({ column: n.name, settings: n.settings })), + xAxis: xColumn, + }, + }) }, })), ]) diff --git a/frontend/src/queries/nodes/DataVisualization/displayLogic.ts b/frontend/src/queries/nodes/DataVisualization/displayLogic.ts index 0dd3fef0de781..06ce220d5bb76 100644 --- a/frontend/src/queries/nodes/DataVisualization/displayLogic.ts +++ b/frontend/src/queries/nodes/DataVisualization/displayLogic.ts @@ -16,8 +16,8 @@ export const displayLogic = kea([ path(['queries', 'nodes', 'DataVisualization', 'displayLogic']), props({ key: '' } as DisplayLogicProps), connect({ - values: [dataVisualizationLogic, ['yData', 'query']], - actions: [dataVisualizationLogic, ['setQuery']], + values: [dataVisualizationLogic, ['yData', 'query', 'chartSettings']], + actions: [dataVisualizationLogic, ['setQuery', 'updateChartSettings']], }), actions(({ values }) => ({ addGoalLine: () => ({ yData: values.yData }), diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 3984f612d6aad..9a201ff3ba179 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -2043,6 +2043,10 @@ "$ref": "#/definitions/ChartAxis" }, "type": "array" + }, + "yAxisAtZero": { + "description": "Whether the Y axis should start at zero", + "type": "boolean" } }, "type": "object" diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 3db53c8204d38..c9d134c84604e 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -570,6 +570,8 @@ export interface ChartSettings { xAxis?: ChartAxis yAxis?: ChartAxis[] goalLines?: GoalLine[] + /** Whether the Y axis should start at zero */ + yAxisAtZero?: boolean } export interface DataVisualizationNode extends Node { diff --git a/posthog/schema.py b/posthog/schema.py index bca2db0f40988..1ef4c7920ced2 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -1906,6 +1906,7 @@ class ChartSettings(BaseModel): goalLines: Optional[list[GoalLine]] = None xAxis: Optional[ChartAxis] = None yAxis: Optional[list[ChartAxis]] = None + yAxisAtZero: Optional[bool] = Field(default=None, description="Whether the Y axis should start at zero") class Response(BaseModel):