Public
Edited
Dec 9
Insert cell
Insert cell
Insert cell
query = `SELECT ?character ?characterLabel ?book ?bookLabel ?rk WHERE {
?book p:P179 ?statement.
?statement ps:P179 wd:Q744536;
pq:P1545 ?rank.
BIND(xsd:integer(?rank) AS ?rk)
?book wdt:P674 ?character.
SERVICE wikibase:label { bd:serviceParam wikibase:language "fr". }
}
ORDER BY (?rk) (?characterLabel)`
Insert cell
data = fetch(
`https://query-main.wikidata.org/sparql?query=${encodeURIComponent(query)}`,
{ headers: { accept: "application/sparql-results+json" } }
).then((d) => d.json())
Insert cell
df = aq.from(
data.results.bindings.map((res) => ({
book: res.book.value,
bookLabel: res.bookLabel.value,
character: res.character.value,
characterLabel: res.characterLabel.value
}))
)
Insert cell
Inputs.table(df, { layout: "auto", select: false })
Insert cell
Insert cell
Insert cell
nodes = df
.derive({
id: (d) => op.replace(d.character, "http://www.wikidata.org/entity/", "")
})
.rename({ characterLabel: "label" })
.groupby(["id", "label"])
.count({ as: "size" })
.objects()
Insert cell
nodes[19]["label"]
Insert cell
nodes[19]
Insert cell
Insert cell
function make_edges({ id }) {
const books = df.filter(
aq.escape(
(d) =>
op.replace(d.character, "http://www.wikidata.org/entity/", "") == id
)
);
const relations = df
.semijoin(books, "book")
.filter(
aq.escape(
(d) =>
op.replace(d.character, "http://www.wikidata.org/entity/", "") != id
)
)
.groupby("character")
.count({ as: "size" })
.derive({
source: aq.escape(id),
target: (d) =>
op.replace(d.character, "http://www.wikidata.org/entity/", "")
})
.derive({
id: aq.escape((d) => [d.source, d.target].sort().join("-"))
})
.select(["id", "source", "target", "size"]);
return relations.objects();
}
Insert cell
make_edges({ id: nodes[19]["id"] })
Insert cell
Insert cell
all_edges = aq
.from(nodes)
.array("id")
.map((d) => make_edges({ id: d }))
Insert cell
[].concat.apply([], all_edges)
Insert cell
Insert cell
edges = aq.from([].concat.apply([], all_edges)).dedupe("id").objects()
Insert cell
Insert cell
graph = {
let graph = new Graph({
type: "undirected",
weighted: false,
weight: "weight"
});

nodes.forEach((n) => {
graph.addNode(n.id, { label: n.label, size: +n.size });
});

edges.forEach((e) => {
graph.addEdge(e.source, e.target, {
size: +e.size
});
});

GraphologyLibrary.communitiesLouvain.assign(graph, {
resolution: 1 // the higher, more communities
});

return graph;
}
Insert cell
colors = d3.schemeCategory10.concat().reverse()
Insert cell
graph.forEachNode((n, attr) => {
// graph.setNodeAttribute(n, "size", graph.degree(n)); // la taille des ronds/noeuds reflétera leur nb de connexions

graph.setNodeAttribute(n, "color", colors[attr.community]);
})
Insert cell
graph.getNodeAttributes(graph.nodes()[0])
Insert cell
graph.getNodeAttributes(graph.nodes()[19])
Insert cell
Insert cell
{
GraphologyLibrary.metrics.centrality.degree.assign(graph);
GraphologyLibrary.metrics.centrality.eigenvector.assign(graph);
GraphologyLibrary.metrics.centrality.hits.assign(graph);
GraphologyLibrary.metrics.centrality.betweenness.assign(graph);
GraphologyLibrary.metrics.centrality.closeness.assign(graph);
}
Insert cell
metrics = graph
.nodes()
.map((n) => graph.getNodeAttributes(n))
.map((n, i) => {
n.degrees = graph.degree(nodes[i].id);
return n;
})
Insert cell
Inputs.table(metrics, {
layout: "auto",
sort: "degrees",
reverse: true,
columns: [
"label",
"size",
"community",
"degrees",
"degreeCentrality",
"eigenvectorCentrality",
"authority",
"hub",
"betweennessCentrality",
"closenessCentrality"
]
})
Insert cell
Insert cell
renderer = {
// Create a HTML container
const container = document.createElement("div");
container.style.width = "100%";
container.style.height = "500px";
yield container;

// Create the renderer
// la ligne la plus importante !
const renderer = new sigma.Sigma(graph, container, {
x: "x",
y: "y",
labelRenderedSizeThreshold: 3
});

try {
yield invalidation;
} finally {
renderer.kill();
}
}
Insert cell
renderer2 = {
const container = document.createElement("div");
container.style.width = "100%";
container.style.height = "500px";
yield container;

GraphologyLibrary.layout.circular.assign(graph); // Disposition de départ. circular peut être remplacé par random ou circlepack

let sensibleSettings =
GraphologyLibrary.layoutForceAtlas2.inferSettings(graph);
//sensibleSettings.gravity = 0.01
//sensibleSettings.scalingRatio = 10
sensibleSettings.outboundAttractionDistribution = true;

GraphologyLibrary.layoutForceAtlas2.assign(graph, {
iterations: 1000,
settings: sensibleSettings,
getEdgeWeight: "weight"
});

GraphologyLibrary.layoutNoverlap.assign(graph); // traitement complémentaire pour réduire les superpositions

return new sigma.Sigma(
graph,
container,
{ labelRenderedSizeThreshold: 2.5 }
);
}
Insert cell
Insert cell
import { ForceGraph } from "@d3/force-directed-graph-component"
Insert cell
chart = ForceGraph(
{ nodes: nodes, links: edges },
{
nodeId: (d) => d.id,

nodeGroup: (d) => d.group,
nodeTitle: (d) => `${d.id}\n${d.group}`,
linkStrokeWidth: (l) => Math.sqrt(l.size),
width,
height: 600,
invalidation // a promise to stop the simulation when the cell is re-run
}
)
Insert cell
Insert cell
Plot.plot({
width: 800,
y: { label: null, axis: null },
x: { label: null, axis: null },
color: { scheme: "YlOrRd" },
marks: [
Plot.cell([].concat.apply([], all_edges), {
x: "source",
y: "target",
fill: "size",
title: "id ",
sort: { x: "fill", y: "fill", reverse: true }
})
]
})
Insert cell
Insert cell
Graph = require("graphology")
Insert cell
GraphologyLibrary = require("graphology-library@0.7.1/dist/graphology-library.min.js")
Insert cell
sigma = import("https://cdn.skypack.dev/sigma@2.3.0?min")
Insert cell
import { aq, op } from "@uwdata/arquero"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more