logo Netzschleuder network catalog, repository, and centrifuge

History of lotus_natural_products

The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.

[entries] Add the date when each entry was added, and remove icon_hash by Tiago de Paula Peixoto beff7c9
The dates are those of the commits that first added the entries' files
(2020-08-11 for the entries of the initial commit); renamed entries keep
the date of their first name.

Changed: none
diff --git a/entries/lotus_natural_products/__init__.py b/entries/lotus_natural_products/__init__.py
index 1e06a56..410e4d5 100644
--- a/entries/lotus_natural_products/__init__.py
+++ b/entries/lotus_natural_products/__init__.py
@@ -90,7 +90,7 @@ url = ['https://lotus.naturalproducts.net/', 'https://doi.org/10.5281/zenodo.579
        'https://doi.org/10.5281/zenodo.5665294']
 citation = [('A. Rutz, M. Sorokina, J. Galgonek, D. Mietchen, E. Willighagen, A. Gaudry, J. G. Graham, R. Stephan, R. Page, J. Vondrášek, C. Steinbeck, G. F. Pauli, J.-L. Wolfender, J. Bisson, P.-M. Allard, "The LOTUS initiative for open knowledge management in natural products research." eLife 11, e70780 (2022)',
              'https://doi.org/10.7554/eLife.70780')]
