-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Lens] New value labels config option for bar charts #81776
Changes from 17 commits
cb9777a
db0d21b
b5c55bb
95bfb64
8bae6e6
6f97d07
8a3f7ff
908160b
9a1173a
fe00a1b
75d9013
47b1046
1119bf7
6fcf5ad
a54028c
4a235c6
5facb32
7ca4e34
25522d5
f3d1ec1
36a6c3e
b46016c
b82da66
1f6f324
b96c188
d9562aa
036bbde
6bac751
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,10 @@ import { | |
GeometryValue, | ||
XYChartSeriesIdentifier, | ||
StackMode, | ||
RecursivePartial, | ||
Theme, | ||
VerticalAlignment, | ||
HorizontalAlignment, | ||
} from '@elastic/charts'; | ||
import { I18nProvider } from '@kbn/i18n/react'; | ||
import { | ||
|
@@ -125,6 +129,11 @@ export const xyChart: ExpressionFunctionDefinition< | |
defaultMessage: 'Define how missing values are treated', | ||
}), | ||
}, | ||
valueLabels: { | ||
flash1293 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
types: ['string'], | ||
options: ['hide', 'inside'], | ||
help: '', | ||
}, | ||
tickLabelsVisibilitySettings: { | ||
types: ['lens_xy_tickLabelsConfig'], | ||
help: i18n.translate('xpack.lens.xyChart.tickLabelsSettings.help', { | ||
|
@@ -206,6 +215,40 @@ export const getXyChartRenderer = (dependencies: { | |
}, | ||
}); | ||
|
||
function mergeThemeWithValueLabelsStyling( | ||
theme: RecursivePartial<Theme>, | ||
valuesLabelMode: string = 'hide', | ||
isHorizontal: boolean | ||
) { | ||
const VALUE_LABELS_MAX_FONTSIZE = 15; | ||
const VALUE_LABELS_MIN_FONTSIZE = 10; | ||
const VALUE_LABELS_VERTICAL_OFFSET = -10; | ||
const VALUE_LABELS_HORIZONTAL_OFFSET = 10; | ||
|
||
if (valuesLabelMode === 'hide') { | ||
return theme; | ||
} | ||
return { | ||
...theme, | ||
...{ | ||
barSeriesStyle: { | ||
...theme.barSeriesStyle, | ||
displayValue: { | ||
fontSize: { min: VALUE_LABELS_MIN_FONTSIZE, max: VALUE_LABELS_MAX_FONTSIZE }, | ||
fill: { textInverted: true, textBorder: true }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm honestly finding the text to be more readable without the text border. I know we thought it was important earlier, but I'm rethinking this. Want to try without it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've ran some tests here with current styling, no border or increased border size. Current borderThicker borderNo borderPersonally I find the thicker version easier to read compared to both current state and no border at all (exp. with bars with lower contrast with the text). But I see no big readability gain for few bars or vertical charts with many bars. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for a PR on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was mostly suggesting it because I think having good defaults is important, and this looks like the kind of thing we would want to set by default for elastic-charts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll open an issue on the repo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. elastic-chart issue: elastic/elastic-charts#886 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are other considerations we should consider before baking this into Elastic Charts. I've commented separately on that issue. |
||
alignment: isHorizontal | ||
? { | ||
vertical: VerticalAlignment.Middle, | ||
} | ||
: { horizontal: HorizontalAlignment.Center }, | ||
offsetX: isHorizontal ? VALUE_LABELS_HORIZONTAL_OFFSET : 0, | ||
offsetY: isHorizontal ? 0 : VALUE_LABELS_VERTICAL_OFFSET, | ||
}, | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
function getIconForSeriesType(seriesType: SeriesType): IconType { | ||
return visualizationTypes.find((c) => c.id === seriesType)!.icon || 'empty'; | ||
} | ||
|
@@ -245,7 +288,7 @@ export function XYChart({ | |
onClickValue, | ||
onSelectRange, | ||
}: XYChartRenderProps) { | ||
const { legend, layers, fittingFunction, gridlinesVisibilitySettings } = args; | ||
const { legend, layers, fittingFunction, gridlinesVisibilitySettings, valueLabels } = args; | ||
const chartTheme = chartsThemeService.useChartsTheme(); | ||
const chartBaseTheme = chartsThemeService.useChartsBaseTheme(); | ||
|
||
|
@@ -387,6 +430,16 @@ export function XYChart({ | |
return style; | ||
}; | ||
|
||
const shouldShowValueLabels = | ||
// No stacked bar charts | ||
filteredLayers.every((layer) => !layer.seriesType.includes('stacked')) && | ||
// No histogram charts | ||
!isHistogramViz; | ||
|
||
const baseThemeWithMaybeValueLabels = !shouldShowValueLabels | ||
? chartTheme | ||
: mergeThemeWithValueLabelsStyling(chartTheme, valueLabels || 'hide', shouldRotate); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think so. I was thinking about backward compatibility here, but probably the expression evaluation should ensure that the value is set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, expressions are regenerated every time, so it's safe to assume it's available here because of the default value in |
||
|
||
return ( | ||
<Chart> | ||
<Settings | ||
|
@@ -397,7 +450,7 @@ export function XYChart({ | |
} | ||
legendPosition={legend.position} | ||
showLegendExtra={false} | ||
theme={chartTheme} | ||
theme={baseThemeWithMaybeValueLabels} | ||
baseTheme={chartBaseTheme} | ||
tooltip={{ | ||
headerFormatter: (d) => safeXAccessorLabelRenderer(d.value), | ||
|
@@ -601,6 +654,10 @@ export function XYChart({ | |
}); | ||
} | ||
|
||
const yAxis = yAxesConfiguration.find((axisConfiguration) => | ||
axisConfiguration.series.find((currentSeries) => currentSeries.accessor === accessor) | ||
); | ||
|
||
const seriesProps: SeriesSpec = { | ||
splitSeriesAccessors: splitAccessor ? [splitAccessor] : [], | ||
stackAccessors: seriesType.includes('stacked') ? [xAccessor as string] : [], | ||
|
@@ -611,9 +668,7 @@ export function XYChart({ | |
xScaleType: xAccessor ? xScaleType : 'ordinal', | ||
yScaleType, | ||
color: () => getSeriesColor(layer, accessor), | ||
groupId: yAxesConfiguration.find((axisConfiguration) => | ||
axisConfiguration.series.find((currentSeries) => currentSeries.accessor === accessor) | ||
)?.groupId, | ||
groupId: yAxis?.groupId, | ||
enableHistogramMode: | ||
isHistogram && | ||
(seriesType.includes('stacked') || !splitAccessor) && | ||
|
@@ -685,7 +740,19 @@ export function XYChart({ | |
case 'bar_horizontal': | ||
case 'bar_horizontal_stacked': | ||
case 'bar_horizontal_percentage_stacked': | ||
return <BarSeries key={index} {...seriesProps} />; | ||
const valueLabelsSettings = { | ||
displayValueSettings: { | ||
// This format double fixes two issues in elastic-chart | ||
// * when rotating the chart, the formatter is not correctly picked | ||
// * in some scenarios value labels are not strings, and this breaks the elastic-chart lib | ||
valueFormatter: (d: unknown) => yAxis?.formatter?.convert(d) || '', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this an elastic-charts bug? If yes we should open an issue for it. Also, it seems like this behavior is complex enough to cover it with a unit test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The latter bug (non-string value handling) has been reported already. The former needs to be reported. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha, thanks for confirming. LGTM if it's tested and reported. |
||
showValueLabel: shouldShowValueLabels && valueLabels !== 'hide', | ||
isAlternatingValueLabel: false, | ||
isValueContainedInElement: true, | ||
hideClippedValue: true, | ||
}, | ||
}; | ||
return <BarSeries key={index} {...seriesProps} {...valueLabelsSettings} />; | ||
case 'area_stacked': | ||
case 'area_percentage_stacked': | ||
return ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this workaround - maybe @MichaelMarcialis has an idea how to improve this.
For context: To show why an option in the popover is disabled, a tooltip icon is added, but it's slightly too large to fit into the same row for the standard width of these popovers, so it has to get enlarged:
The only thing I can think of is to put the tooltip on the disabled form element itself instead of an additional icon, then the popover is wide enough and we don't need a separate class. The downside is the missing affordance - does the user know they have to hover the form element to get a reason for it being disabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just realized we have something like this in lens already - it looks like this for the colors:
No strong opinion which route to go but we should make sure to do it the same way in both places
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this was the reason of the conditional icon state. I'll update the PR with a better alignment 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, all. If I'm understanding correctly, and the "missing values" field is one that will always be disabled when any visualization other than line and area are selected, my first instinct would be to conditionally remove that form field altogether in those instances. I'm not a fan of showing users disabled form fields where users have little-to-no ability to re-enable (assuming the currently selected visualization type is the desired one).
For example, if I know I want a bar chart for my visualization, why even present me with a field that I'll never be able to interact with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated PR to hide the field when the chart is not of type area or line.
Also improved icon alignment as in the picture above for
Series color
.