Skip to content

Basic JSDoc types - Plot.plot and all Marks #1055

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

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 22 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
17 changes: 0 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2346,7 +2346,6 @@ Plot.rect(athletes, Plot.bin({fillOpacity: "count"}, {x: "weight", y: "height"})
Bins on *x* and *y*. Also groups on the first channel of *z*, *fill*, or
*stroke*, if any.


Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<!-- jsdoc binX -->

#### Plot.binX(*outputs*, *options*)
Expand All @@ -2358,7 +2357,6 @@ Plot.rectY(athletes, Plot.binX({y: "count"}, {x: "weight"}))
Bins on *x*. Also groups on *y* and the first channel of *z*, *fill*, or
*stroke*, if any.


<!-- jsdoc binY -->

#### Plot.binY(*outputs*, *options*)
Expand Down Expand Up @@ -2456,7 +2454,6 @@ Plot.group({fill: "count"}, {x: "island", y: "species"})
Groups on *x*, *y*, and the first channel of *z*, *fill*, or *stroke*, if
any.


<!-- jsdoc groupX -->

#### Plot.groupX(*outputs*, *options*)
Expand All @@ -2467,7 +2464,6 @@ Plot.groupX({y: "sum"}, {x: "species", y: "body_mass_g"})

Groups on *x* and the first channel of *z*, *fill*, or *stroke*, if any.


<!-- jsdoc groupY -->

#### Plot.groupY(*outputs*, *options*)
Expand All @@ -2478,7 +2474,6 @@ Plot.groupY({x: "sum"}, {y: "species", x: "body_mass_g"})

Groups on *y* and the first channel of *z*, *fill*, or *stroke*, if any.


<!-- jsdoc groupZ -->

#### Plot.groupZ(*outputs*, *options*)
Expand All @@ -2491,7 +2486,6 @@ Groups on the first channel of *z*, *fill*, or *stroke*, if any. If none of
*z*, *fill*, or *stroke* are channels, then all data (within each facet) is
placed into a single group.


<!-- jsdocEnd -->

### Map
Expand Down Expand Up @@ -2569,7 +2563,6 @@ each channel declared in the specified *outputs* object, applies the
corresponding map method. Each channel in *outputs* must have a corresponding
input channel in *options*.


<!-- jsdoc mapX -->

#### Plot.mapX(*map*, *options*)
Expand All @@ -2581,7 +2574,6 @@ Plot.mapX("cumsum", {x: d3.randomNormal()})
Equivalent to Plot.map({x: *map*, x1: *map*, x2: *map*}, *options*), but
ignores any of **x**, **x1**, and **x2** not present in *options*.


<!-- jsdoc mapY -->

#### Plot.mapY(*map*, *options*)
Expand All @@ -2593,7 +2585,6 @@ Plot.mapY("cumsum", {y: d3.randomNormal()})
Equivalent to Plot.map({y: *map*, y1: *map*, y2: *map*}, *options*), but
ignores any of **y**, **y1**, and **y2** not present in *options*.


<!-- jsdoc normalize -->

#### Plot.normalize(*basis*)
Expand Down Expand Up @@ -2803,7 +2794,6 @@ resulting in a count of the data points. The stack options (*offset*,
*order*, and *reverse*) may be specified as part of the *options* object, if
the only argument, or as a separate *stack* options argument.


<!-- jsdoc stackY1 -->

#### Plot.stackY1(*stack*, *options*)
Expand All @@ -2817,7 +2807,6 @@ Equivalent to
except that the **y1** channel is returned as the **y** channel. This can be
used, for example, to draw a line at the bottom of each stacked area.


<!-- jsdoc stackY2 ->

#### Plot.stackY2(*stack*, *options*)
Expand All @@ -2831,7 +2820,6 @@ Equivalent to
except that the **y2** channel is returned as the **y** channel. This can be
used, for example, to draw a line at the top of each stacked area.


<!-- jsdoc stackX -->

#### Plot.stackX(*stack*, *options*)
Expand All @@ -2843,7 +2831,6 @@ Plot.stackX({y: "year", x: "revenue", z: "format", fill: "group"})
See Plot.stackY, but with *x* as the input value channel, *y* as the stack
index, *x1*, *x2* and *x* as the output channels.


<!-- jsdoc stackX1 -->

#### Plot.stackX1(*stack*, *options*)
Expand All @@ -2857,7 +2844,6 @@ Equivalent to
except that the **x1** channel is returned as the **x** channel. This can be
used, for example, to draw a line at the left edge of each stacked area.


<!-- jsdoc stackX2 -->

#### Plot.stackX2(*stack*, *options*)
Expand All @@ -2871,7 +2857,6 @@ Equivalent to
except that the **x2** channel is returned as the **x** channel. This can be
used, for example, to draw a line at the right edge of each stacked area.


<!-- jsdocEnd -->

### Tree
Expand Down Expand Up @@ -3140,7 +3125,6 @@ Given marks arranged along the *x* axis, the dodgeY transform piles them
vertically by defining a *y* position channel that avoids overlapping. The
*x* position channel is unchanged.


<!-- jsdoc dodgeX -->

#### Plot.dodgeX(*dodgeOptions*, *options*)
Expand All @@ -3153,7 +3137,6 @@ Equivalent to Plot.dodgeY, but piling horizontally, creating a new *x*
position channel that avoids overlapping. The *y* position channel is
unchanged.


<!-- jsdocEnd -->

### Hexbin
Expand Down
30 changes: 18 additions & 12 deletions scripts/jsdoc-to-readme.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {readFileSync, writeFileSync} from "fs";
import type {ExportedDeclarations, FunctionDeclaration} from "ts-morph";
import type {ExportedDeclarations, FunctionDeclaration, JSDoc} from "ts-morph";
import {Project} from "ts-morph";

/**
Expand Down Expand Up @@ -53,7 +53,7 @@ function injectJsDoc(readme: string) {
if (!declaration) throw new Error(`${name} is not exported by src/index`);
parts.push(getJsDocs(name, declaration, prefix));
parts.push("");
replacement = parts.join("\n");
replacement = pad(parts.join("\n"));
}
if (!insideReplacement || isReplacementDelimiter) output.push(line);
if (replacement) output.push(replacement);
Expand All @@ -66,14 +66,24 @@ function getJsDocs(name: string, declaration: ExportedDeclarations, prefix = "##
return getJsDocsForFunction(name, declaration, prefix);
}
if ("getJsDocs" in declaration) {
return `${prefix} Plot.${name}\n${declaration
.getJsDocs()
.map((doc) => makeRelativeUrls(doc.getDescription()))
.join("\n\n")}`;
return `${prefix} Plot.${name}\n${transformDocs(declaration.getJsDocs())}`;
}
return `JSDoc extraction for ${declaration.getKindName()} not yet implemented.`;
}

function transformDocs(docs: JSDoc[]): string {
return makeRelativeUrls(pad(docs.map((doc) => doc.getDescription()).join("\n\n")));
}

function makeRelativeUrls(description: string) {
return description.replace(new RegExp("https://github.com/observablehq/plot/blob/main/README.md#", "g"), "#");
}

// Standardize on one leading and trailing new line for each replacement.
function pad(s: string) {
return `\n${s.trim()}\n`;
}

function getJsDocsForFunction(name: string, declaration: FunctionDeclaration, prefix = "####") {
const parameters = declaration.getParameters();
const title = `${prefix} Plot.${name}(${parameters
Expand All @@ -82,7 +92,7 @@ function getJsDocsForFunction(name: string, declaration: FunctionDeclaration, pr
const parts = [title];
const docs = declaration.getJsDocs();
if (docs.length) {
parts.push(docs.map((doc) => makeRelativeUrls(doc.getDescription())).join("\n\n"));
parts.push(transformDocs(docs));
return parts.join("\n");
}
// If we didn't find docs on the implementation, it's probably on one of the
Expand All @@ -91,17 +101,13 @@ function getJsDocsForFunction(name: string, declaration: FunctionDeclaration, pr
for (const overload of overloads) {
const docs = overload.getJsDocs();
if (!docs.length) continue;
parts.push(docs.map((doc) => makeRelativeUrls(doc.getDescription())).join("\n\n"));
parts.push(transformDocs(docs));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the changes to jsdoc-to-readme are about trimming the JSDoc so extra leading and trailing new lines don't end up in the README file. For some reason, when you have a JSDoc in a file that is just importing types, TypeScript returns empty lines for that JSDoc. This is benign but will result in a slightly cleaner README file.

return parts.join("\n");
}

return "No JSDocs found.";
}

function makeRelativeUrls(description: string) {
return description.replace(new RegExp("https://github.com/observablehq/plot/blob/main/README.md#", "g"), "#");
}

const check = process.argv[process.argv.length - 1] === "--check";
const original = readFileSync(readmePath, {encoding: "utf-8"});
const output = injectJsDoc(original);
Expand Down
19 changes: 16 additions & 3 deletions src/marks/area.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* @typedef {import("../types.js").Data} Data
* @typedef {import("../types.js").MarkOptions} MarkOptions
* @typedef {import("../types.js").StackOptions} StackOptions
* @typedef {MarkOptions & StackOptions | undefined} Options
*/

import {area as shapeArea} from "d3";
import {create} from "../context.js";
import {Curve} from "../curve.js";
Expand Down Expand Up @@ -85,8 +92,10 @@ export class Area extends Mark {
* [Plot.areaX](https://github.com/observablehq/plot/blob/main/README.md#plotareaxdata-options)
* is used in the vertical orientation where the baseline and topline share *y*
* values.
* @param {Data} data
* @param {Options} options
*/
export function area(data, options) {
export function area(data, options = undefined) {
if (options === undefined) return areaY(data, {x: first, y: second});
return new Area(data, options);
}
Expand Down Expand Up @@ -121,8 +130,10 @@ export function area(data, options) {
* The **interval** option is recommended to “regularize” sampled data; for
* example, if your data represents timestamped temperature measurements and you
* expect one sample per day, use d3.utcDay as the interval.
* @param {Data} data
* @param {Options} options
*/
export function areaX(data, options) {
export function areaX(data, options = undefined) {
const {y = indexOf, ...rest} = maybeDenseIntervalY(options);
return new Area(data, maybeStackX(maybeIdentityX({...rest, y1: y, y2: undefined})));
}
Expand Down Expand Up @@ -157,8 +168,10 @@ export function areaX(data, options) {
* The **interval** option is recommended to “regularize” sampled data; for
* example, if your data represents timestamped temperature measurements and you
* expect one sample per day, use d3.utcDay as the interval.
* @param {Data} data
* @param {Options} options
*/
export function areaY(data, options) {
export function areaY(data, options = undefined) {
const {x = indexOf, ...rest} = maybeDenseIntervalX(options);
return new Area(data, maybeStackY(maybeIdentityY({...rest, x1: x, x2: undefined})));
}
9 changes: 9 additions & 0 deletions src/marks/arrow.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* @typedef {import("../types.js").ArrowOptions} ArrowOptions
* @typedef {import("../types.js").Data} Data
* @typedef {import("../types.js").MarkOptions} MarkOptions
* @typedef {ArrowOptions & MarkOptions | undefined} Options
*/

import {create} from "../context.js";
import {radians} from "../math.js";
import {constant} from "../options.js";
Expand Down Expand Up @@ -182,6 +189,8 @@ function circleCircleIntersect([ax, ay, ar], [bx, by, br], sign) {
* ```
*
* Returns a new arrow with the given *data* and *options*.
* @param {Data} data
* @param {Options} options
*/
export function arrow(data, options = {}) {
let {x, x1, x2, y, y1, y2, ...remainingOptions} = options;
Expand Down
12 changes: 12 additions & 0 deletions src/marks/bar.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/**
* @typedef {import("../types.js").Data} Data
* @typedef {import("../types.js").RectOptions} RectOptions
* @typedef {import("../types.js").MarkOptions} MarkOptions
* @typedef {import("../types.js").StackOptions} StackOptions
* @typedef {MarkOptions & StackOptions & RectOptions | undefined} Options
*/

import {create} from "../context.js";
import {identity, indexOf, number} from "../options.js";
import {Mark} from "../plot.js";
Expand Down Expand Up @@ -163,6 +171,8 @@ export class BarY extends AbstractBar {
*
* If the **y** channel is not specified, the bar will span the full vertical
* extent of the plot (or facet).
* @param {Data} data
* @param {Options} options
*/
export function barX(data, options = {y: indexOf, x2: identity}) {
return new BarX(data, maybeStackX(maybeIntervalX(maybeIdentityX(options))));
Expand Down Expand Up @@ -203,6 +213,8 @@ export function barX(data, options = {y: indexOf, x2: identity}) {
*
* If the **x** channel is not specified, the bar will span the full horizontal
* extent of the plot (or facet).
* @param {Data} data
* @param {Options} options
*/
export function barY(data, options = {x: indexOf, y2: identity}) {
return new BarY(data, maybeStackY(maybeIntervalY(maybeIdentityY(options))));
Expand Down
9 changes: 9 additions & 0 deletions src/marks/box.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* @typedef {import("../types.js").Data} Data
* @typedef {import("../types.js").MarkOptions | undefined} Options
*/

import {min, max, quantile} from "d3";
import {marks} from "../plot.js";
import {groupX, groupY, groupZ} from "../transforms/group.js";
Expand All @@ -16,6 +21,8 @@ import {tickX, tickY} from "./tick.js";
* defaults to the identity function, as when *data* is an array of numbers. If
* the **y** option is not specified, it defaults to null; if the **y** option
* is specified, it should represent an ordinal (discrete) value.
* @param {Data} data
* @param {Options} options
*/
export function boxX(data, options = {}) {
// Returns a composite mark for producing a horizontal box plot, applying the
Expand Down Expand Up @@ -49,6 +56,8 @@ export function boxX(data, options = {}) {
* defaults to the identity function, as when *data* is an array of numbers. If
* the **x** option is not specified, it defaults to null; if the **x** option
* is specified, it should represent an ordinal (discrete) value.
* @param {Data} data
* @param {Options} options
*/
export function boxY(data, options = {}) {
// Returns a composite mark for producing a vertical box plot, applying the
Expand Down
13 changes: 13 additions & 0 deletions src/marks/cell.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* @typedef {import("../types.js").Data} Data
* @typedef {import("../types.js").MarkOptions} MarkOptions
* @typedef {import("../types.js").RectOptions} RectOptions
* @typedef {RectOptions & MarkOptions | undefined} Options
*/

import {identity, indexOf, maybeColorChannel, maybeTuple} from "../options.js";
import {applyTransform} from "../style.js";
import {AbstractBar} from "./bar.js";
Expand Down Expand Up @@ -33,6 +40,8 @@ export class Cell extends AbstractBar {
* nor **y** options are specified, *data* is assumed to be an array of pairs
* [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*,
* *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …].
* @param {Data} data
* @param {Options} options
*/
export function cell(data, options = {}) {
let {x, y, ...remainingOptions} = options;
Expand All @@ -51,6 +60,8 @@ export function cell(data, options = {}) {
* …], and if the **fill** option is not specified and **stroke** is not a
* channel, the fill defaults to the identity function and assumes that *data* =
* [*x₀*, *x₁*, *x₂*, …].
* @param {Data} data
* @param {Options} options
*/
export function cellX(data, options = {}) {
let {x = indexOf, fill, stroke, ...remainingOptions} = options;
Expand All @@ -69,6 +80,8 @@ export function cellX(data, options = {}) {
* …], and if the **fill** option is not specified and **stroke** is not a
* channel, the fill defaults to the identity function and assumes that *data* =
* [*y₀*, *y₁*, *y₂*, …].
* @param {Data} data
* @param {Options} options
*/
export function cellY(data, options = {}) {
let {y = indexOf, fill, stroke, ...remainingOptions} = options;
Expand Down
Loading