Skip to content

Commit

Permalink
feat: allow custom tooltip formatting (#8883)
Browse files Browse the repository at this point in the history
Co-authored-by: GitHub Actions Bot <vega-actions-bot@users.noreply.github.com>
Co-authored-by: Kanit Wongsuphasawat <kanitw@gmail.com>
  • Loading branch information
3 people committed May 5, 2023
1 parent b29fa64 commit e7b45b8
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 45 deletions.
34 changes: 34 additions & 0 deletions build/vega-lite-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7765,6 +7765,10 @@
"$ref": "#/definitions/TitleConfig",
"description": "Title configuration, which determines default properties for all [titles](https://vega.github.io/vega-lite/docs/title.html). For a full list of title configuration options, please see the [corresponding section of the title documentation](https://vega.github.io/vega-lite/docs/title.html#config)."
},
"tooltipFormat": {
"$ref": "#/definitions/FormatConfig",
"description": "Define [custom format configuration](https://vega.github.io/vega-lite/docs/config.html#format) for tooltips. If unspecified, default format config will be applied."
},
"trail": {
"$ref": "#/definitions/LineConfig",
"description": "Trail-Specific Config"
Expand Down Expand Up @@ -10851,6 +10855,36 @@
"number"
]
},
"FormatConfig": {
"additionalProperties": false,
"properties": {
"normalizedNumberFormat": {
"description": "If normalizedNumberFormatType is not specified, D3 number format for axis labels, text marks, and tooltips of normalized stacked fields (fields with `stack: \"normalize\"`). For example `\"s\"` for SI units. Use [D3's number format pattern](https://github.com/d3/d3-format#locale_format).\n\nIf `config.normalizedNumberFormatType` is specified and `config.customFormatTypes` is `true`, this value will be passed as `format` alongside `datum.value` to the `config.numberFormatType` function. __Default value:__ `%`",
"type": "string"
},
"normalizedNumberFormatType": {
"description": "[Custom format type](https://vega.github.io/vega-lite/docs/config.html#custom-format-type) for `config.normalizedNumberFormat`.\n\n__Default value:__ `undefined` -- This is equilvalent to call D3-format, which is exposed as [`format` in Vega-Expression](https://vega.github.io/vega/docs/expressions/#format). __Note:__ You must also set `customFormatTypes` to `true` to use this feature.",
"type": "string"
},
"numberFormat": {
"description": "If numberFormatType is not specified, D3 number format for guide labels, text marks, and tooltips of non-normalized fields (fields *without* `stack: \"normalize\"`). For example `\"s\"` for SI units. Use [D3's number format pattern](https://github.com/d3/d3-format#locale_format).\n\nIf `config.numberFormatType` is specified and `config.customFormatTypes` is `true`, this value will be passed as `format` alongside `datum.value` to the `config.numberFormatType` function.",
"type": "string"
},
"numberFormatType": {
"description": "[Custom format type](https://vega.github.io/vega-lite/docs/config.html#custom-format-type) for `config.numberFormat`.\n\n__Default value:__ `undefined` -- This is equilvalent to call D3-format, which is exposed as [`format` in Vega-Expression](https://vega.github.io/vega/docs/expressions/#format). __Note:__ You must also set `customFormatTypes` to `true` to use this feature.",
"type": "string"
},
"timeFormat": {
"description": "Default time format for raw time values (without time units) in text marks, legend labels and header labels.\n\n__Default value:__ `\"%b %d, %Y\"` __Note:__ Axes automatically determine the format for each label automatically so this config does not affect axes.",
"type": "string"
},
"timeFormatType": {
"description": "[Custom format type](https://vega.github.io/vega-lite/docs/config.html#custom-format-type) for `config.timeFormat`.\n\n__Default value:__ `undefined` -- This is equilvalent to call D3-time-format, which is exposed as [`timeFormat` in Vega-Expression](https://vega.github.io/vega/docs/expressions/#timeFormat). __Note:__ You must also set `customFormatTypes` to `true` and there must *not* be a `timeUnit` defined to use this feature.",
"type": "string"
}
},
"type": "object"
},
"Generator": {
"anyOf": [
{
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/compiled/config_numberFormatType_tooltip.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
126 changes: 126 additions & 0 deletions examples/compiled/config_numberFormatType_tooltip.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "Testing global number formatting config",
"background": "white",
"padding": 5,
"width": 150,
"height": 150,
"style": "cell",
"data": [
{
"name": "source_0",
"url": "data/cars.json",
"format": {"type": "json", "parse": {"Year": "date"}},
"transform": [
{
"type": "aggregate",
"groupby": ["Year"],
"ops": ["average"],
"fields": ["Miles_per_Gallon"],
"as": ["average_Miles_per_Gallon"]
},
{
"type": "filter",
"expr": "(isDate(datum[\"Year\"]) || (isValid(datum[\"Year\"]) && isFinite(+datum[\"Year\"]))) && isValid(datum[\"average_Miles_per_Gallon\"]) && isFinite(+datum[\"average_Miles_per_Gallon\"])"
}
]
}
],
"marks": [
{
"name": "marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "source_0"},
"encode": {
"update": {
"tooltip": {
"signal": "{\"Year\": timeFormat(datum[\"Year\"], '%b %d, %Y'), \"Average of Miles_per_Gallon\": format(datum[\"average_Miles_per_Gallon\"], \".8f\")}"
},
"fill": {"value": "#4c78a8"},
"ariaRoleDescription": {"value": "bar"},
"description": {
"signal": "\"Year: \" + (timeFormat(datum[\"Year\"], '%b %d, %Y')) + \"; Average of Miles_per_Gallon: \" + (format(datum[\"average_Miles_per_Gallon\"], \".8f\"))"
},
"xc": {"scale": "x", "field": "Year"},
"width": {"value": 5},
"y": {"scale": "y", "field": "average_Miles_per_Gallon"},
"y2": {"scale": "y", "value": 0}
}
}
}
],
"scales": [
{
"name": "x",
"type": "time",
"domain": {"data": "source_0", "field": "Year"},
"range": [0, {"signal": "width"}],
"padding": 5
},
{
"name": "y",
"type": "linear",
"domain": {"data": "source_0", "field": "average_Miles_per_Gallon"},
"range": [{"signal": "height"}, 0],
"nice": true,
"zero": true
}
],
"axes": [
{
"scale": "x",
"orient": "bottom",
"gridScale": "y",
"grid": true,
"tickCount": {"signal": "ceil(width/40)"},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"gridScale": "x",
"grid": true,
"tickCount": {"signal": "ceil(height/40)"},
"tickMinStep": 1,
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "Year",
"labelFlush": true,
"labelOverlap": true,
"tickCount": {"signal": "ceil(width/40)"},
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Average of Miles_per_Gallon",
"format": "d",
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"tickMinStep": 1,
"zindex": 0
}
],
"config": {
"tooltipFormat": {"numberFormat": ".8f"},
"customFormatTypes": true
}
}
19 changes: 19 additions & 0 deletions examples/specs/config_numberFormatType_tooltip.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "Testing global number formatting config",
"width": 150,
"height": 150,
"data": {"url": "data/cars.json"},
"mark": {"type": "bar", "tooltip": true},
"encoding": {
"x": {"field": "Year", "type": "temporal"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative", "aggregate": "average"}
},
"config": {
"tooltipFormat": {
"numberFormat": ".8f"
},
"numberFormat": "d",
"customFormatTypes": true
}
}
14 changes: 10 additions & 4 deletions site/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ The rest of this page outlines different types of config properties:

A Vega-Lite `config` object can have the following top-level properties:

{% include table.html props="autosize,background,countTitle,fieldTitle,font,lineBreak,padding" source="Config" %}
{% include table.html props="autosize,background,countTitle,fieldTitle,font,lineBreak,padding,tooltipFormat" source="Config" %}

{:#format}

## Format Configuration

These config properties define the default number and time formats for text marks as well as axes, headers, and legends:
These config properties define the default number and time formats for text marks as well as axes, headers, tooltip, and legends:

{% include table.html props="numberFormat,numberFormatType,normalizedNumberFormat,normalizedNumberFormatType,timeFormat,timeFormatType,customFormatTypes" source="Config" %}

Expand All @@ -69,7 +69,7 @@ vega.expressionFunction('customFormatA', function(datum, params) {
});
```

2. Setting the `customFormatTypes` config to `true`.
(2) Setting the `customFormatTypes` config to `true`.

```js
{
Expand All @@ -78,7 +78,7 @@ vega.expressionFunction('customFormatA', function(datum, params) {
}
```

3. You can then use this custom format function with `format` and `formatType` properties in text encodings and guides (axis/legend/header).
(3) You can then use this custom format function with `format` and `formatType` properties in text encodings and guides (axis/legend/header).

```js
{
Expand All @@ -87,6 +87,12 @@ vega.expressionFunction('customFormatA', function(datum, params) {
}
```

### Customize Formatter for Tooltips only

Since tooltips have more screen estate and less chance of collisions, sometimes it is desirable to have a truncated format in a visualization, with a longer format in the tooltip. For example, in the visualization below, we want the y-axis to have the format `d` so it does not have a decimal point, so as not to have incredibly long labels, but on the tooltip it has the longer `.8f`. To achieve this specificity, one can add a `tooltipFormat` prop to their config that conforms to the [FormatConfig](#format) type.

<span class="vl-example" data-name="config_numberFormatType_tooltip"></span>

{:#axis-config}

## Guide Configurations
Expand Down
9 changes: 5 additions & 4 deletions src/compile/mark/encode/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export function tooltipData(
config: Config,
{reactiveGeom}: {reactiveGeom?: boolean} = {}
) {
const formatConfig = {...config, ...config.tooltipFormat};
const toSkip = {};
const expr = reactiveGeom ? 'datum.datum' : 'datum';
const tuples: {channel: Channel; key: string; value: string}[] = [];
Expand All @@ -86,7 +87,7 @@ export function tooltipData(
type: (encoding[mainChannel] as TypedFieldDef<any>).type // for secondary field def, copy type from main channel
};

const title = fieldDef.title || defaultTitle(fieldDef, config);
const title = fieldDef.title || defaultTitle(fieldDef, formatConfig);
const key = array(title).join(', ');

let value: string;
Expand All @@ -99,7 +100,7 @@ export function tooltipData(
const startField = vgField(fieldDef, {expr});
const endField = vgField(fieldDef2, {expr});
const {format, formatType} = getFormatMixins(fieldDef);
value = binFormatExpression(startField, endField, format, formatType, config);
value = binFormatExpression(startField, endField, format, formatType, formatConfig);
toSkip[channel2] = true;
}
}
Expand All @@ -116,12 +117,12 @@ export function tooltipData(
format,
formatType,
expr,
config,
config: formatConfig,
normalizeStack: true
}).signal;
}

value ??= textRef(fieldDef, config, expr).signal;
value ??= textRef(fieldDef, formatConfig, expr).signal;

tuples.push({channel, key, value});
}
Expand Down
Loading

0 comments on commit e7b45b8

Please sign in to comment.