Skip to content
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

tip title format #2074

Merged
merged 2 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/marks/tip.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Plot.rectY(olympians, Plot.binX({y: "sum"}, {x: "weight", y: (d) => d.sex === "m
```
:::

The order and formatting of channels in the tip can be customized with the **format** option <VersionBadge version="0.6.11" pr="1823" />, which accepts a key-value object mapping channel names to formats. Each [format](../features/formats.md) can be a string (for number or time formats), a function that receives the value as input and returns a string, true to use the default format, and null or false to suppress. The order of channels in the tip follows their order in the format object followed by any additional channels.
The order and formatting of channels in the tip can be customized with the **format** option <VersionBadge version="0.6.11" pr="1823" />, which accepts a key-value object mapping channel names to formats. Each [format](../features/formats.md) can be a string (for number or time formats), a function that receives the value as input and returns a string, true to use the default format, and null or false to suppress. The order of channels in the tip follows their order in the format object followed by any additional channels. When using the **title** channel, the **format** option may be specified as a string or a function; the given format will then apply to the **title** channel. <VersionBadge pr="2074" />

A channel’s label can be specified alongside its value as a {value, label} object; if a channel label is not specified, the associated scale’s label is used, if any; if there is no associated scale, or if the scale has no label, the channel name is used instead.

Expand Down
14 changes: 13 additions & 1 deletion src/marks/tip.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export interface TipOptions extends MarkOptions, TextStyles {
* is interpreted as a (UTC) time format for temporal channels, and otherwise
* a number format.
*/
format?: {[name in ChannelName]?: boolean | string | ((d: any, i: number) => string)};
format?: {[name in ChannelName]?: null | boolean | TipFormat} | TipFormat;

/** The image filter for the tip’s box; defaults to a drop shadow. */
pathFilter?: string;
Expand All @@ -86,6 +86,18 @@ export interface TipOptions extends MarkOptions, TextStyles {
textPadding?: number;
}

/**
* How to format channel values; one of:
*
* - a [d3-format][1] string for numeric scales
* - a [d3-time-format][2] string for temporal scales
* - a function passed a channel *value* and *index*, returning a string
*
* [1]: https://d3js.org/d3-time
* [2]: https://d3js.org/d3-time-format
*/
export type TipFormat = string | ((d: any, i: number) => string);

/**
* Returns a new tip mark for the given *data* and *options*.
*
Expand Down
10 changes: 5 additions & 5 deletions src/marks/tip.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class Tip extends Mark {
for (const key in defaults) if (key in this.channels) this[key] = defaults[key]; // apply default even if channel
this.splitLines = splitter(this);
this.clipLine = clipper(this);
this.format = {...format}; // defensive copy before mutate; also promote nullish to empty
this.format = typeof format === "string" || typeof format === "function" ? {title: format} : {...format}; // defensive copy before mutate; also promote nullish to empty
}
render(index, scales, values, dimensions, context) {
const mark = this;
Expand Down Expand Up @@ -120,10 +120,10 @@ export class Tip extends Mark {
// channels as name-value pairs.
let sources, format;
if ("title" in values) {
sources = values.channels;
sources = getSourceChannels.call(this, {title: values.channels.title}, scales);
format = formatTitle;
} else {
sources = getSourceChannels.call(this, values, scales);
sources = getSourceChannels.call(this, values.channels, scales);
format = formatChannels;
}

Expand Down Expand Up @@ -319,7 +319,7 @@ function getPath(anchor, m, r, width, height) {
}

// Note: mutates this.format!
function getSourceChannels({channels}, scales) {
function getSourceChannels(channels, scales) {
const sources = {};

// Promote x and y shorthand for paired channels (in order).
Expand Down Expand Up @@ -384,7 +384,7 @@ function maybeExpandPairedFormat(format, channels, key) {
}

function formatTitle(i, index, {title}) {
return formatDefault(title.value[i], i);
return this.format.title(title.value[i], i);
}

function* formatChannels(i, index, channels, scales, values) {
Expand Down
2 changes: 1 addition & 1 deletion src/scales.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ export interface ScaleOptions extends ScaleDefaults {
* [1]: https://d3js.org/d3-time
* [2]: https://d3js.org/d3-time-format
*/
tickFormat?: string | ((t: any, i: number) => any) | null;
tickFormat?: string | ((d: any, i: number) => any) | null;

/**
* The rotation angle of axis tick labels in degrees clocksize; defaults to 0.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions test/output/tipFormatTitleFormatFunction.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions test/output/tipFormatTitleFormatShorthand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 10 additions & 2 deletions test/plots/tip-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,16 @@ export async function tipFormatTitleExplicit() {
return tip({length: 1}, {title: [new Date("2010-01-01")]});
}

export async function tipFormatTitleIgnoreFormat() {
return tip({length: 1}, {title: [0], format: {title: ".2f"}});
export async function tipFormatTitleFormat() {
return tip({length: 1}, {title: [0.009], format: {title: ".2f"}});
}

export async function tipFormatTitleFormatFunction() {
return tip({length: 1}, {title: [0.019], format: (d) => d.toFixed(2)});
}

export async function tipFormatTitleFormatShorthand() {
return tip({length: 1}, {title: [0.029], format: ".2f"});
}

export async function tipFormatTitlePrimitive() {
Expand Down