Skip to content

Add support for projections to the standalone Plot.scale function#2427

Open
Fil wants to merge 3 commits intomainfrom
fil/scale-projection
Open

Add support for projections to the standalone Plot.scale function#2427
Fil wants to merge 3 commits intomainfrom
fil/scale-projection

Conversation

@Fil
Copy link
Copy Markdown
Contributor

@Fil Fil commented Apr 13, 2026

e.g. Plot.scale({projection: {type: "mercator", width, domain: …}}).

When merged, we must add this to the changelog PR #2426:

The standalone [Plot.scale](https://observablehq.com/plot/features/scales#scale) function now also supports projections.

```js
const projection = Plot.scale({projection: {type: "mercator"}});
projection.apply([-1.55, 47.22]) // [316.7, 224.2]

const plot = Plot.plot({projection, marks: [Plot.sphere()]});
```

Fil added 2 commits April 13, 2026 17:26
_e.g._ Plot.scale({projection: {type: "mercator", width, domain: …}}).
@Fil Fil requested a review from mbostock April 13, 2026 15:46
const plot2 = Plot.plot({...options2, color: plot1.scale("color")});
```

Plot.scale also supports projections. <VersionBadge version="0.6.18" /> The returned projection object exposes *apply* and *invert* methods for converting between geographic and pixel coordinates, and can be passed as the **projection** option of another plot.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Plot.scale also supports projections. <VersionBadge version="0.6.18" /> The returned projection object exposes *apply* and *invert* methods for converting between geographic and pixel coordinates, and can be passed as the **projection** option of another plot.
Plot.scale also supports projections. <VersionBadge pr="2427" /> The returned projection object exposes *apply* and *invert* methods for converting between geographic and pixel coordinates, and can be passed as the **projection** option of another plot.

Let’s not get ahead of ourselves. 🙂

@@ -673,3 +674,4 @@ export interface Scale extends ScaleOptions {
* ```
*/
export function scale(options?: {[name in ScaleName]?: ScaleOptions}): Scale;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is options really optional here?

Suggested change
export function scale(options?: {[name in ScaleName]?: ScaleOptions}): Scale;
export function scale(options: {[name in ScaleName]?: ScaleOptions}): Scale;

return scale;
}

function scaleProjection({
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be called exposeProjection for symmetry?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. There is already an exposeProjection function but it could be renamed to prepareProjection.

marginLeft = margin,
...projection
}) {
if (height === undefined) height = width * projectionAspectRatio(projection);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doesn’t look like what we do in autoHeight

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

True. I'll make a helper function to be used in both places.

Copy link
Copy Markdown
Member

@mbostock mbostock left a comment

Choose a reason for hiding this comment

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

As far as testing goes, I’m hoping that we can test this new implementation against the existing (more wasteful) one. This:

Plot.plot({projection: {type: "mercator"}}).scale("projection")

Should be the same as this:

Plot.scale({projection: {type: "mercator"}})

* ```
*/
export function scale(options?: {[name in ScaleName]?: ScaleOptions}): Scale;
export function scale(options: {projection: ProjectionOptions & {width?: number; height?: number}}): Projection;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks like it needs margin options, too. And probably aspectRatio? I guess those should be pulled out of PlotOptions and into something we can reuse here, maybe call it DimensionOptions?

Co-authored-by: Mike Bostock <mbostock@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants