Chemistry Metadata
Every SVG exported from the Export SVG dialog carries a machine-readable description of the structure (there is no longer a checkbox for it; older builds had an Embed chemistry metadata option). Molkit stamps it into the SVG itself: scalar attributes on the root element, data-mk-* attributes on every atom group and bond group, and a structured mk:chemistry block inside the file’s metadata element. Your page script can read the formula, walk the bond graph, or hand the embedded MOL block to a cheminformatics library without a server round trip. This page is the schema reference.
Reading conventions
- Attribute values are strings. Numbers are plain decimals. Boolean flags are the literal
"true"and are omitted when false; there is no"false"value except where noted. - Attributes marked “JSON” hold JSON text and need
JSON.parse. getAttributereturnsnullfor an absent attribute. An absent attribute means “not applicable” or “not computed”, never zero.- Coordinates in
data-mk-x,data-mk-y, the bond endpoint attributes, anddata-mk-view-boxesare in the SVG’s own coordinate space (the rootviewBoxspace, Y grows downward).
Root attributes
Scalar attributes on the svg root give you the identity of the structure without walking the tree. They are duplicated outside the metadata block so they survive HTML sanitizers that strip metadata elements.
| Attribute | When present | Value and meaning |
|---|---|---|
data-mk-version | always | Schema version, currently 1.0 |
data-mk-species-type | the structure is a real species (no generic atoms) | molecular, element, monatomic-ion, polyatomic-ion, or ionic (a salt drawn as separate charged ions). See species type |
data-mk-slug | the molecule has a user-set name | Kebab-case identity, e.g. carbon-monoxide |
data-mk-formula | identity is emitted (see below) | Molecular formula. Ions carry a Unicode superscript charge, e.g. NO3⁻, CO3²⁻. Carbon compounds use Hill order; carbon-free compounds use the IUPAC element sequence (NH3, SO2, PF5). Isotope labels appear in the formula, e.g. D2O |
data-mk-mw | identity is emitted | Molecular weight in g/mol, rounded to three decimals |
data-mk-smiles | identity is emitted and SMILES generation succeeded | SMILES string, built from computed formal charges |
data-mk-canonical-smiles | RDKit canonicalization ran | Canonical SMILES |
data-mk-inchi | PubChem lookup succeeded with a full property match | InChI |
data-mk-inchi-key | same as above | 27-character InChIKey |
data-mk-cid | PubChem lookup returned a compound | PubChem compound ID |
data-mk-has-abbreviations | a condensed label such as CH3 or OEt was decomposed | "true". See condensed labels |
data-mk-has-generic-definitions | R-group definitions were exported | "true". See mk:generic-definitions |
data-mk-has-resonance | a resonance set was exported | "true" |
data-mk-has-visual-sets | a visual set (one species drawn in several views) was exported | "true" |
data-mk-views | with data-mk-has-visual-sets | Comma-separated views in canonical order: lewis, vsepr, condensed, bondline, fischer, orbitals |
data-mk-default-view | with data-mk-has-visual-sets | The view the author chose to open on |
data-mk-default-layout | the Lewis view has two layouts | orthogonal or zigzag: the Lewis layout to open on |
data-mk-view-boxes | with data-mk-has-visual-sets | JSON object mapping a view (or view.layout when a view has two Lewis layouts) to an "x y w h" box in root viewBox space. Set the root viewBox to one box to show only that depiction |
When identity is emitted. The formula, molecular weight, and SMILES attributes are written when the export holds exactly one covalently connected species, an ionic salt whose charges balance to zero, or a resonance set or visual set (one species drawn several times, reported from one depiction). They are never written when any atom is a generic placeholder. Non-covalent bonds (hydrogen bonds, order-0 coordination, dotted bonds) do not join two species into one.
The InChI, InChIKey, and CID attributes come from an online lookup at export time (see PubChem integration). If the export happened offline, or PubChem did not recognize the structure, they are absent. When a PubChem hit disagrees with the drawn formula (for example a radical that PubChem completes with hydrogen), Molkit falls back to a formula search, which returns only a CID and a name, so data-mk-cid can be present without data-mk-inchi.
Species type
data-mk-species-type (mirrored as mk:species-type) is derived from covalent components and their net formal charges:
| Value | Meaning | Example |
|---|---|---|
molecular | one neutral species of mixed elements, including zwitterions; also neutral mixtures | water, glycine |
element | neutral species of one element | O2, S8 |
monatomic-ion | one charged atom | Cl⁻ |
polyatomic-ion | one charged multi-atom species | NO3⁻ |
ionic | two or more components with at least one positive and one negative | NaCl, NH4NO3 |
Per-atom attributes
Every atom group (the element that carries the atom’s data-id, class atom-group) gets its own attribute set. Query atoms with [data-mk-element].
| Attribute | When present | Value and meaning |
|---|---|---|
data-mk-element | always | Element symbol, e.g. N. * for a generic placeholder |
data-mk-x, data-mk-y | non-generic atoms | Atom position |
data-mk-index | non-generic atoms | Zero-based atom index. For a single molecule it matches the MOL block atom order |
data-mk-formal-charge | non-generic atoms | Formal charge computed from bonds and lone pairs; can be 0 or negative |
data-mk-lone-pairs | non-generic atoms | Lone pair count |
data-mk-domains-bonding | non-generic atoms | Bonding electron domains (VSEPR). Includes coordinate bonds to lone ions drawn around a core, so SF6 drawn as four S-F bonds plus two F⁻ reads 6 |
data-mk-domains-nonbonding | non-generic atoms | Nonbonding electron domains (VSEPR) |
data-mk-implicit-h | non-generic atoms | Implicit hydrogen count. Reads 0 when the omit-implicit-H export option was checked |
data-mk-implicit-h-meta | implicit H count above 0 | JSON object describing each implicit H: element, bondedTo, bonds, lonePairs, hybridization (null), formalCharge, valenceElectrons, octet, oxidationState (1, or -1 when bonded to a less electronegative atom such as B or Si) |
data-mk-octet | the octet is defined for this atom | satisfied, deficient, or expanded. Absent for generic placeholders, atoms in a three-center two-electron bridge (bridging H and its bridgeheads), and bare transition-metal ions |
data-mk-valence-electrons | non-generic atoms | Valence electrons contributed by this atom |
data-mk-radical | the atom has unpaired electrons | Number of unpaired electrons, e.g. 1 on the N of NO2 |
data-mk-warnings | non-generic atoms | JSON array of validator warning types: valence, charge, coincident. [] when clean. See the note below |
data-mk-hybridization | the domain count maps to a hybridization | sp, sp2, sp3, sp3d, or sp3d2 |
data-mk-lp-delocalized | with data-mk-hybridization, when a lone pair is delocalized into an adjacent pi bond | "true". The atom reports sp2 although it has four domains. See delocalized lone pairs |
data-mk-geometry | the VSEPR geometry is known | Geometry name, e.g. trigonal planar, trigonal pyramidal, seesaw, square planar |
data-mk-vsepr-angles | with data-mk-geometry | JSON array of reference angles in degrees for that geometry, e.g. [120], [107] for ammonia, [134] for a centre with one unpaired electron and no lone pair (NO2) |
data-mk-chiral | four distinct substituents detected | "true". A heuristic (element and bond order of each neighbour), not a full CIP analysis |
data-mk-isotope | an isotope label is set | Mass number |
data-mk-aromatic | atom in an aromatic ring | "true" |
data-mk-ring-sizes | atom in at least one ring | JSON array of ring sizes, e.g. [6] |
data-mk-oxidation-state | computable | Oxidation state |
data-mk-abbreviation | the atom is drawn with a custom label | The displayed label, e.g. OEt or R |
data-mk-abbreviation-head | the label was decomposed into mk:abbreviations | "true". See condensed labels |
data-mk-oxidation-state-ambiguous | abbreviation heads only, when bonds to like atoms split electrons evenly | "true" |
Warnings on bracketed ions. An ion drawn with neutral atoms and its charge on the bracket does not get a charge warning when the bracket charge agrees with the electrons. The export applies the same bracket check as the app, so the warnings written to the file match what the canvas shows.
Delocalized lone pairs
An N or O with only single bonds, at least one lone pair, and a neighbour that carries a pi bond has its lone pair delocalized into that pi bond.
- An amide nitrogen (neighbour is C=O or C=S) or a nitrogen with two pi-bearing neighbours (pyrrole) reports
sp2,trigonal planar, and[120]. - An oxygen next to a pi bond (acid, ester, phenol) reports
sp2but keeps its measuredbentgeometry and angle.
In both cases data-mk-domains-bonding plus data-mk-domains-nonbonding still totals four, and data-mk-lp-delocalized="true" tells you why the hybridization does not follow the domain count. The atom is not flagged when it is part of a coordinate-bond core.
Generic placeholder atoms
Generic atoms (R, R’, X, Y, Z, A, E, Nu, LG, and the other labels in the generics palette) are stored with element *. The export writes only three attributes on them:
| Attribute | Value |
|---|---|
data-mk-generic | "true" |
data-mk-element | * |
data-mk-abbreviation | the displayed label, e.g. R or X |
No per-atom chemistry is written for a generic atom, because it is undefined by design. A is recognized alongside X and E, so a VSEPR template drawn as AX2E2 is exported as placeholders rather than as a carbon atom. Any generic atom in the export also suppresses the molecule-level identity: there is no formula, SMILES, species type, or MOL block, and mk:chemistry gains mk:indeterminate (text true) and mk:generic-labels (a JSON array of the labels).
Condensed labels
When an atom is drawn with a condensed label that Molkit can parse (CH3, CH2, OCH3, CO2H, and similar), the atom group gets data-mk-abbreviation-head="true", and its per-atom attributes are rewritten from the attach atom of the parsed group and its real bonds, so a CH3 carbon reads sp3 with zero lone pairs. data-mk-geometry and data-mk-vsepr-angles are removed from the head, because the group members carry the real shape. The decomposition itself is in mk:abbreviations.
Per-bond attributes
Bond groups carry the graph topology plus rendered geometry. Query bonds with [data-mk-order].
| Attribute | When present | Value and meaning |
|---|---|---|
data-mk-order | always | Bond order: 1, 2, 3, or 1.5 |
data-mk-atom1, data-mk-atom2 | always | data-id of each endpoint atom |
data-mk-x1, data-mk-y1, data-mk-x2, data-mk-y2 | geometry could be read | Rendered start and end points of the bond line |
data-mk-stereo | non-plain bonds | Drawn bond style, e.g. wedge, dash, wavy, aromatic, dative |
data-mk-polarity | electronegativity difference at or above 0.05 | Pauling electronegativity difference, two decimals |
data-mk-polar-toward | with data-mk-polarity | Element symbol of the more electronegative end |
data-mk-conjugated | bond in a conjugated system | "true" |
data-mk-resonance-order | aromatic bonds | 1.5 |
data-mk-avg-bond-order | bonds in a resonance set whose forms share one skeleton | Average bond order over the non-minor forms, e.g. 1.33 |
data-mk-avg-bond-order-range | the order varies across forms | min-max, e.g. 1-2 |
Resonance and visual-set tags
Resonance sets and visual sets draw one species several times in the same file. Each drawing’s atom groups, bond groups, and decorations (ion brackets, charge labels) are tagged so a consumer can show one drawing at a time.
| Attribute | Appears on | Value and meaning |
|---|---|---|
data-mk-resonance-set | atoms, bonds, decorations of a resonance form | Set id. In a visual set it is setId:view, extended with :layout and :octet when the set has more than one Lewis layout or mixes octet models |
data-mk-resonance-index | same | Form index within the set, as a string |
data-mk-resonance-arrow | resonance arrows | "true" |
data-mk-visual-set | atoms, bonds, decorations, arrows in a visual set | Visual set id |
data-mk-view | same, and mk:conformer-3d | Space-separated list of views this drawing serves, e.g. lewis vsepr for a planar drawing that is both |
data-mk-lewis-layout | Lewis drawings in a set with two layouts, and matching conformers | orthogonal or zigzag |
data-mk-octet-model | drawings in a set that mixes octet models | expanded or strict. Distinct from the per-atom data-mk-octet |
data-mk-resonance-parent | a convenience drawing that stands for several forms | "true" |
data-mk-resonance-parent-kind | with data-mk-resonance-parent | e.g. expanded-octet, aromatic |
data-mk-resonance-note | with data-mk-resonance-parent, when the author wrote one | Free text |
A drawing that is the only form in its view gets data-mk-visual-set and data-mk-view but no resonance tags. Resonance arrows in a visual set get only data-mk-visual-set, data-mk-view, and data-mk-lewis-layout, because they connect forms rather than belong to one.
The metadata element
Deeper data lives in the mk:chemistry element inside the SVG’s metadata element, in the namespace https://molkit.app/ns/chemistry/1.0. Children appear roughly in the order below (PubChem results are appended last), so match them by localName rather than position.
| Element | When present | Content |
|---|---|---|
mk:molkit-version | every export | Molkit version that wrote the file |
mk:created | every export | ISO 8601 timestamp |
mk:url | every export | https://molkit.com |
mk:schema-org | every export | JSON-LD. A Schema.org MolecularEntity when identity is emitted, otherwise a SoftwareApplication block describing Molkit |
mk:author | the document has an author | Text |
mk:common-names | user-entered names, or PubChem synonyms | Comma-separated text as entered; replaced by a JSON array when PubChem synonyms are merged in |
mk:indeterminate, mk:generic-labels | a generic atom is present | true; JSON array of labels |
mk:species-type | as data-mk-species-type | Same value |
mk:common-name | user-set name, or the first PubChem synonym | Text |
mk:pubchem-cid, mk:iupac-name, mk:inchi, mk:inchi-key | from a stored identity or the PubChem lookup | Text |
mk:generic-definitions | R-group definitions exist | One mk:def label atom per generic atom, each holding mk:member display smiles [source] children |
mk:abbreviations | condensed labels were decomposed | One mk:group atom label resolved per labelled atom. A resolved group adds source, attach, mk:member i element x y lone-pairs implicit-h [formal-charge] children, and mk:bond from to order children |
mk:formula, mk:molecular-weight, mk:smiles, mk:canonical-smiles | identity is emitted | As the root attributes |
mk:formula-html | a single molecule | Formula with sub and sup markup |
mk:exact-mass | a single molecule | Monoisotopic mass, four decimals |
mk:atom-count, mk:bond-count, mk:total-valence-electrons, mk:degree-of-unsaturation | a single molecule | Numbers; counts include implicit hydrogens |
mk:element-composition | a single molecule | JSON object of element counts |
mk:point-group, mk:point-group-confidence | a single molecule, when determinable | Schoenflies symbol and a confidence rating |
mk:functional-groups | a single molecule with detected groups | JSON array of group names |
mk:mol-block | a single molecule | V2000 molfile |
mk:conformer-3d, mk:dipole | 3D conformer generation succeeded at export | See 3D conformers and dipoles |
mk:esp | a molecule in the export has a current electrostatic potential map, and the map was not left out | See electrostatic potential maps |
mk:dipole-measured | the species has a reference dipole on file | See measured dipole |
mk:resonance | a resonance set was exported | See resonance and visual-set blocks |
mk:visual-set | a visual set was exported | Same |
“A single molecule” here means a genuine single species. For a resonance set or visual set, only the formula, molecular weight, SMILES, and JSON-LD are written, because the other counts would add up every drawing.
When the author ticks Include editable source, the export also puts an mk:source element next to mk:chemistry inside the metadata element. It carries Molkit’s editable document so the SVG can be reopened in Molkit. It is off by default, it is not chemistry data, and readers should not depend on it; everything a reader needs is in the attributes and elements above.
JSON-LD
The MolecularEntity payload, taken from a real export of ammonia:
{ "@context": "https://schema.org", "@type": "MolecularEntity", "name": "NH3", "molecularFormula": "NH3", "molecularWeight": "17.031", "smiles": "[H]N([H])[H]", "hasRepresentation": { "@type": "ImageObject", "encodingFormat": "image/svg+xml", "creator": { "@type": "SoftwareApplication", "name": "Molkit", "url": "https://molkit.com" } }}When the PubChem lookup succeeds, name becomes the IUPAC name and iupacName, inChI, inChIKey, and identifier (CID:<number>) are added.
3D conformers and dipoles
SVG exports also embed 3D data. Conformer generation runs at export time and is best-effort: if it fails, the file has no conformer block and nothing else changes. When it succeeds, each non-generic species gets one mk:conformer-3d element with generated 3D coordinates, followed by its mk:dipole elements. A consumer can render the 3D model from these without any chemistry library.
<mk:conformer-3d component="0" source="openchemlib" added-h="false" units="angstrom" frame="drawing-aligned" scope="molecule" data-mk-view="lewis" data-mk-conformer-primary="true"> <mk:atoms>C:-0.6980,-0.0000,-0.0000; O:0.6980,-0.0000,-0.0000</mk:atoms> <mk:bonds>0-1:3</mk:bonds></mk:conformer-3d><mk:dipole component="0" method="bond-sum" units="relative" magnitude="0.89" dir="-1,0,0"/>mk:conformer-3d attributes:
| Attribute | Value and meaning |
|---|---|
component | Index that pairs this conformer with the mk:dipole elements carrying the same component. Numbers can skip |
source | Coordinate generator, openchemlib, or adopted when the author made the geometry of an electrostatic potential map the molecule’s 3D structure (exported as it is, with no idealized shape applied). Shapes for a single central atom with bonds and lone pairs (linear, trigonal planar, T-shaped, seesaw, square planar, square pyramidal, octahedral) are the ideal VSEPR shapes |
added-h | true when hydrogens not drawn in 2D were added for the 3D model |
units | angstrom |
frame | drawing-aligned: rotated so the model matches the 2D drawing, x right and y up |
scope | molecule |
data-mk-view, data-mk-lewis-layout | In a visual set, the depiction this conformer was aligned to |
data-mk-conformer-primary | "true" on the conformer whose drawing gives the clearest 3D view (VSEPR first, then angled Lewis, bond-line, square Lewis, condensed, Fischer). Use this one when you show a single 3D model |
mk:atoms is a ; -separated list of Element:x,y,z entries. Drawn atoms come first in drawing order, then any added hydrogens. mk:bonds is a ; -separated list of i-j:order entries using zero-based indexes into mk:atoms, with optional trailing flags: :c marks a coordinate bond (draw it dashed) and :d marks a bond whose order varies across resonance forms (draw it as a partial bond). Parse the order with parseInt and read flags from the remainder.
A resonance form has no separate 3D shape, so a resonance set carries one conformer for the species rather than one per form. In a visual set, conformers aligned to resonance forms are dropped when a non-resonant depiction has one; otherwise the first form of each view keeps its conformer.
mk:dipole attributes:
| Attribute | Value and meaning |
|---|---|
component | Matches a mk:conformer-3d |
method | bond-sum (vector sum of bond dipoles from electronegativity differences) or gasteiger (from Gasteiger partial charges) |
units | relative for bond-sum (electronegativity units, not debye); debye for gasteiger |
magnitude | Three decimals. 0 when below 0.05 |
dir | Unit vector x,y,z in the drawing frame (x right, y down, z out of the page) pointing toward the negative end. 0,0,0 when the magnitude is 0 |
If no bond is polar, no bond-sum element is written for that component, which means a prediction of exactly zero. For carbon monoxide and nitric oxide the direction follows the measured moment (negative end on C and on N), not the electronegativity rule; the matching mk:dipole-measured says so.
Measured dipole
mk:dipole-measured holds the measured gas-phase dipole moment for species in Molkit’s reference table (79 entries, keyed by InChIKey). It appears at most once per file. Its absence means no reference value is on file, not that the moment is zero.
| Attribute | When present | Value and meaning |
|---|---|---|
mu | always | Moment in debye |
units | always | debye |
kind | always | experimental, or symmetry for an exact zero by symmetry with no primary measurement (SF6, Br2, I2, anti-butane). Do not present symmetry values as measurements |
year | known | Measurement year. For entries from the 1967 NSRDS-NBS10 compilation this is an upper bound |
species | always | Species name |
key | always | InChIKey of the reference entry |
matched-by | always | inchi-key (canonical) or name (name match checked against the drawn formula) |
source, doi | known | Citation and DOI |
note | the entry has one | Free text caveat |
negative-end | the measured direction contradicts the electronegativity rule | Element symbol at the negative end: C for carbon monoxide, N for nitric oxide |
departure | with negative-end | Sentence explaining the departure from the rule of thumb |
Only mu === 0 means zero by symmetry. Small nonzero values (propane, 0.084 D) are real.
Electrostatic potential maps
A molecule with an electrostatic potential map gets one mk:esp element next to its mk:conformer-3d, with the same component. The author chooses in the Export SVG dialog whether the map data goes inside the SVG or into a separate .esp file; the description is in the SVG either way. An out-of-date map is never exported.
mk:esp attributes (absent when unknown):
| Attribute | Value and meaning |
|---|---|
component | Matches a mk:conformer-3d |
format | 1 |
program, program-version | The program that computed the potential, e.g. OCC |
method, basis | Level of theory split at the first /: B3LYP and def2-SVP. GFN2-xTB has no basis |
charge, unpaired | Net charge and number of unpaired electrons of the calculation |
phase | gas |
geometry | built (Molkit’s idealized geometry), relaxed, or imported (from cube files) |
geometry-method, geometry-medium | For relaxed: the relax method and program, and gas or water |
date | Date of the calculation, YYYY-MM-DD |
surface | electron density 0.002 e/bohr^3 |
density-source | calculated or free-atom densities |
units | atomic units (hartree per elementary charge) |
grid-step | Grid spacing in angstrom |
fingerprint | 8 hex digits identifying the geometry the map belongs to |
surface-min, surface-max | Lowest and highest potential on the surface, atomic units |
Children:
| Element | Content |
|---|---|
mk:esp-caption | One sentence describing the map, for a caption or a screen reader |
mk:esp-note | Notes from the calculation, when there were any |
mk:esp-citation | One per reference for the program and method |
mk:esp-charges | Per-atom charges in mk:conformer-3d atom order, space-separated, with a kind attribute (CHELPG from OCC). The widget does not show them |
mk:esp-display | The author’s display settings as attributes (scheme, range-mode, fixed, opacity, iso, view, plane, plane-offset, contours), and view-q, the camera rotation as a quaternion x y z w when the map was on in the 3D viewer at export. Starting values only; treat them as untrusted and clamp them |
mk:esp-data | The map file as base64, with encoding="base64", bytes and checksum |
mk:esp-file | Instead of mk:esp-data: href (a relative path, by default esp/<name>-<fingerprint>.esp), bytes and checksum |
The .esp file (embedded or separate) starts with the line MKESP 1, then one line of JSON (the record above, the atoms and the grid shapes), a newline, and the grid data as 16-bit values. checksum is an FNV-1a hash of the whole file in 8 hex digits; a reader must show no map when it does not match. Files are named by content, so a changed geometry gets a new name.
Resonance and visual-set blocks
mk:resonance has attributes set, optional equivalent="true", and optional arrow-ids (comma-separated). It contains one mk:form per form, with index, weight (equivalent, major, or minor), optional dominant="true" (a display flag; it does not change the average), and optional caption.
mk:visual-set has attributes id, default (the default view), views (comma-separated), optional planar="true", and optional primary (view:index or view:parent). It contains one mk:depiction per drawing, with view, optional views (when one drawing serves several views), lewis-layout, octet, index, is-parent, parent-kind, weight, dominant, caption, and provenance attributes generated-by, edited, source-view, source-index, source-layout.
A depiction in the orbitals view is an orbital picture. A group can hold several, and each always has a caption: the author’s own, or All orbitals or Pi system written from the picture’s settings. It also has a box attribute, "x y w h" in root viewBox space, because the lobes reach past the atoms and data-mk-view-boxes holds only the union of all pictures.
Both blocks can contain mk:bond-order summaries, one per bond type, when the forms share one skeleton: elements (space-separated pair, e.g. N O), order (average), optional range (min-max), basis (non-minor or all), and in a visual set group (the view key the average belongs to).
Extracting the MOL block
The mk:mol-block element holds a complete V2000 molfile as text, ready for RDKit.js, OpenBabel, or any MOL-aware tool. Y coordinates are flipped relative to the SVG (chemistry convention is Y-up, SVG is Y-down). Match metadata children by localName, which ignores the namespace prefix and works in every browser:
function getMolBlock(svg) { const meta = svg.querySelector('metadata'); if (!meta) return null; const chem = [...meta.children].find(el => el.localName === 'chemistry'); const mol = chem && [...chem.children].find(el => el.localName === 'mol-block'); return mol ? mol.textContent : null;}Reading the molecule graph
The atom and bond attributes together form a complete graph. This parser builds an adjacency structure for highlighting, tooltips, or analysis. It works against an inlined export (see embedding):
function parseGraph(svg) { const atoms = new Map(); const int = (g, name) => { const v = g.getAttribute(name); return v == null ? null : parseInt(v, 10); };
for (const g of svg.querySelectorAll('[data-mk-element]')) { const id = g.getAttribute('data-id'); const generic = g.getAttribute('data-mk-generic') === 'true'; atoms.set(id, { id, generic, element: g.getAttribute('data-mk-element'), // "*" for a generic label: g.getAttribute('data-mk-abbreviation'), // "R", "OEt", or null charge: int(g, 'data-mk-formal-charge'), // null on generics lonePairs: int(g, 'data-mk-lone-pairs'), implicitH: int(g, 'data-mk-implicit-h'), hybridization: g.getAttribute('data-mk-hybridization'), ringSizes: JSON.parse(g.getAttribute('data-mk-ring-sizes') ?? '[]'), neighbors: [], node: g, // keep the live element for styling }); }
const bonds = []; for (const g of svg.querySelectorAll('[data-mk-order]')) { const bond = { order: parseFloat(g.getAttribute('data-mk-order')), atom1: g.getAttribute('data-mk-atom1'), atom2: g.getAttribute('data-mk-atom2'), stereo: g.getAttribute('data-mk-stereo'), // null for plain bonds node: g, }; bonds.push(bond); atoms.get(bond.atom1)?.neighbors.push(bond.atom2); atoms.get(bond.atom2)?.neighbors.push(bond.atom1); }
return { atoms, bonds };}In a resonance set or visual set the same species appears once per drawing, so the graph has several disconnected copies. Filter by data-mk-resonance-index or data-mk-view to work with one.
Gotchas
- Conditional attributes need null-guards. Decide on a default before parsing.
data-mk-octetin particular is absent where the octet is undefined; do not read absence assatisfied. - Never use logical-or fallbacks on numeric reads. Zero is a valid value for
data-mk-formal-charge,data-mk-lone-pairs,data-mk-implicit-h, anddata-mk-oxidation-state. Use??after parsing, not||. - Generic atoms carry almost nothing. Check
data-mk-genericbefore reading coordinates, charge, or index; they are absent on generics. - JSON attributes need
JSON.parse.data-mk-vsepr-angles,data-mk-ring-sizes,data-mk-warnings,data-mk-implicit-h-meta, anddata-mk-view-boxes. - Hybridization does not always follow the domain count. Check
data-mk-lp-delocalizedbefore explainingsp2from four domains. - Identity fields can be missing on a valid export. Multi-species drawings, unbalanced ion mixtures, and anything with a generic atom have no formula, SMILES, or MOL block. Per-atom and per-bond attributes are still present.
- Atom IDs are opaque strings. Do not parse them. Match bonds to atoms by comparing
data-mk-atom1anddata-mk-atom2against each atom group’sdata-id. - The bond-sum dipole is not in debye. Use
mk:dipole-measuredfor a number in debye; thegasteigerrecord is in debye but is a model value. - PubChem fields are best-effort.
data-mk-inchi,data-mk-inchi-key,data-mk-cid, and the IUPAC name exist only when the lookup succeeded online. - The omit-implicit-H export option only blanks one attribute. With it checked, every
data-mk-implicit-hreads 0 anddata-mk-implicit-h-metais dropped. Formula, molecular weight, atom count, and total valence electrons always include implicit hydrogens. - Re-export files made with older builds. Earlier exporters wrote
data-mk-octet="expanded"on generics and bridging hydrogens, stamped charge warnings on correctly bracketed ions, wrote dipole directions that depended on how a free O-H was drawn, and had implicit-hydrogen accounting bugs. Treat old files as suspect and re-export.