Para crear el objeto anidado exacto que desea, usaremos una combinación de JavaScript puro y un método D3 llamado d3.stratify
. Sin embargo, tenga en cuenta que 7 millones de filas (consulte el post scriptum a continuación) es mucho para calcular.
Es muy importante mencionar que, para esta solución propuesta, tendrá que separar los Reinos en diferentes matrices de datos (por ejemplo, usando Array.prototype.filter
). Esta restricción ocurre porque necesitamos un nodo raíz, y en la taxonomía linneana no hay relación entre reinos (a menos que cree "Dominio" como rango superior, que será la raíz para todos los eucariotas, pero entonces tendrás la misma problema para Archaea y Bacteria).
Entonces, supongamos que tiene este CSV (agregué algunas filas más) con solo un Reino:
RecordID,kingdom,phylum,class,order,family,genus,species
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis latrans
3,Animalia,Chordata,Mammalia,Cetacea,Delphinidae,Tursiops,Tursiops truncatus
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Pan,Pan paniscus
Basado en ese CSV, crearemos una matriz aquí tableOfRelationships
que, como su nombre lo indica, tiene las relaciones entre los rangos:
const data = d3.csvParse(csv);
const taxonomicRanks = data.columns.filter(d => d !== "RecordID");
const tableOfRelationships = [];
data.forEach(row => {
taxonomicRanks.forEach((d, i) => {
if (!tableOfRelationships.find(e => e.name === row[d])) tableOfRelationships.push({
name: row[d],
parent: row[taxonomicRanks[i - 1]] || null
})
})
});
Para los datos anteriores, este es el tableOfRelationships
:
+---------+----------------------+---------------+
| (Index) | name | parent |
+---------+----------------------+---------------+
| 0 | "Animalia" | null |
| 1 | "Chordata" | "Animalia" |
| 2 | "Mammalia" | "Chordata" |
| 3 | "Primates" | "Mammalia" |
| 4 | "Hominidae" | "Primates" |
| 5 | "Homo" | "Hominidae" |
| 6 | "Homo sapiens" | "Homo" |
| 7 | "Carnivora" | "Mammalia" |
| 8 | "Canidae" | "Carnivora" |
| 9 | "Canis" | "Canidae" |
| 10 | "Canis latrans" | "Canis" |
| 11 | "Cetacea" | "Mammalia" |
| 12 | "Delphinidae" | "Cetacea" |
| 13 | "Tursiops" | "Delphinidae" |
| 14 | "Tursiops truncatus" | "Tursiops" |
| 15 | "Pan" | "Hominidae" |
| 16 | "Pan paniscus" | "Pan" |
+---------+----------------------+---------------+
Eche un vistazo null
como padre de Animalia
: es por eso que le dije que necesita separar su conjunto de datos por Reinos, solo puede haber un null
valor en toda la tabla.
Finalmente, en base a esa tabla, creamos la jerarquía usando d3.stratify()
:
const stratify = d3.stratify()
.id(function(d) { return d.name; })
.parentId(function(d) { return d.parent; });
const hierarchicalData = stratify(tableOfRelationships);
Y aquí está la demo. Abra la consola de su navegador (la del fragmento no es muy buena para esta tarea) e inspeccione los varios niveles ( children
) del objeto:
const csv = `RecordID,kingdom,phylum,class,order,family,genus,species
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis latrans
3,Animalia,Chordata,Mammalia,Cetacea,Delphinidae,Tursiops,Tursiops truncatus
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Pan,Pan paniscus`;
const data = d3.csvParse(csv);
const taxonomicRanks = data.columns.filter(d => d !== "RecordID");
const tableOfRelationships = [];
data.forEach(row => {
taxonomicRanks.forEach((d, i) => {
if (!tableOfRelationships.find(e => e.name === row[d])) tableOfRelationships.push({
name: row[d],
parent: row[taxonomicRanks[i - 1]] || null
})
})
});
const stratify = d3.stratify()
.id(function(d) {
return d.name;
})
.parentId(function(d) {
return d.parent;
});
const hierarchicalData = stratify(tableOfRelationships);
console.log(hierarchicalData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
PD : No sé qué tipo de dataviz crearás, pero realmente deberías evitar los rangos taxonómicos. Toda la taxonomía linneana está desactualizada, ya no usamos rangos: dado que la sistemática filogenética se desarrolló a mediados de los años 60, usamos solo taxones, sin ningún rango taxonómico (profesor de biología evolutiva aquí). Además, tengo bastante curiosidad acerca de estos 7 millones de filas, ¡ya que hemos descrito poco más de 1 millón de especies!
nan
para el Filo que contiene Magnoliopsida. ¿Qué es esonan
? El Phylum es Anthophyta, o alternativamente Magnolia (es el antiguo Phylum Angiospermae).