Polygons with holes in Observable.Plot

It’s easy to draw a polygon with a hole in SVG using an even/odd winding rule. For example:

svg`
  <svg width="800px" height="300" viewBox="0 0 800 400"  version="1.1"
    xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
      <path
        d='M 50,50 L 400,50 L 400,300 L 50,300 Z
        M 100,100 L 100,200 L 200,200 L 200,100 Z'>
      </path>
  </svg>
`

will produce a rectangle with a square hole:

Is there a way to produce this sort of output with Observable.Plot? An artificial simulation, like drawing a white polygon for the hole on a black polygon would be insufficient.

We don’t have a generic path mark, but you can create it as a “function which returns an SVG element”:

Plot.plot({
  marks: [
    () => svg`<path
        d='M 50,50 L 400,50 L 400,300 L 50,300 Z
        M 100,100 L 100,200 L 200,200 L 200,100 Z'>
      </path> `
  ],
  height: 320
})

If the question is to make it data- and scales-aware, the answer will be of course more complex than this—creating a custom mark type can be done by building up on the generic Plot.Mark class, or in the simpler case on the Plot.Rect mark. Depends on how you’d want to link the channels to the visuals.

3 Likes

Thanks @Fil! Your response makes perfect sense but I ended up using canvas for efficiency reasons. Here’s what I was after.

that’s great! viva polygon-clipping :slight_smile: