Stop telling the reader that the hundred directly imaged exoplanets were never imaged
Every exoplanet card without a map ended "Not an observation — no image of this world exists.",
and 395b613 wrote that rule into a comment ("Only an exoplanet has never been imaged") and a test.
The NASA Exoplanet Archive flags 102 planets as detected by imaging (ima_flag), all 102 of them in
exoplanets.json: HR 8799 b to e (Marois et al. 2008), bet Pic b, 51 Eri b, AF Lep b, and bet Pic c
and eps Ind A b, found by radial velocity and imaged since. The review read the sentence on the
live pages of HR 8799 b, 51 Eri b and bet Pic b.
The ETL now asks the archive for those names in a query of its own, cached apart from the main
table so the other 6 252 planets stay on the snapshot they were built from, and carries
`imaged: true` on the matching records. exoplanets.json changes by that field on 102 records and
nothing else (compared record by record). Their cards now end "Not an observation — it has been
imaged only as a point of light beside its star, and no map of it exists."; the rest keep "no
image of this world exists". The provenance comment and the texture catalogue's comment say which
is which.
Checked live on :4301: HR 8799 b and eps Ind A b carry the new sentence, Kepler-22 b the old one.
Tests: body-view-model.spec 'says a directly imaged exoplanet was seen as a point of light, not
that no image of it exists'; the old test is renamed 'says an exoplanet the archive does not flag
as imaged has no image'. Unit controls, each failing that test only (1 failed, 840 passed): the
provenance ignoring the flag; the view model dropping it. build.ts now requires at least 95
imaged planets (measured 102); control, the full ETL with the join made on the host's name
instead of the planet's, fails with "Only 0 exoplanets are marked as imaged".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,8 @@ export interface BodyDetailViewModel {
|
||||
appearance: PlanetAppearance;
|
||||
/** True when a real photograph is being shown rather than the derived surface. */
|
||||
hasPhotography: boolean;
|
||||
/** An exoplanet photographed by direct imaging, as a point of light; see `ExoplanetRecord.imaged`. */
|
||||
imaged?: boolean;
|
||||
/**
|
||||
* Sidereal orbital period. For a solar-system body, 360 degrees over JPL's published mean
|
||||
* motion; for an exoplanet, the archive's period where it published one, and undefined where not.
|
||||
|
||||
@@ -75,15 +75,22 @@ export function bodyReadouts(body: BodyDetailViewModel): BodyReadouts {
|
||||
* The derived surface is a reasoned illustration, and a panel of real measurements sitting next
|
||||
* to it is exactly the context in which it could be mistaken for another one.
|
||||
*
|
||||
* Only an exoplanet has never been imaged. A moon or dwarf planet drawn this way has been — Voyager
|
||||
* 2 photographed Uranus's five large moons, Proteus and Nereid, Cassini Hyperion, and Hubble sees
|
||||
* Eris, Haumea and Makemake as points — but has no global map this app can use.
|
||||
* A moon or dwarf planet drawn this way has been imaged — Voyager 2 photographed Uranus's five
|
||||
* large moons, Proteus and Nereid, Cassini Hyperion, and Hubble sees Eris, Haumea and Makemake as
|
||||
* points — but has no global map this app can use. So have the hundred or so exoplanets the
|
||||
* archive flags as imaged, HR 8799's four among them, though only as points of light beside their
|
||||
* star. Only the other exoplanets, known from what they do to starlight, have no image at all.
|
||||
*/
|
||||
function provenanceFor(body: BodyDetailViewModel): string {
|
||||
if (body.hasPhotography) {
|
||||
return 'Surface: NASA/ESA/USGS photography.';
|
||||
}
|
||||
const why = body.kind === 'exoplanet' ? 'no image of this world exists' : 'no global map of this world is used here';
|
||||
const why =
|
||||
body.kind !== 'exoplanet'
|
||||
? 'no global map of this world is used here'
|
||||
: body.imaged
|
||||
? 'it has been imaged only as a point of light beside its star, and no map of it exists'
|
||||
: 'no image of this world exists';
|
||||
return body.appearance.equilibriumTemperatureK === null
|
||||
? `Surface illustrated from this body’s measured size and mass. Its host star is not in the catalogue, so no temperature could be derived. Not an observation — ${why}.`
|
||||
: `Surface illustrated from the measurements above — size, density and the temperature derived from its star’s output and its orbit. Not an observation — ${why}.`;
|
||||
|
||||
@@ -91,12 +91,20 @@ describe('buildBodyViewModel', () => {
|
||||
expect(provenance).not.toContain('no image of this world exists');
|
||||
});
|
||||
|
||||
it('says an exoplanet has never been imaged', () => {
|
||||
it('says an exoplanet the archive does not flag as imaged has no image', () => {
|
||||
const exoplanet: ExoplanetRecord = { id: 'x', hostStarId: SUN_STAR_ID, hostStarName: 'Sol', name: 'X b', orbit: { semiMajorAxisAu: 0.05 } };
|
||||
const model = buildBodyViewModel('x', { bodies: [], exoplanets: [exoplanet], stars: [sun] })!;
|
||||
expect(bodyReadouts(model).provenance).toContain('Not an observation — no image of this world exists.');
|
||||
});
|
||||
|
||||
it('says a directly imaged exoplanet was seen as a point of light, not that no image of it exists', () => {
|
||||
// HR 8799 b: photographed beside its star at Gemini and Keck (Marois et al. 2008).
|
||||
const exoplanet: ExoplanetRecord = { id: 'HR 8799 b', hostStarId: SUN_STAR_ID, hostStarName: 'HR 8799', name: 'HR 8799 b', imaged: true, orbit: { semiMajorAxisAu: 68 } };
|
||||
const provenance = bodyReadouts(buildBodyViewModel('HR 8799 b', { bodies: [], exoplanets: [exoplanet], stars: [sun] })!).provenance;
|
||||
expect(provenance).toContain('Not an observation — it has been imaged only as a point of light beside its star, and no map of it exists.');
|
||||
expect(provenance).not.toContain('no image of this world exists');
|
||||
});
|
||||
|
||||
it('marks a published exoplanet period as measured, not derived', () => {
|
||||
const exoplanet: ExoplanetRecord = {
|
||||
id: 'kepler-22-b',
|
||||
|
||||
@@ -78,6 +78,7 @@ export function buildBodyViewModel(id: string, catalogues: BodyCatalogues): Body
|
||||
orbit: exoplanet.orbit,
|
||||
appearance: appearanceForExoplanet(exoplanet, luminosityOf(hostStar)),
|
||||
hasPhotography: bodyTexturePath(exoplanet.id) !== undefined,
|
||||
imaged: exoplanet.imaged,
|
||||
// `periodDays` is populated for none of the shipped records, and deriving one would need the
|
||||
// host star's mass, which is equally absent. Left undefined rather than assuming a solar-mass
|
||||
// host, which would silently mis-state the period of every planet around an M dwarf.
|
||||
|
||||
@@ -12,6 +12,11 @@ export interface ExoplanetRecord {
|
||||
radiusEarth?: number;
|
||||
massEarth?: number;
|
||||
discoveryYear?: number;
|
||||
/**
|
||||
* True where the archive flags the planet as detected by imaging (`ima_flag`): photographed as a
|
||||
* point of light beside its star, as HR 8799's four planets were. Absent for every other planet.
|
||||
*/
|
||||
imaged?: true;
|
||||
/**
|
||||
* Measured orbital period in days (`pl_orbper`). Together with the semi-major axis this
|
||||
* pins the host star's gravitational parameter exactly, so the planet can be propagated at
|
||||
|
||||
@@ -5,7 +5,8 @@ import * as THREE from 'three/webgpu';
|
||||
* keyed by the same ids used in `bodies.json`.
|
||||
*
|
||||
* Only surface *maps* belong here: equirectangular images, twice as wide as tall, that wrap a
|
||||
* sphere. Everything else — every exoplanet, since not one has ever been imaged, and every moon
|
||||
* sphere. Everything else — every exoplanet, since the few imaged were seen only as points of
|
||||
* light, and every moon
|
||||
* or dwarf planet with no such map in the repository — falls through to
|
||||
* `procedural-planet-texture.ts`, which derives a surface from the body's own measured size,
|
||||
* mass, orbit and host star instead.
|
||||
|
||||
Reference in New Issue
Block a user