-icon_hash = None
+date_added = '2026-10-31'
 upstream_license = ('Creative Commons Attribution 4.0 International (CC BY 4.0)',
                     'https://creativecommons.org/licenses/by/4.0/')
 upstream_prefix = 'https://zenodo.org/records'
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) by Tiago de Paula Peixoto bc3dbbd
The lists of properties at the end of the descriptions marked edge
properties with "Edge" but left node properties unmarked, or grouped
them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property
was often unclear. Every item now starts with (Node), (Edge) or (Graph),
followed by the property names, a colon and the explanation, one item
per property or group of properties; qualifications (kinds of nodes,
networks) follow the names in parentheses. Properties that were only
named got a short explanation, and a few items that named the wrong
kind of property were corrected.
diff --git a/entries/lotus_natural_products/__init__.py b/entries/lotus_natural_products/__init__.py
index c2181be..1e06a56 100644
--- a/entries/lotus_natural_products/__init__.py
+++ b/entries/lotus_natural_products/__init__.py
@@ -65,26 +65,26 @@ description = r"""Bipartite networks of natural products (chemical structures) a
 
 The networks have the following properties (structure properties are empty for organisms, and vice versa; not all of them are in every export):
 
-- `is_structure`: whether the node is a chemical structure (otherwise it is an organism).
-- `wikidata` (exports): the Wikidata item of the structure or organism.
-- `name`: the traditional name of the structure (its InChIKey if it has none, and in the export of 2021-12-20, which has no names of structures), or the name of the organism.
-- `structure_inchikey`, `structure_inchi`, `structure_smiles`, `structure_smiles_2d`, `structure_molecular_formula`: the identifiers and formula of the structure (InChIKey, InChI, isomeric SMILES, SMILES without stereochemistry; no formula in `processed_2021_05_28`).
-- `structure_inchikey_2d`, `structure_inchi_2d` (`processed_*`): the InChIKey and InChI of the structure without stereochemistry.
-- `structure_exact_mass`, `structure_xlogp`: the exact mass and the computed partition coefficient of the structure (NaN if not given).
-- `structure_cid`: the PubChem compound identifier of the structure (not in the processed datasets before `processed_2023_01_13`).
-- `structure_name_iupac`: the IUPAC name of the structure.
-- `structure_stereocenters_total`, `structure_stereocenters_unspecified`: the numbers of stereocenters of the structure, and of those whose configuration is not specified.
-- `structure_taxonomy_npclassifier_01pathway`, `..._02superclass`, `..._03class`: the chemical classification of the structure by NPClassifier.
-- `structure_taxonomy_classyfire_chemontid`, `..._01kingdom`, `..._02superclass`, `..._03class`, `..._04directparent`: the chemical classification of the structure by ClassyFire.
-- `organism_taxonomy_gbifid`, `organism_taxonomy_ncbiid`, `organism_taxonomy_ottid`: the identifiers of the organism in GBIF, the NCBI taxonomy and the Open Tree of Life.
-- `organism_taxonomy_01domain`, `..._02kingdom`, `..._03phylum`, `..._04class`, `..._05order`, `..._06family`, `..._07tribe`, `..._08genus`, `..._09species`, `..._10varietas`: the taxonomy of the organism (exports).
-- `organism_id`, `organism_db_taxo`, `organism_taxon_ranks`, `organism_taxonomy` (`processed_*`): the identifier of the organism in its taxonomic database, the name of the database, and the ranks and names of its lineage.
-- Edge `reference_wikidata`, `reference_doi` (exports): the Wikidata item and DOI of the reference.
-- Edge `manual_validation` (exports): the result of the manual validation of the pair (`Y` if it was validated by hand, empty otherwise).
-- Edge `database` (`processed_*`): the source database of the pair.
-- Edge `organism_original`, `reference_original` (`processed_*`): the organism and reference as given by the source database (the structures as given by the source databases, as InChI or SMILES strings, are left out, since they are long and the curated structure is given by the node).
-- Edge `structure_original_type`, `reference_original_type` (`processed_*`): the kind of the structure and reference identifiers of the source database (e.g. `inchi`, `smiles`, `doi`, `pubmed`, `title`).
-- Edge `reference_doi`, `reference_pmcid`, `reference_pmid`, `reference_title` (`processed_*`): the curated reference."""
+- (Node) `is_structure`: whether the node is a chemical structure (otherwise it is an organism).
+- (Node) `wikidata` (exports): the Wikidata item of the structure or organism.
+- (Node) `name`: the traditional name of the structure (its InChIKey if it has none, and in the export of 2021-12-20, which has no names of structures), or the name of the organism.
+- (Node) `structure_inchikey`, `structure_inchi`, `structure_smiles`, `structure_smiles_2d`, `structure_molecular_formula`: the identifiers and formula of the structure (InChIKey, InChI, isomeric SMILES, SMILES without stereochemistry; no formula in `processed_2021_05_28`).
+- (Node) `structure_inchikey_2d`, `structure_inchi_2d` (`processed_*`): the InChIKey and InChI of the structure without stereochemistry.
+- (Node) `structure_exact_mass`, `structure_xlogp`: the exact mass and the computed partition coefficient of the structure (NaN if not given).
+- (Node) `structure_cid`: the PubChem compound identifier of the structure (not in the processed datasets before `processed_2023_01_13`).
+- (Node) `structure_name_iupac`: the IUPAC name of the structure.
+- (Node) `structure_stereocenters_total`, `structure_stereocenters_unspecified`: the numbers of stereocenters of the structure, and of those whose configuration is not specified.
+- (Node) `structure_taxonomy_npclassifier_01pathway`, `..._02superclass`, `..._03class`: the chemical classification of the structure by NPClassifier.
+- (Node) `structure_taxonomy_classyfire_chemontid`, `..._01kingdom`, `..._02superclass`, `..._03class`, `..._04directparent`: the chemical classification of the structure by ClassyFire.
+- (Node) `organism_taxonomy_gbifid`, `organism_taxonomy_ncbiid`, `organism_taxonomy_ottid`: the identifiers of the organism in GBIF, the NCBI taxonomy and the Open Tree of Life.
+- (Node) `organism_taxonomy_01domain`, `..._02kingdom`, `..._03phylum`, `..._04class`, `..._05order`, `..._06family`, `..._07tribe`, `..._08genus`, `..._09species`, `..._10varietas`: the taxonomy of the organism (exports).
+- (Node) `organism_id`, `organism_db_taxo`, `organism_taxon_ranks`, `organism_taxonomy` (`processed_*`): the identifier of the organism in its taxonomic database, the name of the database, and the ranks and names of its lineage.
+- (Edge) `reference_wikidata`, `reference_doi` (exports): the Wikidata item and DOI of the reference.
+- (Edge) `manual_validation` (exports): the result of the manual validation of the pair (`Y` if it was validated by hand, empty otherwise).
+- (Edge) `database` (`processed_*`): the source database of the pair.
+- (Edge) `organism_original`, `reference_original` (`processed_*`): the organism and reference as given by the source database (the structures as given by the source databases, as InChI or SMILES strings, are left out, since they are long and the curated structure is given by the node).
+- (Edge) `structure_original_type`, `reference_original_type` (`processed_*`): the kind of the structure and reference identifiers of the source database (e.g. `inchi`, `smiles`, `doi`, `pubmed`, `title`).
+- (Edge) `reference_doi`, `reference_pmcid`, `reference_pmid`, `reference_title` (`processed_*`): the curated reference."""
 tags = ['Biological', 'Chemical', 'Unweighted', 'Bipartite', 'Multigraph', 'Metadata']
 url = ['https://lotus.naturalproducts.net/', 'https://doi.org/10.5281/zenodo.5794106',
        'https://doi.org/10.5281/zenodo.5665294']
[entries] New entry: lotus_natural_products by Tiago de Paula Peixoto acf4c48
diff --git a/entries/lotus_natural_products/__init__.py b/entries/lotus_natural_products/__init__.py
new file mode 100644
index 0000000..c2181be
--- /dev/null
+++ b/entries/lotus_natural_products/__init__.py
@@ -0,0 +1,254 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import csv
+import re
+import io
+import math
+from collections import defaultdict
+
+from .. import *
+
+# The exports of LOTUS from Wikidata on Zenodo (concept record 5794106): one
+# network per distinct export (the export of 2022-02-08 was published three
+# times, with the same pairs and updated metadata; the last record is used).
+# Only the *_frozen_metadata.csv.gz files are used: they contain the same
+# rows as the *_frozen.csv.gz files, with the metadata of the structures and
+# organisms.
+EXPORTS = {
+    "2021_12_20": ("5794107", "211220"),
+    "2022_02_08": ("6277266", "220208"),
+    "2022_02_26": ("6299673", "220226"),
+    "2022_03_18": ("6378204", "220318"),
+    "2022_05_25": ("6582124", "220525"),
+    "2022_07_01": ("6786314", "220701"),
+    "2022_09_16": ("7085063", "220916"),
+    "2023_01_06": ("7534071", "230106"),
+    "2026_04_13": ("19360665", "260413"),
+}
+# The datasets of the curated pairs of the LOTUS processing pipeline, with
+# the source databases (concept record 5665294): all its versions, named by
+# their publication dates, except the last one, which has the same
+# publication date as the previous one (2022-09-16) and is named by its
+# creation date (2023-01-13). (All seven files differ.)
+PAIRS = "validated_referenced_structure_organism_pairs.tsv.gz"
+PROCESSED = {
+    "processed_2021_05_28": ("5665295", "documented_pairs.tsv.gz"),
+    "processed_2021_12_20": ("5793668", PAIRS),
+    "processed_2022_03_23": ("6378193", PAIRS),
+    "processed_2022_05_25": ("6582121", PAIRS),
+    "processed_2022_07_01": ("6786337", PAIRS),
+    "processed_2022_09_16": ("7085066", PAIRS),
+    "processed_2023_01_13": ("7534062", PAIRS),
+}
+
+title = "LOTUS natural products and the organisms they occur in (2021-2026)"
+description = r"""Bipartite networks of natural products (chemical structures) and the organisms in which they were found, from LOTUS, an open resource of structure-organism pairs documented in the literature, compiled from about 40 natural-product databases, curated, and shared through Wikidata, where the community can edit and extend it. Each structure-organism pair is supported by a reference (an article or book).
+
+- `2021_12_20` ... `2026_04_13`: the exports of the LOTUS data from Wikidata (the "frozen" datasets), one network per export: 2021-12-20, 2022-02-08, 2022-02-26, 2022-03-18, 2022-05-25, 2022-07-01, 2022-09-16, 2023-01-06 and 2026-04-13. Nodes are structures (Wikidata items with an InChIKey) and organisms (Wikidata taxa), and there is an edge between a structure and an organism for each reference that documents that the structure is found in (or produced by) the organism, so that a pair can be connected by several edges. Structures and organisms are identified by their Wikidata items. The exports have a row for each combination of the values of the properties that have several values (e.g. an organism with two GBIF identifiers); the edges are the distinct (structure, organism, reference) triples, and the several values of a property are joined with `|`.
+- `processed_2021_05_28`, `processed_2021_12_20`, `processed_2022_03_23`, `processed_2022_05_25`, `processed_2022_07_01`, `processed_2022_09_16`, `processed_2023_01_13`: the curated structure-organism pairs of the processing pipeline of LOTUS (the datasets from which the data of Wikidata were built), all the versions of the dataset on Zenodo, named by their publication dates (the last one, published with the same date as the previous one, by its creation date), where each edge is a documented pair as given by one of the source databases, so that a pair documented by several databases or references is connected by several edges. Nodes are structures (identified by their InChIKey) and organisms (by their cleaned name).
+
+The networks have the following properties (structure properties are empty for organisms, and vice versa; not all of them are in every export):
+
+- `is_structure`: whether the node is a chemical structure (otherwise it is an organism).
+- `wikidata` (exports): the Wikidata item of the structure or organism.
+- `name`: the traditional name of the structure (its InChIKey if it has none, and in the export of 2021-12-20, which has no names of structures), or the name of the organism.
+- `structure_inchikey`, `structure_inchi`, `structure_smiles`, `structure_smiles_2d`, `structure_molecular_formula`: the identifiers and formula of the structure (InChIKey, InChI, isomeric SMILES, SMILES without stereochemistry; no formula in `processed_2021_05_28`).
+- `structure_inchikey_2d`, `structure_inchi_2d` (`processed_*`): the InChIKey and InChI of the structure without stereochemistry.
+- `structure_exact_mass`, `structure_xlogp`: the exact mass and the computed partition coefficient of the structure (NaN if not given).
+- `structure_cid`: the PubChem compound identifier of the structure (not in the processed datasets before `processed_2023_01_13`).
+- `structure_name_iupac`: the IUPAC name of the structure.
+- `structure_stereocenters_total`, `structure_stereocenters_unspecified`: the numbers of stereocenters of the structure, and of those whose configuration is not specified.
+- `structure_taxonomy_npclassifier_01pathway`, `..._02superclass`, `..._03class`: the chemical classification of the structure by NPClassifier.
+- `structure_taxonomy_classyfire_chemontid`, `..._01kingdom`, `..._02superclass`, `..._03class`, `..._04directparent`: the chemical classification of the structure by ClassyFire.
+- `organism_taxonomy_gbifid`, `organism_taxonomy_ncbiid`, `organism_taxonomy_ottid`: the identifiers of the organism in GBIF, the NCBI taxonomy and the Open Tree of Life.
+- `organism_taxonomy_01domain`, `..._02kingdom`, `..._03phylum`, `..._04class`, `..._05order`, `..._06family`, `..._07tribe`, `..._08genus`, `..._09species`, `..._10varietas`: the taxonomy of the organism (exports).
+- `organism_id`, `organism_db_taxo`, `organism_taxon_ranks`, `organism_taxonomy` (`processed_*`): the identifier of the organism in its taxonomic database, the name of the database, and the ranks and names of its lineage.
+- Edge `reference_wikidata`, `reference_doi` (exports): the Wikidata item and DOI of the reference.
+- Edge `manual_validation` (exports): the result of the manual validation of the pair (`Y` if it was validated by hand, empty otherwise).
+- Edge `database` (`processed_*`): the source database of the pair.
+- Edge `organism_original`, `reference_original` (`processed_*`): the organism and reference as given by the source database (the structures as given by the source databases, as InChI or SMILES strings, are left out, since they are long and the curated structure is given by the node).
+- Edge `structure_original_type`, `reference_original_type` (`processed_*`): the kind of the structure and reference identifiers of the source database (e.g. `inchi`, `smiles`, `doi`, `pubmed`, `title`).
+- Edge `reference_doi`, `reference_pmcid`, `reference_pmid`, `reference_title` (`processed_*`): the curated reference."""
+tags = ['Biological', 'Chemical', 'Unweighted', 'Bipartite', 'Multigraph', 'Metadata']
+url = ['https://lotus.naturalproducts.net/', 'https://doi.org/10.5281/zenodo.5794106',
+       'https://doi.org/10.5281/zenodo.5665294']
+citation = [('A. Rutz, M. Sorokina, J. Galgonek, D. Mietchen, E. Willighagen, A. Gaudry, J. G. Graham, R. Stephan, R. Page, J. Vondrášek, C. Steinbeck, G. F. Pauli, J.-L. Wolfender, J. Bisson, P.-M. Allard, "The LOTUS initiative for open knowledge management in natural products research." eLife 11, e70780 (2022)',
+             'https://doi.org/10.7554/eLife.70780')]
+icon_hash = None
+upstream_license = ('Creative Commons Attribution 4.0 International (CC BY 4.0)',
+                    'https://creativecommons.org/licenses/by/4.0/')
+upstream_prefix = 'https://zenodo.org/records'
+files = [(f"{rec}/files/{date}_frozen_metadata.csv.gz", alt, None)
+         for alt, (rec, date) in EXPORTS.items()] + \
+        [(f"{rec}/files/{fname}", alt, None) for alt, (rec, fname) in PROCESSED.items()]
+
+def fetch_upstream(force=False):
+    return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+                                force)
+
+_check_rows = None
+
+NUMERIC = {"structure_exact_mass", "structure_xlogp",
+           "structure_stereocenters_total", "structure_stereocenters_unspecified"}
+
+def snake(c):
+    "Column names in lower case (e.g. structure_nameIupac -> structure_name_iupac)."
+    return re.sub(r"(?<=[a-z0-9])([A-Z])", r"_\1", c).lower()
+
+def to_float(x):
+    try:
+        return float(x)
+    except ValueError:
+        return math.nan
+
+# columns of the processed dataset, and their property names
+PROC_STRUCTURE = {"structureCleanedInchikey": "structure_inchikey",
+                  "structureCleanedInchi": "structure_inchi",
+                  "structureCleanedSmiles": "structure_smiles",
+                  "structureCleaned_smiles2D": "structure_smiles_2d",
+                  "structureCleaned_inchikey2D": "structure_inchikey_2d",
+                  "structureCleaned_inchi2D": "structure_inchi_2d",
+                  "structureCleaned_molecularFormula": "structure_molecular_formula",
+                  "structureCleaned_cid": "structure_cid",
+                  "structureCleaned_nameIupac": "structure_name_iupac",
+                  "structureCleaned_stereocenters_total": "structure_stereocenters_total",
+                  "structureCleaned_stereocenters_unspecified": "structure_stereocenters_unspecified"}
+PROC_ORGANISM = {"organismCleaned_id": "organism_id",
+                 "organismCleaned_dbTaxo": "organism_db_taxo",
+                 "organismCleaned_dbTaxoTaxonRanks": "organism_taxon_ranks",
+                 "organismCleaned_dbTaxoTaxonomy": "organism_taxonomy"}
+PROC_EDGE = {"database": "database", "organismValue": "organism_original",
+             "structureType": "structure_original_type",
+             "referenceType": "reference_original_type",
+             "referenceValue": "reference_original",
+             "referenceCleanedDoi": "reference_doi",
+             "referenceCleanedPmcid": "reference_pmcid",
+             "referenceCleanedPmid": "reference_pmid",
+             "referenceCleanedTitle": "reference_title"}
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+    name = __name__.split(".")[-1]
+    for fname, alt, fmt in files:
+        if alts is not None and alt not in alts:
+            continue
+        processed = alt.startswith("processed")
+        with open_upstream_file(name, fname, "rb") as fz:
+            f = io.TextIOWrapper(fz, encoding="utf8", newline="")
+            reader = csv.reader(f, delimiter="\t" if processed else ",")
+            header = next(reader)
+            col = {c: i for i, c in enumerate(header)}
+            if processed:
+                s_cols = PROC_STRUCTURE
+                o_cols = PROC_ORGANISM
+                e_cols = PROC_EDGE
+                s_key, o_key = "structureCleanedInchikey", "organismCleaned"
+                s_name, o_name = "structureCleaned_nameTraditional", "organismCleaned"
+            else:
+                s_cols = {c: snake(c) for c in header if c.startswith("structure_")
+                          and c not in ("structure_wikidata", "structure_nameTraditional")}
+                o_cols = {c: snake(c) for c in header if c.startswith("organism_")
+                          and c not in ("organism_wikidata", "organism_name")}
+                e_cols = {c: c for c in ("reference_wikidata", "reference_doi",
+                                         "manual_validation")}
+                s_key, o_key = "structure_wikidata", "organism_wikidata"
+                s_name, o_name = "structure_nameTraditional", "organism_name"
+            if processed:
+                # (the earlier versions lack some columns of the structures:
+                # the formula until 2021-12-20, the PubChem CID until
+                # 2022-09-16)
+                s_cols = {c: p for c, p in s_cols.items() if c in col}
+            for c in list(s_cols) + list(o_cols) + list(e_cols) + [s_key, o_key, o_name]:
+                assert c in col, (alt, c)
+            vprops = sorted(set(s_cols.values()) | set(o_cols.values()),
+                            key=lambda p: (not p.startswith("structure"), p))
+            vidx = {}
+            vvals = defaultdict(list)
+            def add_vertex(key, is_s, row, cols, nm):
+                v = vidx.get((is_s, key))
+                if v is not None:
+                    # the exports repeat a row for each value of a property
+                    # with several values (e.g. two GBIF identifiers of an
+                    # organism): the values are joined with "|"
+                    if not processed:
+                        for c, p in cols.items():
+                            x = row[col[c]]
+                            old = vvals[p][v]
+                            if x != old and p not in NUMERIC and \
+                               x not in old.split("|"):
+                                vvals[p][v] = f"{old}|{x}"
+                    return v
+                v = vidx[(is_s, key)] = len(vidx)
+                vvals["is_structure"].append(is_s)
+                if not processed:
+                    vvals["wikidata"].append(key.removeprefix("http://www.wikidata.org/entity/"))
+                # (the first export has no names of structures)
+                n = row[col[nm]] if nm in col else ""
+                if is_s and n in ("", "NA"):
+                    n = row[col["structureCleanedInchikey" if processed else "structure_inchikey"]]
+                vvals["name"].append(n)
+                for p in vprops:
+                    vvals[p].append(None)
+                for c, p in cols.items():
+                    vvals[p][-1] = row[col[c]]
+                return v
+            edges = []
+            evals = defaultdict(list)
+            strings = {}
+            seen = set()
+            for i, row in enumerate(reader):
+                if _check_rows is not None and i >= _check_rows:
+                    break
+                if len(row) != len(header):
+                    raise ValueError(f"{alt}: malformed row {i}: {row[:3]}")
+                s = add_vertex(row[col[s_key]], True, row, s_cols, s_name)
+                o = add_vertex(row[col[o_key]], False, row, o_cols, o_name)
+                if not processed:
+                    # one edge per (structure, organism, reference)
+                    k = (s, o, row[col["reference_wikidata"]])
+                    if k in seen:
+                        continue
+                    seen.add(k)
+                edges.append((s, o))
+                for c, p in e_cols.items():
+                    x = row[col[c]]
+                    if x == "NA":
+                        x = ""
+                    # repeated values (references, databases) are shared
+                    evals[p].append(strings.setdefault(x, x))
+
+        g = Graph(directed=False)
+        g.add_vertex(len(vidx))
+        g.add_edge_list(numpy.array(edges, dtype="int64").reshape(-1, 2))
+        g.vp.is_structure = g.new_vp("bool", vals=vvals["is_structure"])
+        if not processed:
+            g.vp.wikidata = g.new_vp("string", vals=vvals["wikidata"])
+        g.vp.name = g.new_vp("string", vals=vvals["name"])
+        for p in vprops:
+            if p in NUMERIC:
+                g.vp[p] = g.new_vp("double", vals=[math.nan if x is None else to_float(x)
+                                                   for x in vvals[p]])
+            else:
+                g.vp[p] = g.new_vp("string", vals=["" if x is None or x == "NA" else x
+                                                   for x in vvals[p]])
+        for p, vals in evals.items():
+            g.ep[p] = g.new_ep("string", vals=vals)
+        yield alt, g