Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,9 @@ node scripts/geocode-places.mjs --check # exit 1 if anything is unplaced
```

Coordinates live in `config/places.json` so the site and CI never call a
geocoder. The script skips anything not in the format above, and checks the
geocoder. A name that is the same campus as another — "University of Chicago" and
"The University of Chicago" — is written `{ "sameAs": "<other name>" }`, not a
second copy of the coordinates; `tests/places.test.js` fails on a repeat. The script skips anything not in the format above, and checks the
`matched` string it wrote — Nominatim answers "Durham, UK" with the county, not
the city. Correct a wrong pin by hand; the script never overwrites one.

Expand Down
54 changes: 14 additions & 40 deletions config/places.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$comment": "Coordinates for every place the site pins — collaborator institutions and presentation locations alike — resolved once with scripts/geocode-places.mjs and committed so the site and CI never call a geocoder. `matched` is what the geocoder thought it found — check it before trusting a pin. Safe to correct by hand: the script only fills in what is missing.",
"$comment": "Coordinates for every place the site pins — collaborator institutions and presentation locations alike — resolved once with scripts/geocode-places.mjs and committed so the site and CI never call a geocoder. `matched` is what the geocoder thought it found — check it before trusting a pin. Safe to correct by hand: the script only fills in what is missing. A name that is the same campus as another is `{ \"sameAs\": \"<other name>\" }` rather than a second copy of the coordinates; read places through src/lib/places.js. Keep one entry per campus: tests/places.test.js fails on two entries with the same coordinates.",
"source": "https://nominatim.openstreetmap.org (ODbL)",
"places": {
"A Coruña, Spain": {
Expand Down Expand Up @@ -38,9 +38,7 @@
"matched": "California Institute of Technology, Moore Walk, Pasadena Council District 7, Pasadena, Los Angeles County, California, 91125, United States"
},
"Caltech": {
"lat": 34.137,
"lon": -118.1253,
"matched": "California Institute of Technology, Broad Walk, Pasadena Council District 7, Pasadena, Los Angeles County, California, 91106, United States"
"sameAs": "California Institute of Technology"
},
"Caltech/JPL": {
"lat": 34.2015,
Expand All @@ -58,9 +56,7 @@
"matched": "hand-placed: MaRS Centre, 661 University Ave, Toronto"
},
"Canadian Institute for Theoretical Astrophysics": {
"lat": 43.66,
"lon": -79.3971,
"matched": "hand-placed: 60 St George St, University of Toronto"
"sameAs": "University of Toronto"
},
"Cardiff University": {
"lat": 51.5067,
Expand All @@ -73,9 +69,7 @@
"matched": "hand-placed: 1530 P St NW, Washington DC — Nominatim has no entry"
},
"Carnegie Observatories": {
"lat": 34.1563,
"lon": -118.1334,
"matched": "The Carnegie Observatories, Earlham Street, Bungalow Heaven, Pasadena Council District 5, Pasadena, Los Angeles County, California, 91188, United States"
"sameAs": "Observatories of the Carnegie Institution of Washington"
},
"Case Western Reserve University": {
"lat": 41.5014,
Expand All @@ -88,9 +82,7 @@
"matched": "60 Garden Street, Cambridge, MA, USA (placed by hand)"
},
"Center for Computational Astrophysics": {
"lat": 40.7397,
"lon": -73.9903,
"matched": "hand-placed: part of the Flatiron Institute, 162 Fifth Ave, New York"
"sameAs": "Flatiron Institute"
},
"Centre de Recherche Astrophysique de Lyon": {
"lat": 45.6936,
Expand All @@ -103,9 +95,7 @@
"matched": "Centro de Estudios de Física del Cosmos de Aragón, VF-TE-02, Arcos de las Salinas, Gúdar-Javalambre, Teruel, Aragón, España"
},
"CESR": {
"lat": 43.5626,
"lon": 1.4759,
"matched": "Toulouse, France (placed by hand) — same place as Institut de Recherche en Astrophysique et Planétologie, its successor"
"sameAs": "Institut de Recherche en Astrophysique et Planétologie"
},
"Chengdu Experimental Foreign Languages School": {
"lat": 30.6587,
Expand Down Expand Up @@ -213,9 +203,7 @@
"matched": "Jesi, Ancona, Marche, 60035, Italia"
},
"Københavns Universitet": {
"lat": 55.6802,
"lon": 12.5723,
"matched": "Københavns Universitet, Copenhagen (geocoded) — same place as University of Copenhagen"
"sameAs": "University of Copenhagen"
},
"Laboratoire d'Astrophysique de Marseille": {
"lat": 43.3436,
Expand Down Expand Up @@ -398,19 +386,15 @@
"matched": "City of Rochester, Monroe County, New York, United States"
},
"Ruprecht Karls Universität Heidelberg": {
"lat": 49.4186,
"lon": 8.6692,
"matched": "Universität Heidelberg, Handschuhsheimer Landstraße, Handschuhsheim, Heidelberg, Baden-Württemberg, 69121, Deutschland"
"sameAs": "Ruprecht-Karls-Universität Heidelberg"
},
"Ruprecht-Karls-Universität Heidelberg": {
"lat": 49.4186,
"lon": 8.6692,
"matched": "Universität Heidelberg, Handschuhsheimer Landstraße, Handschuhsheim, Heidelberg, Baden-Württemberg, 69121, Deutschland"
},
"Rutgers The State University of New Jersey": {
"lat": 40.4969,
"lon": -74.449,
"matched": "Rutgers University, New Brunswick, NJ (geocoded)"
"sameAs": "Rutgers University"
},
"Rutgers University": {
"lat": 40.5204,
Expand All @@ -433,14 +417,10 @@
"matched": "Seattle, King County, Washington, United States"
},
"Simons Foundation": {
"lat": 40.7392,
"lon": -73.9909,
"matched": "hand-placed: 160 Fifth Ave, New York — Nominatim has no entry"
"sameAs": "Flatiron Institute"
},
"Smithsonian Astrophysical Observatory": {
"lat": 42.3814,
"lon": -71.1281,
"matched": "60 Garden Street, Cambridge, MA, USA (placed by hand) — same place as Center for Astrophysics Harvard & Smithsonian"
"sameAs": "Center for Astrophysics Harvard & Smithsonian"
},
"Smithsonian Institution": {
"lat": 38.8888,
Expand Down Expand Up @@ -528,9 +508,7 @@
"matched": "Orto Botanico dell'Università degli Studi di Cagliari, Stampaxi/Stampace, Casteddu/Cagliari, Sardigna/Sardegna, Italia"
},
"Università di Bologna": {
"lat": 44.4983,
"lon": 11.3545,
"matched": "Università di Bologna, Via dei Bibiena, Ghetto ebraico, Irnerio, Santo Stefano, Bologna, Emilia-Romagna, 40126, Italia"
"sameAs": "University of Bologna"
},
"Universität Bern": {
"lat": 46.951,
Expand Down Expand Up @@ -593,9 +571,7 @@
"matched": "University of Cambridge, 82-88, Hills Road, Petersfield, Cambridge, Cambridgeshire, Cambridgeshire and Peterborough, England, CB2 1NF, United Kingdom"
},
"University of Chicago": {
"lat": 41.7881,
"lon": -87.6048,
"matched": "University of Chicago, 5841, South Maryland Avenue, Hyde Park, Chicago, Hyde Park Township, Cook County, Illinois, 60637, United States"
"sameAs": "The University of Chicago"
},
"University of Colorado": {
"lat": 40.0076,
Expand Down Expand Up @@ -708,9 +684,7 @@
"matched": "Université Paris Cité – Campus Saint-Germain-des-Prés, 45, Rue des Saints-Pères, Quartier Saint-Thomas-d'Aquin, Paris 7e Arrondissement, Paris, Île-de-France, France métropolitaine, 75006, France"
},
"Universtity of Wisconsin": {
"lat": 43.0766,
"lon": -89.4125,
"matched": "hand-placed: University of Wisconsin-Madison. The name is misspelt on the ORCID record it came from, and is kept as written so the collector still matches it."
"sameAs": "University of Wisconsin Madison"
},
"Valencia, Spain": {
"lat": 39.4697,
Expand Down
8 changes: 6 additions & 2 deletions scripts/geocode-places.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
//
// Both live in one file because they are the same kind of fact — somewhere on
// Earth the site draws a dot for — and one committed answer per place means the
// two maps cannot disagree about where Cambridge is.
// two maps cannot disagree about where Cambridge is. A name that is the same
// campus as another is `{ sameAs }` it, so each coordinate is written once.
//
// Issue #22: geocoding at build time would make CI depend on a third-party
// API, which this repo avoids everywhere else. So this is run by hand and the
Expand Down Expand Up @@ -94,7 +95,10 @@ fs.writeFileSync(OUT, `${JSON.stringify({
+ 'presentation locations alike — resolved once with scripts/geocode-places.mjs and '
+ 'committed so the site and CI never call a geocoder. `matched` is what the geocoder '
+ 'thought it found — check it before trusting a pin. Safe to correct by hand: the '
+ 'script only fills in what is missing.',
+ 'script only fills in what is missing. '
+ 'A name that is the same campus as another is `{ "sameAs": "<other name>" }` rather than a '
+ 'second copy of the coordinates; read places through src/lib/places.js. Keep one entry per '
+ 'campus: tests/places.test.js fails on two entries with the same coordinates.',
source: 'https://nominatim.openstreetmap.org (ODbL)',
places: Object.fromEntries(Object.entries(places).sort(([a], [b]) => a.localeCompare(b))),
}, null, 2)}\n`);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/collabmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// lives in worldmap.js, shared with the conference map.

import collaborators from '/config/collaborators.json';
import places from '/config/places.json';
import { locate } from './places.js';
import { map, project, toXY, spread, hueFor, KM_PER_UNIT, MAX_DRIFT_MILES, MAX_PIN_DRIFT }
from './worldmap.js';
import { byType, venueUrl, links, assists, primaryLink } from './data.js';
Expand Down Expand Up @@ -83,7 +83,7 @@ export function collaboratorMap() {

for (const person of collaborators.people) {
const posts = person.affiliations
.filter((a) => a.start && a.organization && places.places[a.organization])
.filter((a) => a.start && a.organization && locate(a.organization))
// Newest first: what someone is doing now is the more useful fact, and it
// is the order every other dated list on this site uses. The trajectory
// is a line through the same points either way.
Expand All @@ -92,7 +92,7 @@ export function collaboratorMap() {

const mine = papers.get(person.orcid) ?? [];
const pins = posts.map((post) => {
const { lat, lon } = places.places[post.organization];
const { lat, lon } = locate(post.organization);
const [x, y] = toXY(lon, lat);
return {
organization: post.organization,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/confmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// Geometry is resolved here rather than in the component, so the page renders
// plain numbers and the maths is testable without a DOM.

import places from '/config/places.json';
import { locate } from './places.js';
import { map, toXY, spread, hueFor } from './worldmap.js';
import { byType, dateLabel, links } from './data.js';

Expand All @@ -32,7 +32,7 @@ export const ONLINE = 'Online';
export const ONLINE_AT = { lat: -70, lon: 0 };

/** Where a location string is on Earth, or nothing if it is not settled. */
const coords = (loc) => (loc === ONLINE ? ONLINE_AT : places.places[loc]);
const coords = (loc) => (loc === ONLINE ? ONLINE_AT : locate(loc));

/** How the CV's `kind` reads in a sentence about one talk. */
const KIND = {
Expand Down
14 changes: 14 additions & 0 deletions src/lib/places.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Where a named place is on Earth.
//
// `config/places.json` holds each coordinate once. A name that is the same
// campus as another — "University of Chicago" and "The University of Chicago",
// SAO and the CfA — is written `{ "sameAs": "<other name>" }` instead of
// repeating coordinates, so the two can never drift apart.

import data from '/config/places.json';

/** `{ lat, lon }` for a place name, or undefined when it is not placed. */
export function locate(name) {
const p = data.places[name];
return p?.sameAs ? data.places[p.sameAs] : p;
}
35 changes: 35 additions & 0 deletions tests/places.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, expect, it } from 'vitest';
import data from '../config/places.json';
import { locate } from '../src/lib/places.js';

const entries = Object.entries(data.places);

describe('config/places.json', () => {
it('points every sameAs at a place with coordinates of its own', () => {
for (const [name, p] of entries.filter(([, e]) => e.sameAs)) {
const target = data.places[p.sameAs];
expect(target, `${name} -> ${p.sameAs}`).toBeDefined();
expect(target.sameAs, `${name} -> ${p.sameAs} is a chain`).toBeUndefined();
expect(typeof target.lat).toBe('number');
}
});

it('writes each coordinate once: the same campus is a sameAs, not a copy', () => {
const seen = new Map();
for (const [name, p] of entries.filter(([, e]) => !e.sameAs)) {
const key = `${p.lat},${p.lon}`;
expect(seen.get(key), `${name} repeats the coordinates of ${seen.get(key)}`).toBeUndefined();
seen.set(key, name);
}
});

it('locate follows a sameAs and is undefined for an unplaced name', () => {
expect(locate('Smithsonian Astrophysical Observatory'))
.toBe(data.places['Center for Astrophysics Harvard & Smithsonian']);
expect(locate('Nowhere in particular')).toBeUndefined();
});

it('keeps the Smithsonian Institution in Washington, apart from the observatory', () => {
expect(locate('Smithsonian Institution').lat).not.toBe(locate('Smithsonian Astrophysical Observatory').lat);
});
});
Loading