Set global plot defaults for Observable Plot

Hi. I have been using Observable Plot within quarto documents to create interactive plots for HTML output. It really works so well! Is there any way to change the defaults of Plot so they apply to all the plots in a document?
For example, setting backgroundColor: "red" in a way it applies to all plots, without the need to change it in each plot. The same for other plot properties (font, etc).

Thanks!

This is not possible yet, but you can follow the feature request (and vote it up) here Create plot themes · Issue #630 · observablehq/plot · GitHub

1 Like

One way is to define your theme as an options object like so:

theme = ({
  style: "background-color: black; color: white;"
})

Then you pass your theme options in to Plot.plot:

Plot.plot({
  ...theme,
  marks: [
    Plot.barY(alphabet, {x: "letter", y: "frequency"})
  ]
})

Or in shorthand:

Plot.barY(alphabet, {x: "letter", y: "frequency"}).plot(theme)

Here’s a related tutorial on this technique:

If you like, you could also wrap Plot.plot to apply these default options:

function myplot({
  style = "background-color: black; color: white;",
  ...options
} = {}) {
  return Plot.plot({style, ...options});
}

Then you would replace calls to Plot.plot with myplot, like so:

myplot({marks: [Plot.barY(alphabet, {x: "letter", y: "frequency"})]})

(This approach won’t work with Plot.barY(…).plot(), though.)

If you really want to override the behavior of Plot so that you don’t have to rewrite your code, then you could monkey patch Plot like so:

Plot = {
  const Plot = await require("@observablehq/plot@0.6.4/dist/plot.umd.min.js");
  const {plot} = Plot; // capture the base plot before overriding

  // A themed version of Plot.plot, altering the default options. Note that
  // nested options (e.g., x.grid) will require fancier destructuring.
  function myplot({style = "background-color: black; color: white;", ...options} = {}) {
    return plot({style, ...options});
  }

  // Override Plot.plot to use the theme.
  Plot.plot = myplot;

  // Override Mark.prototoype.plot for mark shorthand.
  Plot.Mark.prototype.plot = function({marks = [], ...options} = {}) {
    return myplot({...options, marks: [...marks, this]});
  };

  return Plot;
}

But it’s messy to do this; for example if the code above runs more than once, it will wrap the themed plot to apply the theme twice! S I recommend using a helper plot method instead. As @Fil said we’d like to offer more explicit supporting for theming within Plot soon. Then it’d probably be something like

MyPlot = Plot.theme({style = "background-color: black; color: white;"})

and then calling MyPlot.plot or MyPlot.barY instead of Plot.plot and Plot.barY.

4 Likes

Thanks for the response! The theme solution you propose is very nice.

1 Like