var sigInst, canvas, $GP //Load configuration file var config={}; var currentColorAttribute = "base_model_relation"; var currentAtlasFile = ""; //For debug allow a config=file.json parameter to specify the config function GetQueryStringParams(sParam,defaultVal) { var sPageURL = ""+window.location;//.search.substring(1);//This might be causing error in Safari? if (sPageURL.indexOf("?")==-1) return defaultVal; sPageURL=sPageURL.substr(sPageURL.indexOf("?")+1); var sURLVariables = sPageURL.split('&'); for (var i = 0; i < sURLVariables.length; i++) { var sParameterName = sURLVariables[i].split('='); if (sParameterName[0] == sParam) { return sParameterName[1]; } } return defaultVal; } jQuery.getJSON(GetQueryStringParams("config","config.json"), function(data, textStatus, jqXHR) { config=data; currentAtlasFile = config.data; if (config.type!="network") { //bad config alert("Invalid configuration settings.") return; } //As soon as page is ready (and data ready) set up it $(document).ready(setupGUI(config)); });//End JSON Config load // FUNCTION DECLARATIONS Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; function initSigma(config) { var data=config.data var drawProps, graphProps,mouseProps; if (config.sigma && config.sigma.drawingProperties) drawProps=config.sigma.drawingProperties; else drawProps={ defaultLabelColor: "#000", defaultLabelSize: 14, defaultLabelBGColor: "#ddd", defaultHoverLabelBGColor: "#002147", defaultLabelHoverColor: "#fff", labelThreshold: 10, defaultEdgeType: "curve", hoverFontStyle: "bold", fontStyle: "bold", activeFontStyle: "bold" }; if (config.sigma && config.sigma.graphProperties) graphProps=config.sigma.graphProperties; else graphProps={ minNodeSize: 1, maxNodeSize: 7, minEdgeSize: 0.2, maxEdgeSize: 0.5 }; if (config.sigma && config.sigma.mouseProperties) mouseProps=config.sigma.mouseProperties; else mouseProps={ minRatio: 0.75, // How far can we zoom out? maxRatio: 20, // How far can we zoom in? }; var a = sigma.init(document.getElementById("sigma-canvas")).drawingProperties(drawProps).graphProperties(graphProps).mouseProperties(mouseProps); sigInst = a; a.active = !1; a.neighbors = {}; a.detail = !1; dataReady = function() { a.clusters = {}; // Initialize node clusters based on current coloring a.iterNodes(function (b) { a.clusters[b.color] || (a.clusters[b.color] = []); a.clusters[b.color].push(b.id); // Make sure colors are properly copied from the JSON to node.attr if (!b.attr) b.attr = {}; if (b.colors && !b.attr.colors) { b.attr.colors = b.colors; } }); a.bind("upnodes", function (a) { nodeActive(a.content[0]); }); a.draw(); configSigmaElements(config); // Create the color legend updateColorLegend(); // Find available color attributes from nodes var colorAttributes = []; var colorAttrsFound = {}; a.iterNodes(function(node) { if (node.attr && node.attr.colors) { for (var attr in node.attr.colors) { if (!colorAttrsFound[attr]) { colorAttrsFound[attr] = true; colorAttributes.push('
'+attr+'
'); } } } else if (node.colors) { // If colors are in the original structure, copy them to attr if (!node.attr) node.attr = {}; node.attr.colors = node.colors; for (var attr in node.colors) { if (!colorAttrsFound[attr]) { colorAttrsFound[attr] = true; colorAttributes.push('
'+attr+'
'); } } } }); $GP.coloring.content(colorAttributes.join("")); $GP.coloring.select.text(currentColorAttribute); } if (data.indexOf("gexf")>0 || data.indexOf("xml")>0) a.parseGexf(data,dataReady); else a.parseJson(data,dataReady); gexf = sigmaInst = null; } function setupGUI(config) { // Initialise main interface elements var logo=""; // Logo elements if (config.logo.file) { logo = ""; } if (config.logo.link) logo=""+logo+""; $("#maintitle").html(logo); // #title $("#title").html("

"+config.text.title+"

