Add [graph] filtering based on table

This commit is contained in:
niclas 2024-02-05 09:42:20 +01:00
parent d357075432
commit 590a05e3c7
4 changed files with 148 additions and 28 deletions

View file

@ -93,7 +93,6 @@ class Galaxy():
self.entry += f' |{author}|\n' self.entry += f' |{author}|\n'
def _create_clusters(self): def _create_clusters(self):
# global public_clusters_dict
clusters = [] clusters = []
for cluster in self.cluster_list: for cluster in self.cluster_list:
clusters.append(Cluster( clusters.append(Cluster(
@ -195,18 +194,11 @@ class Cluster():
self.entry += f'\n' self.entry += f'\n'
self.entry += f'??? info "Associated metadata"\n' self.entry += f'??? info "Associated metadata"\n'
self.entry += f'\n' self.entry += f'\n'
self.entry += f' <div class="no-filter">\n'
self.entry += f' \n'
self.entry += f' |Metadata key {{ .no-filter }} |Value|\n' self.entry += f' |Metadata key {{ .no-filter }} |Value|\n'
self.entry += f' |-----------------------------------|-----|\n' self.entry += f' |-----------------------------------|-----|\n'
for meta in sorted(self.meta.keys()): for meta in sorted(self.meta.keys()):
if meta not in excluded_meta: if meta not in excluded_meta:
self.entry += f' | {meta} | {self.meta[meta]} |\n' self.entry += f' | {meta} | {self.meta[meta]} |\n'
# self.entry += " {: .no-filter }\n"
self.entry += f' \n'
self.entry += f' </div>\n'
self.entry += f'\n'
def get_related_clusters(self, cluster_dict, depth=-1, visited=None, level=1): def get_related_clusters(self, cluster_dict, depth=-1, visited=None, level=1):
global public_relations_count global public_relations_count

View file

@ -1,28 +1,43 @@
document$.subscribe(function () { document$.subscribe(function () {
// Function to parse table and return data // Function to parse table and return data
function parseTable(table) { // function parseTable(table) {
// var data = [];
// var rows = table.querySelectorAll("tr");
// rows.forEach((row, i) => {
// // Skipping header row and filter row
// if (i > 1) {
// var cells = row.querySelectorAll("td");
// data.push({ source: cells[0].textContent, target: cells[1].textContent, level: cells[2].textContent });
// }
// });
// return data;
// }
function parseFilteredTable(tf) {
var data = []; var data = [];
var rows = table.querySelectorAll("tr"); tf.getFilteredData().forEach((row, i) => {
rows.forEach((row, i) => { // console.log("Row");
// Skipping header row and filter row // console.log(row);
if (i > 1) { data.push({ source: row[1][0], target: row[1][1], level: row[1][2] });
var cells = row.querySelectorAll("td"); // console.log("Data");
data.push({ source: cells[0].textContent, target: cells[1].textContent, level: cells[2].textContent }); // console.log(data);
} }
}); );
return data; return data;
} }
// Function to create graph // Function to create Force-Directed Graph
function createGraph(data, elementId) { function createForceDirectedGraph(data, elementId) {
// Extract nodes and links // Extract nodes and links
var nodes = Array.from(new Set(data.flatMap(d => [d.source, d.target]))) var nodes = Array.from(new Set(data.flatMap(d => [d.source, d.target])))
.map(id => ({ id })); .map(id => ({ id }));
var links = data.map(d => ({ source: d.source, target: d.target })); var links = data.map(d => ({ source: d.source, target: d.target }));
// console.log("Nodes");
// console.log(nodes);
// Set up the dimensions of the graph // Set up the dimensions of the graph
var width = 800, height = 600; var width = 1000, height = 1000;
// Append SVG for the graph // Append SVG for the graph
var svg = d3.select(elementId).append("svg") var svg = d3.select(elementId).append("svg")
@ -66,19 +81,132 @@ document$.subscribe(function () {
.attr("cx", d => d.x) .attr("cx", d => d.x)
.attr("cy", d => d.y); .attr("cy", d => d.y);
}); });
// return simulation;
// invalidation.then(() => simulation.stop());
return Object.assign(svg.node(), {
update({ newNodes, newLinks }) {
// Process new nodes and maintain the existing ones
const oldNodesMap = new Map(node.data().map(d => [d.id, d]));
nodes = newNodes.map(d => Object.assign(oldNodesMap.get(d.id) || {}, d));
// Update nodes with new data
node = node.data(nodes, d => d.id)
.join(
enter => enter.append("circle")
.attr("r", 5)
.attr("fill", "#69b3a2"),
update => update,
exit => exit.remove()
);
// Process new links
const oldLinksMap = new Map(link.data().map(d => [`${d.source.id},${d.target.id}`, d]));
links = newLinks.map(d => Object.assign(oldLinksMap.get(`${d.source.id},${d.target.id}`) || {}, d));
// Update links with new data
link = link.data(links, d => `${d.source.id},${d.target.id}`)
.join(
enter => enter.append("line")
.attr("stroke-width", d => Math.sqrt(d.value)),
update => update,
exit => exit.remove()
);
// Restart the simulation with new data
simulation.nodes(nodes);
simulation.force("link").links(links);
simulation.alpha(1).restart();
}
});
} }
// Find all tables that have a th with the class .graph and generate graphs // Find all tables that have a th with the class .graph and generate Force-Directed Graphs
document.querySelectorAll("table").forEach((table, index) => { document.querySelectorAll("table").forEach((table, index) => {
var graphHeader = table.querySelector("th.graph"); var graphHeader = table.querySelector("th.graph");
if (graphHeader) { if (graphHeader) {
var data = parseTable(table); // var data = parseTable(table);
console.log(data); // //var data = parseFilteredTable(table);
// // console.log("Data");
// // console.log(data);
// var graphId = "graph" + index;
// var div = document.createElement("div");
// div.id = graphId;
// table.after(div);
// var simulation = createForceDirectedGraph(data, "#" + graphId);
// Initialize TableFilter for the table
var tf = new TableFilter(table, {
// Define filter options for each column (customize as needed)
base_path: "https://unpkg.com/tablefilter@0.7.3/dist/tablefilter/",
highlight_keywords: true,
col_2: "checklist",
col_widths: ["350px", "350px", "100px"],
col_types: ["string", "string", "number"],
grid_layout: false,
responsive: false,
watermark: ["Filter table ...", "Filter table ..."],
auto_filter: {
delay: 100 //milliseconds
},
filters_row_index: 1,
state: true,
rows_counter: true,
status_bar: true,
themes: [{
name: "transparent",
}],
btn_reset: {
tooltip: "Reset",
toolbar_position: "right",
},
toolbar: true,
extensions: [{
name: "sort",
},
{
name: 'filtersVisibility',
description: 'Sichtbarkeit der Filter',
toolbar_position: 'right',
}],
});
tf.init();
//var data = parseTable(table);
var data = parseFilteredTable(tf);
// console.log("Data");
// console.log(data);
var graphId = "graph" + index; var graphId = "graph" + index;
var div = document.createElement("div"); var div = document.createElement("div");
div.id = graphId; div.id = graphId;
table.after(div); table.after(div);
createGraph(data, "#" + graphId); var simulation = createForceDirectedGraph(data, "#" + graphId);
// Function to filter the table data and update the graph
function filterTableAndGraph() {
var filteredData = parseFilteredTable(tf);
// console.log("Filtered Data");
// console.log(filteredData);
var { newNodes, newLinks } = processNewData(filteredData);
// Restart the simulation with filtered data
simulation.update({ newNodes: newNodes, newLinks: newLinks });
}
function processNewData(newData) {
// Extracting new nodes
var newNodes = Array.from(new Set(newData.flatMap(d => [d.source, d.target])))
.map(id => ({ id }));
// Preparing the links in the required format
var newLinks = newData.map(d => ({ source: d.source, target: d.target }));
// console.log("New Nodes");
// console.log(newNodes);
return { newNodes, newLinks };
}
// Listen for table filtering events
tf.emitter.on(['after-filtering'], filterTableAndGraph);
} }
}); });
}); });

View file

@ -32,9 +32,9 @@ document$.subscribe(function () {
tooltip: "Reset", tooltip: "Reset",
toolbar_position: "right", toolbar_position: "right",
}, },
no_results_message: { // no_results_message: {
content: "No matching records found", // content: "No matching records found",
}, // },
toolbar: true, toolbar: true,
extensions: [{ extensions: [{
name: "sort", name: "sort",

View file

@ -66,7 +66,7 @@ extra:
generator: false generator: false
extra_javascript: extra_javascript:
- javascripts/tablefilter.js # - javascripts/tablefilter.js
- "https://unpkg.com/tablefilter@0.7.3/dist/tablefilter/tablefilter.js" - "https://unpkg.com/tablefilter@0.7.3/dist/tablefilter/tablefilter.js"
- "https://d3js.org/d3.v6.min.js" - "https://d3js.org/d3.v6.min.js"
- javascripts/d3.js - javascripts/d3.js