From 0fbc2ea1c00335ec32fde8774e05279bb39ff9ca Mon Sep 17 00:00:00 2001 From: Sophia Mersmann Date: Fri, 3 Jan 2025 13:32:56 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20(discrete=20bar)=20hide=20horiz?= =?UTF-8?q?ontal=20axis=20(#4371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ (discrete bar) hide horizontal axis * 🔨 remove relative mode from discrete bar chart configs * 🤖 style: prettify code --- ...RemoveRelativeModeFromDiscreteBarCharts.ts | 21 ++++++++++++++ .../src/barCharts/DiscreteBarChart.tsx | 29 ++----------------- 2 files changed, 23 insertions(+), 27 deletions(-) create mode 100644 db/migration/1735896576517-RemoveRelativeModeFromDiscreteBarCharts.ts diff --git a/db/migration/1735896576517-RemoveRelativeModeFromDiscreteBarCharts.ts b/db/migration/1735896576517-RemoveRelativeModeFromDiscreteBarCharts.ts new file mode 100644 index 00000000000..b2aff926b03 --- /dev/null +++ b/db/migration/1735896576517-RemoveRelativeModeFromDiscreteBarCharts.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class RemoveRelativeModeFromDiscreteBarCharts1735896576517 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + -- sql + update chart_configs + set + patch = json_remove(patch, '$.stackMode'), + full = json_remove(full, '$.stackMode') + where + chartType = 'DiscreteBar' + and full ->> '$.stackMode' = 'relative'; + `) + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + public async down(): Promise {} +} diff --git a/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx b/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx index 3f79cc7bdec..e83be28e48d 100644 --- a/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx +++ b/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx @@ -37,11 +37,7 @@ import { GRAPHER_AREA_OPACITY_DEFAULT, GRAPHER_FONT_SCALE_12, } from "../core/GrapherConstants" -import { - HorizontalAxisComponent, - HorizontalAxisGridLines, - HorizontalAxisZeroLine, -} from "../axis/AxisViews" +import { HorizontalAxisZeroLine } from "../axis/AxisViews" import { NoDataModal } from "../noDataModal/NoDataModal" import { AxisConfig, AxisManager } from "../axis/AxisConfig" import { ColorSchemes } from "../color/ColorSchemes" @@ -305,7 +301,6 @@ export class DiscreteBarChart @computed private get innerBounds(): Bounds { return this.boundsWithoutColorLegend .padLeft(Math.max(this.seriesLegendWidth, this.leftValueLabelWidth)) - .padBottom(this.showHorizontalAxis ? this.yAxis.height : 0) .padRight(this.rightValueLabelWidth) } @@ -350,10 +345,6 @@ export class DiscreteBarChart return this.barPlacements.map((b) => b.width) } - @computed private get showHorizontalAxis(): boolean | undefined { - return this.manager.isRelativeMode - } - private d3Bars(): Selection< BaseType, unknown, @@ -504,7 +495,7 @@ export class DiscreteBarChart } renderChartArea(): React.ReactElement { - const { manager, boundsWithoutColorLegend, yAxis, innerBounds } = this + const { manager, yAxis, innerBounds } = this const axisLineWidth = manager.isStaticAndSmall ? GRAPHER_AXIS_LINE_WIDTH_THICK @@ -516,22 +507,6 @@ export class DiscreteBarChart {this.showColorLegend && ( )} - {this.showHorizontalAxis && ( - <> - - - - )} {!this.isLogScale && ( Date: Fri, 3 Jan 2025 15:15:36 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20(discrete=20bar)=20thin=20zero?= =?UTF-8?q?=20line=20(#4372)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../grapher/src/barCharts/DiscreteBarChart.tsx | 12 ++++++++++-- .../src/stackedCharts/StackedDiscreteBarChart.tsx | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx b/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx index e83be28e48d..4b0857a882a 100644 --- a/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx +++ b/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx @@ -498,8 +498,8 @@ export class DiscreteBarChart const { manager, yAxis, innerBounds } = this const axisLineWidth = manager.isStaticAndSmall - ? GRAPHER_AXIS_LINE_WIDTH_THICK - : GRAPHER_AXIS_LINE_WIDTH_DEFAULT + ? 0.5 * GRAPHER_AXIS_LINE_WIDTH_THICK + : 0.5 * GRAPHER_AXIS_LINE_WIDTH_DEFAULT return ( <> @@ -512,6 +512,14 @@ export class DiscreteBarChart horizontalAxis={yAxis} bounds={innerBounds} strokeWidth={axisLineWidth} + // if the chart doesn't have negative values, then we + // move the zero line a little to the left to avoid + // overlap with the bars + align={ + this.hasNegative + ? HorizontalAlign.center + : HorizontalAlign.right + } /> )} {this.renderBars()} diff --git a/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx b/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx index b298d2ae160..63317a0eae4 100644 --- a/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx +++ b/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx @@ -713,7 +713,7 @@ export class StackedDiscreteBarChart Date: Mon, 6 Jan 2025 11:48:05 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=A8=20(discrete=20bar)=20add=20more?= =?UTF-8?q?=20whitespace=20between=20bars=20(#4373)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/barCharts/DiscreteBarChart.tsx | 29 ++++++++++++++----- .../stackedCharts/StackedDiscreteBarChart.tsx | 27 ++++++++++++----- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx b/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx index 4b0857a882a..614f65a8ae2 100644 --- a/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx +++ b/packages/@ourworldindata/grapher/src/barCharts/DiscreteBarChart.tsx @@ -86,6 +86,8 @@ const DEFAULT_PROJECTED_DATA_COLOR_IN_LEGEND = "#787878" // if an entity name exceeds this width, we use the short name instead (if available) const SOFT_MAX_LABEL_WIDTH = 90 +const BAR_SPACING_FACTOR = 0.35 + export interface Label { valueString: string timeString: string @@ -312,18 +314,29 @@ export class DiscreteBarChart return this.series.length } - @computed private get barHeight(): number { - return (0.8 * this.innerBounds.height) / this.barCount + /** The total height of the series, i.e. the height of the bar + the white space around it */ + @computed private get seriesHeight(): number { + return this.innerBounds.height / this.barCount } - // useful if `this.barHeight` can't be used due to a cyclic dependency - // keep in mind though that this is not exactly the same as `this.barHeight` - @computed private get approximateBarHeight(): number { - return (0.8 * this.boundsWithoutColorLegend.height) / this.barCount + @computed private get barSpacing(): number { + return this.seriesHeight * BAR_SPACING_FACTOR } - @computed private get barSpacing(): number { - return this.innerBounds.height / this.barCount - this.barHeight + @computed private get barHeight(): number { + const totalWhiteSpace = this.barCount * this.barSpacing + return (this.innerBounds.height - totalWhiteSpace) / this.barCount + } + + // useful if `barHeight` can't be used due to a cyclic dependency + // keep in mind though that this is not exactly the same as `barHeight` + @computed private get approximateBarHeight(): number { + const { height } = this.boundsWithoutColorLegend + const approximateMaxBarHeight = height / this.barCount + const approximateBarSpacing = + approximateMaxBarHeight * BAR_SPACING_FACTOR + const totalWhiteSpace = this.barCount * approximateBarSpacing + return (height - totalWhiteSpace) / this.barCount } @computed private get barPlacements(): { x: number; width: number }[] { diff --git a/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx b/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx index 63317a0eae4..493cba5fca7 100644 --- a/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx +++ b/packages/@ourworldindata/grapher/src/stackedCharts/StackedDiscreteBarChart.tsx @@ -84,6 +84,8 @@ import { TextWrap } from "@ourworldindata/components" // if an entity name exceeds this width, we use the short name instead (if available) const SOFT_MAX_LABEL_WIDTH = 90 +const BAR_SPACING_FACTOR = 0.35 + const labelToBarPadding = 5 export interface StackedDiscreteBarChartManager extends ChartManager { @@ -470,18 +472,29 @@ export class StackedDiscreteBarChart })) } - // useful if `this.barHeight` can't be used due to a cyclic dependency - // keep in mind though that this is not exactly the same as `this.barHeight` - @computed private get approximateBarHeight(): number { - return (0.8 * this.boundsWithoutLegend.height) / this.barCount + /** The total height of the series, i.e. the height of the bar + the white space around it */ + @computed private get seriesHeight(): number { + return this.innerBounds.height / this.barCount + } + + @computed private get barSpacing(): number { + return this.seriesHeight * BAR_SPACING_FACTOR } @computed private get barHeight(): number { - return (0.8 * this.innerBounds.height) / this.barCount + const totalWhiteSpace = this.barCount * this.barSpacing + return (this.innerBounds.height - totalWhiteSpace) / this.barCount } - @computed private get barSpacing(): number { - return this.innerBounds.height / this.barCount - this.barHeight + // useful if `barHeight` can't be used due to a cyclic dependency + // keep in mind though that this is not exactly the same as `barHeight` + @computed private get approximateBarHeight(): number { + const { height } = this.boundsWithoutLegend + const approximateMaxBarHeight = height / this.barCount + const approximateBarSpacing = + approximateMaxBarHeight * BAR_SPACING_FACTOR + const totalWhiteSpace = this.barCount * approximateBarSpacing + return (height - totalWhiteSpace) / this.barCount } // legend props