"); // #titletext $("#titletext").html(config.text.intro); // More information if (config.text.more) { $("#information").html(config.text.more); } else { //hide more information link $("#moreinformation").hide(); } // Legend // Node if (config.legend.nodeLabel) { $(".node").next().html(config.legend.nodeLabel); } else { //hide more information link $(".node").hide(); } // Edge if (config.legend.edgeLabel) { $(".edge").next().html(config.legend.edgeLabel); } else { //hide more information link $(".edge").hide(); } // Colours if (config.legend.nodeLabel) { $(".colours").next().html(config.legend.colorLabel); } else { //hide more information link $(".colours").hide(); } $GP = { calculating: !1, showgroup: !1 }; $GP.intro = $("#intro"); $GP.minifier = $GP.intro.find("#minifier"); $GP.mini = $("#minify"); $GP.info = $("#attributepane"); $GP.info_donnees = $GP.info.find(".nodeattributes"); $GP.info_name = $GP.info.find(".name"); $GP.info_link = $GP.info.find(".link"); $GP.info_data = $GP.info.find(".data"); $GP.info_close = $GP.info.find(".returntext"); $GP.info_close2 = $GP.info.find(".close"); $GP.info_p = $GP.info.find(".p"); $GP.info_close.click(nodeNormal); $GP.info_close2.click(nodeNormal); $GP.form = $("#mainpanel").find("form"); $GP.search = new Search($GP.form.find("#search")); if (!config.features.search) { $("#search").hide(); } if (!config.features.groupSelectorAttribute) { $("#attributeselect").hide(); } $GP.cluster = new Cluster($GP.form.find("#attributeselect")); $GP.coloring = new ColorSelector($GP.form.find("#coloringselect")); $GP.atlas = new AtlasSelector($GP.form.find("#atlasselect")); var atlases = getAvailableAtlases(); var atlasLinks = []; for (var i = 0; i < atlases.length; i++) { atlasLinks.push('
' + atlases[i].name + '
'); } $GP.atlas.content(atlasLinks.join("")); $GP.atlas.select.text(atlases[0].name); // Set default atlas name config.GP=$GP; initSigma(config); } function configSigmaElements(config) { $GP=config.GP; // Node hover behaviour if (config.features.hoverBehavior == "dim") { var greyColor = '#ccc'; sigInst.bind('overnodes',function(event){ var nodes = event.content; var neighbors = {}; sigInst.iterEdges(function(e){ if(nodes.indexOf(e.source)<0 && nodes.indexOf(e.target)<0){ if(!e.attr['grey']){ e.attr['true_color'] = e.color; e.color = greyColor; e.attr['grey'] = 1; } }else{ e.color = e.attr['grey'] ? e.attr['true_color'] : e.color; e.attr['grey'] = 0; neighbors[e.source] = 1; neighbors[e.target] = 1; } }).iterNodes(function(n){ if(!neighbors[n.id]){ if(!n.attr['grey']){ n.attr['true_color'] = n.color; n.color = greyColor; n.attr['grey'] = 1; } }else{ n.color = n.attr['grey'] ? n.attr['true_color'] : n.color; n.attr['grey'] = 0; } }).draw(2,2,2); }).bind('outnodes',function(){ sigInst.iterEdges(function(e){ e.color = e.attr['grey'] ? e.attr['true_color'] : e.color; e.attr['grey'] = 0; }).iterNodes(function(n){ n.color = n.attr['grey'] ? n.attr['true_color'] : n.color; n.attr['grey'] = 0; }).draw(2,2,2); }); } else if (config.features.hoverBehavior == "hide") { sigInst.bind('overnodes',function(event){ var nodes = event.content; var neighbors = {}; sigInst.iterEdges(function(e){ if(nodes.indexOf(e.source)>=0 || nodes.indexOf(e.target)>=0){ neighbors[e.source] = 1; neighbors[e.target] = 1; } }).iterNodes(function(n){ if(!neighbors[n.id]){ n.hidden = 1; }else{ n.hidden = 0; } }).draw(2,2,2); }).bind('outnodes',function(){ sigInst.iterEdges(function(e){ e.hidden = 0; }).iterNodes(function(n){ n.hidden = 0; }).draw(2,2,2); }); } $GP.bg = $(sigInst._core.domElements.bg); $GP.bg2 = $(sigInst._core.domElements.bg2); var a = [], b,x=1; for (b in sigInst.clusters) a.push('
Group ' + (x++) + ' (' + sigInst.clusters[b].length + ' members)
'); //a.sort(); $GP.cluster.content(a.join("")); b = { minWidth: 400, maxWidth: 800, maxHeight: 600 };// minHeight: 300, $("a.fb").fancybox(b); $("#zoom").find("div.z").each(function () { var a = $(this), b = a.attr("rel"); a.click(function () { if (b == "center") { sigInst.position(0,0,1).draw(); } else { var a = sigInst._core; sigInst.zoomTo(a.domElements.nodes.width / 2, a.domElements.nodes.height / 2, a.mousecaptor.ratio * ("in" == b ? 1.5 : 0.5)); } }) }); $GP.mini.click(function () { $GP.mini.hide(); $GP.intro.show(); $GP.minifier.show() }); $GP.minifier.click(function () { $GP.intro.hide(); $GP.minifier.hide(); $GP.mini.show() }); $GP.intro.find("#showGroups").click(function () { !0 == $GP.showgroup ? showGroups(!1) : showGroups(!0) }); a = window.location.hash.substr(1); if (0 < a.length) switch (a) { case "Groups": showGroups(!0); break; case "information": $.fancybox.open($("#information"), b); break; default: $GP.search.exactMatch = !0, $GP.search.search(a) $GP.search.clean(); } // $GP.coloring = new ColorSelector($GP.form.find("#coloringselect")); } function Search(a) { this.input = a.find("input[name=search]"); this.state = a.find(".state"); this.results = a.find(".results"); this.exactMatch = !1; this.lastSearch = ""; this.searching = !1; var b = this; this.input.focus(function () { var a = $(this); a.data("focus") || (a.data("focus", !0), a.removeClass("empty")); b.clean() }); this.input.keydown(function (a) { if (13 == a.which) return b.state.addClass("searching"), b.search(b.input.val()), !1 }); this.state.click(function () { var a = b.input.val(); b.searching && a == b.lastSearch ? b.close() : (b.state.addClass("searching"), b.search(a)) }); this.dom = a; this.close = function () { this.state.removeClass("searching"); this.results.hide(); this.searching = !1; this.input.val("");//SAH -- let's erase string when we close nodeNormal() }; this.clean = function () { this.results.empty().hide(); this.state.removeClass("searching"); this.input.val(""); }; this.search = function (a) { var b = !1, c = [], b = this.exactMatch ? ("^" + a + "$").toLowerCase() : a.toLowerCase(), g = RegExp(b); this.exactMatch = !1; this.searching = !0; this.lastSearch = a; this.results.empty(); if (2 >= a.length) this.results.html("You must search for a name with a minimum of 3 letters."); else { sigInst.iterNodes(function (a) { g.test(a.label.toLowerCase()) && c.push({ id: a.id, name: a.label }) }); c.length ? (b = !0, nodeActive(c[0].id)) : b = showCluster(a); a = ["Search Results: "]; if (1 < c.length) for (var d = 0, h = c.length; d < h; d++) a.push('" + c[d].name + ""); 0 == c.length && !b && a.push("No results found."); 1 < a.length && this.results.html(a.join("")); } if(c.length!=1) this.results.show(); if(c.length==1) this.results.hide(); } } function Cluster(a) { this.cluster = a; this.display = !1; this.list = this.cluster.find(".list"); this.list.empty(); this.select = this.cluster.find(".select"); this.select.click(function () { $GP.cluster.toggle() }); this.toggle = function () { this.display ? this.hide() : this.show() }; this.content = function (a) { this.list.html(a); this.list.find("a").click(function () { var a = $(this).attr("href").substr(1); showCluster(a) }) }; this.hide = function () { this.display = !1; this.list.hide(); this.select.removeClass("close") }; this.show = function () { this.display = !0; this.list.show(); this.select.addClass("close") } } // Add this after the Cluster constructor function ColorSelector(a) { this.coloring = a; this.display = false; this.list = this.coloring.find(".list"); this.list.empty(); this.select = this.coloring.find(".select"); this.select.click(function () { $GP.coloring.toggle(); }); this.toggle = function () { this.display ? this.hide() : this.show(); }; this.content = function (a) { this.list.html(a); this.list.find("a").click(function () { var a = $(this).attr("data-attr"); changeNodeColors(a); }); }; this.hide = function () { this.display = false; this.list.hide(); this.select.removeClass("close"); }; this.show = function () { this.display = true; this.list.show(); this.select.addClass("close"); }; } // Add this function to change node colors function changeNodeColors(attribute) { currentColorAttribute = attribute; $GP.coloring.select.text(attribute); $GP.coloring.hide(); // Reset clusters sigInst.clusters = {}; // Update node colors based on the selected attribute sigInst.iterNodes(function (n) { if (n.attr && n.attr.colors && n.attr.colors[attribute]) { n.color = n.attr.colors[attribute]; } // Update clusters sigInst.clusters[n.color] || (sigInst.clusters[n.color] = []); if (sigInst.clusters[n.color].indexOf(n.id) === -1) { sigInst.clusters[n.color].push(n.id); } }); // Update node colors based on the selected attribute sigInst.iterEdges(function (e) { if (e.attr && e.attr.colors && e.attr.colors[attribute]) { e.color = e.attr.colors[attribute]; } }); // Update color legend updateColorLegend(); // Redraw the graph sigInst.draw(2, 2, 2); } function updateColorLegend() { var legendColors = {}; var legendHtml = ""; // Collect unique colors and their values sigInst.iterNodes(function (n) { if (n.attr && n.attr.colors && n.attr.colors[currentColorAttribute]) { var color = n.attr.colors[currentColorAttribute]; var attrValue = ""; // Try to get the attribute value from node attributes if (n.attr.attributes && n.attr.attributes[currentColorAttribute]) { attrValue = n.attr.attributes[currentColorAttribute]; } else { // If not found in attributes, use a generic label attrValue = "Value " + Object.keys(legendColors).length; } if (!legendColors[color]) { legendColors[color] = attrValue; } } }); // Create legend HTML for (var color in legendColors) { legendHtml += '
  • ' + legendColors[color] + '
  • '; } legendHtml += ""; $("#colorLegend").html(legendHtml); } function showGroups(a) { a ? ($GP.intro.find("#showGroups").text("Hide groups"), $GP.bg.show(), $GP.bg2.hide(), $GP.showgroup = !0) : ($GP.intro.find("#showGroups").text("View Groups"), $GP.bg.hide(), $GP.bg2.show(), $GP.showgroup = !1) } function nodeNormal() { !0 != $GP.calculating && !1 != sigInst.detail && (showGroups(!1), $GP.calculating = !0, sigInst.detail = !0, $GP.info.delay(400).animate({width:'hide'},350),$GP.cluster.hide(), sigInst.iterEdges(function (a) { a.attr.color = !1; a.hidden = !1 }), sigInst.iterNodes(function (a) { a.hidden = !1; a.attr.color = !1; a.attr.lineWidth = !1; a.attr.size = !1 }), sigInst.draw(2, 2, 2, 2), sigInst.neighbors = {}, sigInst.active = !1, $GP.calculating = !1, window.location.hash = "") } function nodeActive(a) { var groupByDirection=false; if (config.informationPanel.groupByEdgeDirection && config.informationPanel.groupByEdgeDirection==true) groupByDirection=true; sigInst.neighbors = {}; sigInst.detail = !0; var b = sigInst._core.graph.nodesIndex[a]; showGroups(!1); var outgoing={},incoming={},mutual={};//SAH sigInst.iterEdges(function (b) { b.attr.lineWidth = !1; b.hidden = !0; n={ name: b.label, colour: b.color }; if (a==b.source) outgoing[b.target]=n; //SAH else if (a==b.target) incoming[b.source]=n; //SAH if (a == b.source || a == b.target) sigInst.neighbors[a == b.target ? b.source : b.target] = n; b.hidden = !1, b.attr.color = "rgba(0, 0, 0, 1)"; }); var f = []; sigInst.iterNodes(function (a) { a.hidden = !0; a.attr.lineWidth = !1; a.attr.color = a.color }); if (groupByDirection) { //SAH - Compute intersection for mutual and remove these from incoming/outgoing for (e in outgoing) { //name=outgoing[e]; if (e in incoming) { mutual[e]=outgoing[e]; delete incoming[e]; delete outgoing[e]; } } } var createList=function(c) { var f = []; var e = [], //c = sigInst.neighbors, g; for (g in c) { var d = sigInst._core.graph.nodesIndex[g]; d.hidden = !1; d.attr.lineWidth = !1; d.attr.color = c[g].colour; a != g && e.push({ id: g, name: d.label, group: (c[g].name)? c[g].name:"", colour: c[g].colour }) } e.sort(function (a, b) { var c = a.group.toLowerCase(), d = b.group.toLowerCase(), e = a.name.toLowerCase(), f = b.name.toLowerCase(); return c != d ? c < d ? -1 : c > d ? 1 : 0 : e < f ? -1 : e > f ? 1 : 0 }); d = ""; for (g in e) { c = e[g]; /*if (c.group != d) { d = c.group; f.push('
  • ' + d + "
  • "); }*/ f.push('
  • ' + c.name + "
  • "); } return f; } /*console.log("mutual:"); console.log(mutual); console.log("incoming:"); console.log(incoming); console.log("outgoing:"); console.log(outgoing);*/ var f=[]; //console.log("neighbors:"); //console.log(sigInst.neighbors); if (groupByDirection) { size=Object.size(mutual); f.push("

    Mututal (" + size + ")

    "); (size>0)? f=f.concat(createList(mutual)) : f.push("No mutual links
    "); size=Object.size(incoming); f.push("

    Incoming (" + size + ")

    "); (size>0)? f=f.concat(createList(incoming)) : f.push("No incoming links
    "); size=Object.size(outgoing); f.push("

    Outgoing (" + size + ")

    "); (size>0)? f=f.concat(createList(outgoing)) : f.push("No outgoing links
    "); } else { f=f.concat(createList(sigInst.neighbors)); } //b is object of active node -- SAH b.hidden = !1; b.attr.color = b.color; b.attr.lineWidth = 6; b.attr.strokeStyle = "#000000"; sigInst.draw(2, 2, 2, 2); $GP.info_link.find("ul").html(f.join("")); $GP.info_link.find("li").each(function () { var a = $(this), b = a.attr("rel"); }); f = b.attr; if (f.attributes) { var image_attribute = false; if (config.informationPanel.imageAttribute) { image_attribute=config.informationPanel.imageAttribute; } e = []; e.push('Model page: https://huggingface.co/' + f.attributes['id'] + '
    ') e.push('Update model information: edit
    ') temp_array = []; g = 0; for (var attr in f.attributes) { var d = f.attributes[attr], h = ""; if (attr!=image_attribute) { h = '' + attr + ': ' + d + '
    ' } //temp_array.push(f.attributes[g].attr); e.push(h) } if (image_attribute) { //image_index = jQuery.inArray(image_attribute, temp_array); $GP.info_name.html("
    ' + b.label + "
    "); } else { $GP.info_name.html("
    ' + b.label + "
    "); } // Image field for attribute pane $GP.info_data.html(e.join("
    ")) } $GP.info_data.show(); $GP.info_p.html("Connections:"); $GP.info.animate({width:'show'},350); $GP.info_donnees.hide(); $GP.info_donnees.show(); sigInst.active = a; window.location.hash = b.label; } function showCluster(a) { var b = sigInst.clusters[a]; if (b && 0 < b.length) { showGroups(!1); sigInst.detail = !0; b.sort(); sigInst.iterEdges(function (a) { a.hidden = !1; a.attr.lineWidth = !1; a.attr.color = !1 }); sigInst.iterNodes(function (a) { a.hidden = !0 }); for (var f = [], e = [], c = 0, g = b.length; c < g; c++) { var d = sigInst._core.graph.nodesIndex[b[c]]; !0 == d.hidden && (e.push(b[c]), d.hidden = !1, d.attr.lineWidth = !1, d.attr.color = d.color, f.push('
  • ' + d.label + "
  • ")) } sigInst.clusters[a] = e; sigInst.draw(2, 2, 2, 2); $GP.info_name.html("" + a + ""); $GP.info_data.hide(); $GP.info_p.html("Group Members:"); $GP.info_link.find("ul").html(f.join("")); $GP.info.animate({width:'show'},350); $GP.search.clean(); $GP.cluster.hide(); return !0 } return !1 } function AtlasSelector(a) { this.atlas = a; this.display = false; this.list = this.atlas.find(".list"); this.list.empty(); this.select = this.atlas.find(".select"); this.select.click(function () { $GP.atlas.toggle(); }); this.toggle = function () { this.display ? this.hide() : this.show(); }; this.content = function (a) { this.list.html(a); this.list.find("a").click(function () { var dataFile = $(this).attr("data-file"); loadNewAtlas(dataFile); }); }; this.hide = function () { this.display = false; this.list.hide(); this.select.removeClass("close"); }; this.show = function () { this.display = true; this.list.show(); this.select.addClass("close"); }; } function getAvailableAtlases() { return [ { name: "Modalities Atlas", file: "compressed_modalities_data.json.gz" }, { name: "Large NLP Atlas", file: "compressed_large_nlp_data.json.gz" }, ]; } function loadNewAtlas(dataFile) { // Update the currently selected atlas in the dropdown $GP.atlas.select.text(getAtlasNameByFile(dataFile)); $GP.atlas.hide(); config.data = dataFile; reinitializeSigma(config); } function reinitializeSigma(config) { // Remove the old sigma instance if (sigInst) { sigInst.kill(); } // Recreate the sigma canvas $(".sigma-expand").empty(); // Initialize new sigma instance initSigma(config); } function getAtlasNameByFile(dataFile) { var atlases = getAvailableAtlases(); for (var i = 0; i < atlases.length; i++) { if (atlases[i].file === dataFile) { return atlases[i].name; } } return "Unknown Atlas"; }