Mercurial > code > home > repos > streamed-graph
view src/tabulate.ts @ 94:a5f53d397526
view: pick types to show at top-level
author | drewp@bigasterisk.com |
---|---|
date | Wed, 12 Jan 2022 22:09:20 -0800 |
parents | ac7ad087d474 |
children | 26c55d5d5202 |
line wrap: on
line source
// Organize graph data into tables (column orders, etc) for the view layer. import Immutable from "immutable"; // mostly using this for the builtin equals() testing, since NamedNode(x)!=NamedNode(x) import { DataFactory, NamedNode, Quad, Quad_Object, Store, Term, Util, } from "n3"; const { namedNode } = DataFactory; // // import ns from 'n3/src/IRIs'; // // const { rdf } = ns; export const rdf = { type: namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), }; type UriSet = Immutable.Set<NamedNode>; export type TypeToSubjs = Immutable.Map<NamedNode, UriSet>; // https://github.com/rdfjs/N3.js/issues/265 if ((NamedNode.prototype as any).hashCode === undefined) { (NamedNode.prototype as any).hashCode = () => 0; } function getType(graph: Store, subj: NamedNode): NamedNode | null { let subjType: NamedNode | null = null; graph.forObjects( (o: Quad_Object) => { subjType = o as NamedNode; }, subj, rdf.type, null ); return subjType; } // When there are multiple types, an arbitrary one is used. export function groupByRdfType( graph: Store ): { byType: TypeToSubjs; typesPresent: NamedNode[]; untypedSubjs: NamedNode[] } { let byType: TypeToSubjs = Immutable.Map(); let untyped: UriSet = Immutable.Set(); // subjs const internSubjs = new Map<string, NamedNode>(); graph.forEach( (q) => { if (!Util.isNamedNode(q.subject)) { throw new Error("unsupported " + q.subject.value); } const subj = q.subject as NamedNode; const subjType = getType(graph, subj); if (subjType !== null) { // (subj, rdf:type, subjType) in graph const oldKeys = Array.from(byType.keys()); const oldVal = byType.get(subjType, Immutable.Set<NamedNode>()); const newVal = oldVal.add(subj); byType = byType.set(subjType, newVal); } else { untyped = untyped.add(subj); } }, null, null, null, null ); const typesPresent = Array.from(byType.keys()); typesPresent.sort(); const untypedSubjs = Array.from(untyped.values()); untypedSubjs.sort(); return { byType: byType, typesPresent: typesPresent, untypedSubjs: untypedSubjs }; } export function predsForSubj(graph: Store, typeUri: NamedNode): NamedNode[] { const predsSet: Set<NamedNode> = new Set(); graph.forEach( (q: Quad) => { predsSet.add(q.predicate as NamedNode); }, typeUri, null, null, null ); const preds = Array.from(predsSet.values()); preds.sort(); return preds; } interface ISP { subj: NamedNode; pred: NamedNode; } const SP = Immutable.Record<ISP>({ subj: new NamedNode(""), pred: new NamedNode(""), }); export class MultiSubjsTypeBlockLayout { subjs: NamedNode[]; preds: NamedNode[]; graphCells: Immutable.Map<ISP, Immutable.Set<Term>>; constructor(graph: Store, byType: TypeToSubjs, typeUri: NamedNode) { const subjSet = byType.get(typeUri); this.subjs = subjSet ? Array.from(subjSet) : []; this.subjs.sort(); let preds = Immutable.Set<NamedNode>(); this.graphCells = Immutable.Map<ISP, Immutable.Set<Term>>().withMutations( (mutGraphCells) => { this.subjs.forEach((subj: NamedNode) => { graph.forEach( (q: Quad) => { if (!Util.isNamedNode(q.predicate)) { throw new Error(); } const pred = q.predicate as NamedNode; if (pred.equals(rdf.type)) { // the whole block is labeled with the type return; } preds = preds.add(pred); const cellKey = this.makeCellKey(subj, pred); mutGraphCells.set( cellKey, mutGraphCells.get(cellKey, Immutable.Set<Term>()).add(q.object) ); }, subj, null, null, null ); }); } ); this.preds = Array.from(preds); this.preds.splice(this.preds.indexOf(rdf.type), 1); // also pull out label, which should be used on 1st column this.preds.sort(); } makeCellKey(subj: NamedNode, pred: NamedNode): ISP { return SP({ subj: subj, pred: pred, }); } }