Quick Observable Retro Riff

Back in 2019, I pre-processed many Maine shapefiles for Day 11 of that year’s 30-Day Map Challenge.

So, I decided to save some time and re-use some of that data. I used R to convert the objects to GeoJSON (it’s just st_write()).

I wanted to add labels for the “towns” (Maine state definition), so I got the link to the ArcGIS REST API endpoint for Maine Town Points from my spiffy state GIS center.

The centroids for those towns are right in the middle of the entire town area, but I wanted Southwest Harbor and Bar Harbor labels to be right in-town. That required a bit of surgery with R:

me_towns <- st_read("https://services1.arcgis.com/RbMX0mRVOFNTdLzd/arcgis/rest/services/Maine_Town_Points/FeatureServer/0/query?where=1%3D1&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&relationParam=&returnGeodetic=false&outFields=&returnGeometry=true&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&defaultSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pgeojson&token=")
me_towns |>
  filter(
    !(TOWN %in% c("Bar Harbor", "Southwest Harbor"))
  ) |>
  bind_rows(
    data.frame(
      TOWN = c("Bar Harbor", "Southwest Harbor"),
      lat = c(44.387699, 44.274498902),
      lng = c(-68.212219, -68.32166538)
    ) |>
      st_as_sf(
        coords = c("lng", "lat"),
        crs = st_crs(me_towns)
      )
  ) |>
  st_transform(
    st_crs(acad_bound)
  ) |>
  filter(
    TOWN %in% c(
      "Bar Harbor",
      "Mount Desert",
      "Tremont",
      "Southwest Harbor",
      "Cranberry Isles"
    )
  ) -> mdi_towns

Having already done a customized Maine map in {ggplot2} in that 2019 post, I decided to switch it over to Observable Plot, especially since I wanted to use some fancy fonts, and fonts in R/ggplot2 — despite having significantly improved — are still just frustrating enough to make working in OBS Plot a much nicer experience.

Expand (below) for the OJS/Plot code.

Code
Plot = require("@observablehq/plot");

fonts = ({
  antiquarian: await FileAttachment("static/fonts/antiquarian.ttf"),
  geographicaHand: await FileAttachment("static/fonts/geographica-hand.ttf"),
  geographicaScript: await FileAttachment("static/fonts/geographica-script.ttf")
})

mdi = ({
  border: await FileAttachment("static/data/mdi-border.geojson").json(),
  inlandWater: await FileAttachment("static/data/mdi-inland-water.geojson").json(),
  southwestHarbor: await FileAttachment("static/data/southwest-harbor.geojson").json(),
  roads: await FileAttachment("static/data/mdi-roads.geojson").json(),
  acadiaBoundary: await FileAttachment("static/data/acadia-boundary.geojson").json(),
  towns: await FileAttachment("static/data/mdi-towns.geojson").json()
})

Plot.plot({
    className: "retro",
    title: html`<h2 style="text-align: center;">
        The Distinguished Territory Of
        <span style="display: block;  color: #dcd8b6; font-size: 1.3em;">Mount Desert Island</span>
    </h2>`,
    subtitle: html`<h3 style='text-align:center;'>Featuring the majestic forests and mountains of <span style="color: #9bd0b0">Acadia National Park</style></h3>`,
    width: width,
    height: width * 1.005,
    style: {
        background: "#324555",
        color: "white",
    },
    x: {
        ticks: 0,
    },
    y: {
        ticks: 0,
    },
    marks: [
        Plot.geo(mdi.border, {
            fill: "#dcd8b6",
            stroke: "#ffffff99",
            strokeWidth: 2,
        }),
        Plot.geo(mdi.inlandWater, { fill: "#324555" }),
        Plot.geo(mdi.southwestHarbor, { fill: "#f0928f", stroke: "#f0928f" }),
        Plot.geo(mdi.acadiaBoundary, { fill: "#9bd0b0", stroke: "#9bd0b0" }),
        Plot.geo(mdi.roads, { strokeWidth: 0.125, stroke: "black" }),
        Plot.text(
            mdi.towns.features,
            Plot.centroid({
                text: (d) => d.properties.TOWN,
                textAnchor: "middle",
                fontFamily: "Antiquarian",
                fontSize: "18pt",
                stroke: "white",
                fill: "black",
            })
        ),
    ],
});