archaeopteryx 3.26.0 → 3.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -297,7 +297,8 @@ The card button in the panel header opens **Control panel**: one row for every
297
297
  control the panel is currently showing, in the order it shows them, each with
298
298
  the control's own glyph or name and the sentence that explains it — the layout
299
299
  and display-type buttons included, drawn with the very glyph they carry in the
300
- panel. The About box has a row for it too.
300
+ panel. The About box has a row for it too, and one for
301
+ [Diagnostics](#diagnostics).
301
302
 
302
303
  The display types say what they do and when they are greyed, whether or not
303
304
  they are greyed in the view you are looking at: *"phylogram: branch lengths
@@ -1148,103 +1149,69 @@ names exactly what is missing (including "the loaded d3 is not usable as d3
1148
1149
  version 7"). The optional export libraries stay page-level globals in every
1149
1150
  loading style: `window.Canvg` (PNG), `window.jspdf` + svg2pdf.js (PDF).
1150
1151
 
1151
- The parser is picked from the data and the `location`: content starting with
1152
- `#NEXUS` (or a name ending in `.nex`/`.nexus`) is read as Nexus, JSON content
1153
- (or a name ending in `.json`) as an **Auspice/Nextstrain v2** `dataset.json`,
1154
- a name ending in `xml` as phyloXML, anything else as New Hampshire (Newick).
1155
- A file holding **several trees** — a Nexus TREES block, a Newick file with one
1156
- tree per `;`, a phyloXML with several phylogenies — opens on the first, and a
1157
- picker with previous / next buttons at the top of the control panel moves
1158
- between them (also ⌘⇧< / ⌘⇧>). **Each tree is its own workspace:** you leave
1159
- a tree as you had it — layout, display type, labels, colours, sizes, tracks,
1160
- both searches, the clade you switched to and the ones you collapsed — and it
1161
- comes back that way. A tree you have not opened yet starts on its own
1162
- presets, read from its own content, in the layout and sizes you are already
1163
- using: stepping through ten trees of one file keeps them all circular, while
1164
- each still labels and colours itself its own way. Zoom and pan are not kept
1165
- (a tree opens fitted), and the views last as long as the page.
1166
- A protein/DNA/RNA characters matrix in a Nexus file
1167
- (sequential or interleaved) lands on the tips as an aligned `mol_seq`, so the
1168
- alignment track appears just as it does for phyloXML.
1169
-
1170
- An Auspice dataset has no branch lengths of its own, so it opens in the
1171
- metric it states completely: the **time view** when every node states a
1172
- `num_date` (branch lengths are the `num_date` differences, sign kept), else
1173
- the divergence view when every node states a `div`, else time if any node is
1174
- dated. In the time view the calendar time axis and node-age bars come from
1175
- `num_date` and its confidence interval, and every trait (country, host,
1176
- clade, ...) becomes a
1177
- `nextstrain:<trait>` node property — so Color-by, search and the node dialog
1178
- pick them up. Both metrics are retained, and
1179
- `forester.applyTimeBranchLengths(phy)` /
1180
- `forester.applyDivergenceBranchLengths(phy)` /
1181
- `forester.hasTimeAndDivergence(phy)` are the plumbing behind the
1182
- **Time | Div** switch (and `forester.clockPlotKind(phy)` /
1183
- `forester.clockPlotData(phy, view)` / `forester.clockRegression(xs, ys)`
1184
- behind the **Clock plot**: which trees have one, its points and its
1185
- least-squares line). The two `apply` functions answer `true` when they
1186
- laid the tree out, and `false` — leaving every branch length as it was —
1187
- when their layout cannot state every branch.
1188
-
1189
- **BEAST-style and NHX annotations** in Newick/Nexus input are always parsed
1190
- (they used to be discarded): in a `[&key=value,...]` blob — as written by
1191
- BEAST, BEAST 2, TreeAnnotator, FigTree and MrBayes — `posterior`, `prob`
1192
- (+`prob_stddev`) and `bootstrap` become confidences, node `height`
1193
- (median/mean) with its `95%_HPD` (or range) becomes the node date the age
1194
- bars draw, FigTree's `!color` becomes the branch colour, and every other
1195
- field (`rate`, traits, ...) becomes a `beast:<key>` node property for
1196
- Color-by and search (`mutations`, `mcc` and FigTree's `!`-prefixed display
1197
- directives are always text, never a gradient). **TreeTime**'s trees open as
1198
- what they are: its `timetree.nexus` carries dates only as `date=` annotations,
1199
- and those become node dates — calendar axis and all — where the date
1200
- differences reproduce the branch lengths, which is true of the time tree and
1201
- not of `divergence_tree.nexus`, though both carry the same annotations. Its
1202
- annotations land as `treetime:<key>` rather than `beast:<key>`, and its
1203
- `auspice_tree.json` opens as the Auspice dataset it is. FigTree's colour on a **taxon** — `'name'[&!color=...]` in the
1204
- TAXLABELS block — is that tip's **label** colour, carried as the desktop's
1205
- `style:font_color` property and drawn by Visual Styles. A number is a plain
1206
- decimal with an optional exponent: `0x1A` and `3f` are text.
1207
- **Auspice's "download Nexus"** annotations land where the
1208
- Auspice JSON reader puts the same dataset, so one Nextstrain build opens the
1209
- same way in either format: `num_date` is the node's date in years (and a
1210
- `nextstrain:num_date` property), `num_date_CI={lo,hi}` its interval — on a tip
1211
- too, where it is the sampling-date uncertainty — and `div` a
1212
- `nextstrain:div` property — but only on a tree that is actually time-scaled,
1213
- since Auspice writes the same annotations on its divergence tree: where the
1214
- year differences do not reproduce the branch lengths the dates stay properties
1215
- and no calendar axis is drawn. Inside an annotation a quote opens a string
1216
- only where a value starts, so a bare `country=Côte d'Ivoire` is one field with
1217
- an apostrophe in it. Classic `[&&NHX:...]` tags map to their phyloXML
1218
- equivalents (`S=` taxonomy, `T=` taxonomy id, `B=` support, `D=`
1219
- duplication/speciation event, `GN=`/`AC=` sequence name/accession), read as
1220
- the desktop reads them: unquoted whitespace is formatting noise (`S=Homo
1221
- sapiens` is `Homosapiens`), a quoted value keeps its content
1222
- (`S="Homo sapiens"` is `Homo sapiens`), and the quotes themselves are never
1223
- part of the value. Plain
1224
- `[number]` brackets keep their old meaning (confidence values).
1225
-
1226
- Both entry points **throw** on bad input — an undefined or empty tree, an
1227
- unparseable file, or a config key that no longer exists. Nothing is reported by
1228
- a popup any more, and nothing fails silently.
1229
-
1230
- ## Supported file formats
1231
-
1232
- | Format | I/O | What Archaeopteryx.js does with it | Ref. |
1233
- |---|---|---|---|
1234
- | **Newick** / New Hampshire (`.nwk`, `.nh`, `.tre`) | in / out | The base tree: topology, names, branch lengths, and bracketed confidence values. | [1] |
1235
- | **NHX** — New Hampshire eXtended | in | `[&&NHX:...]` tags riding on Newick: taxonomy (`S=`, `T=`), sequence (`GN=`, `AC=`), support (`B=`), duplication/speciation events (`D=`). | [2] |
1236
- | **Nexus** (`.nex`, `.nexus`) | in / out | One file for the tree(s) and, in a `CHARACTERS`/`DATA` block, an aligned protein/DNA/RNA matrix (sequential or interleaved) — the tree and its alignment together. | [3] |
1237
- | **phyloXML** (`.xml`) | in / out | The richest native format: taxonomy, sequences and alignments, dates, confidences, branch colours and arbitrary metadata (custom properties). | [4] |
1238
- | **Auspice / Nextstrain** `dataset.json` (v2) | in | Phylodynamic builds: sampling dates and their confidence, cumulative divergence, and discrete traits (country, clade, host, ...) with their posterior distributions. | [5] |
1239
- | **BEAST** / BEAST 2 / TreeAnnotator annotations | in (embedded in Newick/Nexus) | `[&posterior=...,height_95%_HPD={lo,hi},rate=...]`-style blobs: posterior clade support, node-age confidence intervals, per-branch rates and other traits. FigTree's `!color` is read the same way. | [6, 7] |
1240
- | **MrBayes** annotations | in (embedded in Newick/Nexus) | `prob=`/`prob.stddev=` blobs: posterior-probability clade support. | [8] |
1241
- | **Metadata table** (`.tsv`, `.csv`) | in (beside a tree) | A header row and one row per tip, the first column naming the tip: every other column is joined onto the tips as a property, so it is offered for Color-by and Shape, searched, shown in the node data and written into phyloXML exports. See [Metadata tables](#metadata-tables). | — |
1242
- | **FASTA** | out | The molecular sequence(s) of the selected tip(s), or every sequence the tree carries. Offered in the Download menu only when the tree actually carries molecular sequences (aligned or not). | [9] |
1243
- | SVG · PNG · vector PDF | out | The drawn tree for publication or further editing — vector (SVG, PDF) or raster (PNG), either as shown on screen or the whole tree at full size (see [Downloads](#downloads)). General-purpose graphics formats, not phylogenetic data, so no literature reference applies. | — |
1244
-
1245
- The parser for a given input is auto-detected (see **The entry points**
1246
- above); the Download menu offers whichever output formats the current tree
1247
- can carry.
1152
+ ### Diagnostics
1153
+
1154
+ Checking at use rather than at load makes the viewer hard to break — and lets
1155
+ it run half-equipped without a word: no PDF in the Download menu, a retired
1156
+ config key ignored, a forced visualization overruled, each mentioned only in a
1157
+ console nobody has open. **`archaeopteryx.doctor()`** says what state the
1158
+ program is in on this page:
1159
+
1160
+ ```javascript
1161
+ var report = archaeopteryx.doctor();
1162
+ report.ok; // false when something is wrong that nobody chooses
1163
+ report.summary; // "nothing to report", or "2 things to check"
1164
+ report.problems; // ['jspdf: loaded without svg2pdf.js: PDF export needs both, so it is off', ...]
1165
+ report.notes; // stated, not flagged
1166
+ report.libraries; // [{name, role, loaded, version, status, detail}, ...]
1167
+ report.functions; // [{name: 'PDF export', available: false, detail: 'jspdf and svg2pdf.js are not loaded'}, ...]
1168
+ report.launch; // {config, tips, tree, trees, container}, or null when no tree is on view
1169
+ report.text; // all of it as plain text, to paste into an issue
1170
+ console.log(archaeopteryx.doctor().text);
1171
+ ```
1172
+
1173
+ It works before a launch, after a launch that threw, and in Node, and it never
1174
+ throws. The same report is in the viewer: the **About** box (a click on the
1175
+ program name) has a **Diagnostics** row that opens it, with a **Copy report**
1176
+ button — the copied text adds the keys passed to `launch()` (a string or a
1177
+ number as given, anything else as its kind: a tree or a callback is never
1178
+ copied) and the browser.
1179
+
1180
+ What is a **problem** and what is only stated:
1181
+
1182
+ | | |
1183
+ |---|---|
1184
+ | An optional library that is not loaded (canvg, jspdf, svg2pdf.js) | **stated**: "PNG export: off". Leaving one out is a site's choice. |
1185
+ | Half of a pair: jspdf without svg2pdf.js, or the other way round; svg2pdf.js loaded before jspdf | **problem** |
1186
+ | A library under its 2.x-era global (`window.canvg`, `window.jsPDF`) and not under the one this version reads; a `window.Canvg` without `fromString` | **problem** |
1187
+ | A d3 that is not version 7 (d3 4 to 6 have `d3.zoom` and `d3.cluster` too, so the launch check lets them through) | **problem**; a d3 7 older than 7.9 is a note |
1188
+ | `forester.js` and `archaeopteryx.js` from different releases (`forester.VERSION`) | **problem** |
1189
+ | A phyloxml older than 1.1.7: one that drops something when saving, or writes a node's style as the earlier releases did | **problem** — and "Read and save phyloXML" stays **on**, since it still reads and saves |
1190
+ | A phyloxml that only lays the file out differently from 1.1.7 (a newer release) | **note** |
1191
+ | phyloxml or sax not loaded, or a phyloxml that cannot read or write at all | **problem** |
1192
+ | What the last launch printed about its **config**: a deprecated key, an `initialVisualization` the tree cannot honour or that was overruled, a bad `pngExportScale`, a thrown `onViewChange`, and why a launch threw (`launchArchaeopteryx` included) | **problem** |
1193
+ | An export that failed (a clipboard the browser refused, a canvas too large), what the viewer left out of a tree (a domain or a gene it could not place), a size setting ignored | **note**: nothing a site's configuration decides |
1194
+
1195
+ Only forester, jsPDF and d3's script build state a version; the others are
1196
+ judged by what they do. The d3 the viewer was handed at load is the one
1197
+ reported, as `launch()` uses it — a d3 with no `version` (the ES-module build
1198
+ a bundler imports) is recognised by what only d3 7 has. phyloxml is given a
1199
+ small tree to write, and the result is read for what the older releases are
1200
+ known to do.
1201
+
1202
+ **While the report has a problem, a small dot follows the program name** in
1203
+ the panel header, and the name's tooltip says how many. It is neutral, not a
1204
+ warning colour: most of the people who see it are a site's visitors, who can
1205
+ do nothing about it. Nothing appears when an optional library is merely
1206
+ absent. The dot is brought up to date when a problem is recorded, when the
1207
+ page finishes loading, when the pointer enters the panel, when the About box
1208
+ opens and when `doctor()` is called — so a library that arrives after the
1209
+ launch puts it out without a relaunch.
1210
+
1211
+ The warnings belong to **the tree on view**: `showTree()` starts them afresh
1212
+ for the tree it moves to, and so does a new launch. A launch that is rejected
1213
+ while an earlier viewer is still on the page leaves that viewer's report as
1214
+ it was and adds one line saying what failed.
1248
1215
 
1249
1216
  ### Downloads
1250
1217
 
@@ -259,6 +259,57 @@ export interface ViewerHandle {
259
259
  * value, 'label' keeps them as names. */
260
260
  export type InternalNumericLabels = 'auto' | 'confidence' | 'label';
261
261
 
262
+ /** One library's row in the diagnostics report. `status`: 'ok'; 'absent'
263
+ * (not loaded, and that is no fault: an optional library, or d3 outside a
264
+ * page); 'note' (stated, not flagged); 'problem' (lights the dot). */
265
+ export interface DoctorLibrary {
266
+ name: 'forester.js' | 'd3' | 'phyloxml' | 'sax' | 'canvg' | 'jspdf' | 'svg2pdf.js' | string;
267
+ role: 'required' | 'optional';
268
+ loaded: boolean;
269
+ /** Only d3 (its script build), jsPDF and forester state one. */
270
+ version: string | null;
271
+ status: 'ok' | 'absent' | 'note' | 'problem';
272
+ detail: string;
273
+ }
274
+
275
+ /** What the user gets or does not get, with the reason when it is off. */
276
+ export interface DoctorFunction {
277
+ name: 'Read and save phyloXML' | 'PNG export' | 'Copy PNG' | 'PDF export' | string;
278
+ available: boolean;
279
+ detail: string;
280
+ }
281
+
282
+ /** The tree on view. A config value is given as passed when it is a
283
+ * string, a number, a boolean or null, and otherwise as its kind:
284
+ * '(function)', '(list of 3)', '(object)'. */
285
+ export interface DoctorLaunch {
286
+ config: Record<string, string | number | boolean | null>;
287
+ tips: number | null;
288
+ /** 1-based, of `trees`. */
289
+ tree: number;
290
+ trees: number;
291
+ container: { width: number; height: number } | null;
292
+ }
293
+
294
+ /** archaeopteryx.doctor(): the state of the program on this page. */
295
+ export interface DoctorReport {
296
+ program: string;
297
+ version: string;
298
+ /** false when something is wrong that nobody chooses. */
299
+ ok: boolean;
300
+ /** 'nothing to report', or '2 things to check'. */
301
+ summary: string;
302
+ problems: string[];
303
+ notes: string[];
304
+ libraries: DoctorLibrary[];
305
+ functions: DoctorFunction[];
306
+ /** null while no tree is on view. */
307
+ launch: DoctorLaunch | null;
308
+ environment: { userAgent: string | null; secureContext: boolean | null };
309
+ /** The whole report as plain text, for pasting into an issue. */
310
+ text: string;
311
+ }
312
+
262
313
  export interface Archaeopteryx {
263
314
  /** Launch the viewer into a container (a CSS selector or the element
264
315
  * itself; an unresolvable container throws). Exactly three arguments.
@@ -297,6 +348,11 @@ export interface Archaeopteryx {
297
348
  /** Module-level twin of the handle's getSelectedNodes. */
298
349
  getSelectedNodes(): PhylogenyNode[];
299
350
 
351
+ /** The state of the program on this page: the libraries, the functions
352
+ * they switch off, what the launch on view warned about. Works before a
353
+ * launch, after one that threw, and in Node; never throws. */
354
+ doctor(): DoctorReport;
355
+
300
356
  /** A view as a "key=value&..." string for a URL hash, and back. decode
301
357
  * accepts a leading '#', ignores what it does not know, and returns
302
358
  * null for nothing. */