UNPKG

@metacell/geppetto-meta-ui

Version:

React components from geppetto-meta to create neuroscience applications and visualize data.

249 lines (244 loc) 10.3 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var d3 = require("d3"); export var Matrix = /*#__PURE__*/function () { function Matrix() { _classCallCheck(this, Matrix); this.leftIndicator = 10; this.topIndicator = 10; this.order = "id"; } return _createClass(Matrix, [{ key: "draw", value: function draw(context) { var matrixDim = context.height < context.width ? context.height : context.width; var x = d3.scaleBand().range([0, matrixDim]); // Opacity var z = d3.scaleLinear().domain([0, 4]).clamp(true); // Colors var c = d3.scaleOrdinal(d3.schemeCategory10); var defaultTooltipText = "Hover the squares to see the connections."; var container = context.svg.append("g").attr("transform", "translate(" + this.leftIndicator + "," + this.topIndicator + ")"); var matrix = []; var nodes = context.dataset.nodes; var root = context.dataset.root; var n = nodes.length; // Compute index per node. nodes.forEach(function (node, i) { node.pre_count = 0; node.post_count = 0; matrix[i] = d3.range(n).map(function (j) { return { x: j, y: i, z: 0 }; }); }); // Convert links to matrix; count pre / post conns. context.dataset.links.forEach(function (link) { /* * TODO: think about zero weight lines * matrix[link.source][link.target].z = link.weight ? link.type : 0; */ matrix[link.source][link.target].z = link.type; nodes[link.source].pre_count += 1; nodes[link.target].post_count += 1; }); /* * Sorting matrix entries. * TODO: runtime specified sorting criteria */ var sortOptions = { 'id': 'By entity name', 'pre_count': 'By # pre', 'post_count': 'By # post' }; // Precompute the orders. this.orders = { id: d3.range(n).sort(function (a, b) { return d3.ascending(nodes[a].id, nodes[b].id); }), pre_count: d3.range(n).sort(function (a, b) { return nodes[b].pre_count - nodes[a].pre_count; }), post_count: d3.range(n).sort(function (a, b) { return nodes[b].post_count - nodes[a].post_count; }) // community: d3.range(n).sort(function(a, b) { return nodes[b].community - nodes[a].community; }), }; // Default sort order. x.domain(this.orders[this.order]); /* * we store the 'conn' key in case we want to * eg. conditionally colour the indicator if there * are actually connections in that row/column */ var pre = nodes.map(function (x, i) { return { id: x.id, conn: matrix[i].filter(function (d) { return d.z; }).length > 0 }; }); var matrixT = matrix[0].map(function (col, i) { return matrix.map(function (row) { return row[i]; }); }); var post = nodes.map(function (x, i) { return { id: x.id, conn: matrixT[i].filter(function (d) { return d.z; }).length > 0 }; }); var popNameFromId = function popNameFromId(id) { return eval(context.props.modelFactory.getAllPotentialInstancesEndingWith(id)[0]).getParent().getName(); }; var mouseoverCell = function mouseoverCell(msg) { d3.select(this.parentNode.appendChild(this)).transition().duration(100).style('stroke-opacity', 1).style('stroke', 'white').style('stroke-width', 2); d3.select("body").style('cursor', 'pointer'); if (context.tooltipRef.current) { context.tooltipRef.current.setState(function () { return { layoutTooltip: msg }; }); } }; var mouseoutCell = function mouseoutCell() { d3.select(this).transition().duration(100).style('stroke-opacity', 0).style('stroke', 'white'); d3.select("body").style('cursor', 'default'); if (context.tooltipRef.current) { context.tooltipRef.current.setState(function () { return { layoutTooltip: defaultTooltipText }; }); } }; var popIndicator = function popIndicator(pos, colormap, w, h) { return function (d, i) { d3.select(this).selectAll(".cell").data(d).enter().append("rect").attr("class", "cell").attr(pos, function (d, i) { return x(i); }).attr("width", w).attr("height", h).attr("title", function (d) { return d.id; }).style("fill", function (d) { return colormap(popNameFromId(d.id)); }).style("stroke", function (d) { return colormap(popNameFromId(d.id)); }).on("mouseover", function (d) { mouseoverCell.apply(this, [popNameFromId(d.id)]); }).on("mouseout", function () { mouseoutCell.apply(this); }); }; }; var rect = container.append("rect").attr("class", "background").attr("width", matrixDim).attr("height", matrixDim); var colormap = context.nodeColormap.range ? context.nodeColormap : d3.scaleOrdinal(d3.schemeCategory20); var postMargin = parseInt(rect.attr("width")) / pre.length; var preMargin = parseInt(rect.attr("height")) / post.length; var postPop = container.selectAll(".postPop").data([post]).enter().append("g").attr("class", "postPop").attr("transform", "translate(0," + -this.topIndicator + ")").each(popIndicator("x", colormap, postMargin, 5)); var prePop = container.selectAll(".prePop").data([pre]).enter().append("g").attr("class", "prePop").attr("transform", "translate(" + -this.leftIndicator + ",0)").each(popIndicator("y", colormap, 5, preMargin)); var row_ = container.selectAll(".row").data(matrix).enter().append("g").attr("class", "row").attr("transform", function (d, i) { return "translate(0," + x(i) + ")"; }).each(row); row_.append("line").attr("x2", context.width); var column = container.selectAll(".column").data(matrix).enter().append("g").attr("class", "column").attr("transform", function (d, i) { return "translate(" + x(i) + ")rotate(-90)"; }); column.append("line").attr("x1", -context.width); // Draw squares for each connection function row(row) { var cell = d3.select(this).selectAll(".cell").data(row.filter(function (d) { return d.z; })) // only paint conns .enter().append("rect").attr("class", "cell").attr("x", function (d) { return x(d.x); }).attr("width", x.bandwidth()).attr("height", x.bandwidth()).attr("title", function (d) { return d.id; }) // .style("fill-opacity", function(d) { return z(d.z); }) .style("fill", function (d) { return c(d.z); }).on("click", function (d) { context.props.matrixOnClickHandler(); }).on("mouseover", function (d) { mouseoverCell.apply(this, [nodes[d.y].id + " is connected to " + nodes[d.x].id]); }).on("mouseout", function () { mouseoutCell.apply(this); }); } } }, { key: "getLegends", value: function getLegends(context) { var colormap = context.nodeColormap.range ? context.nodeColormap : d3.scaleOrdinal(d3.schemeCategory20); return [{ id: 'legend', colorScale: colormap, title: null }]; } }, { key: "getName", value: function getName() { return "Matrix"; } }, { key: "setOrder", value: function setOrder(context, value) { this.order = value; var matrixDim = context.height < context.width ? context.height : context.width; var x = d3.scaleBand().range([0, matrixDim]); x.domain(this.orders[value]); var t = context.svg.transition().duration(2500); t.selectAll(".row").delay(function (d, i) { return x(i) * 4; }).attr("transform", function (d, i) { return "translate(0," + x(i) + ")"; }).selectAll(".cell").delay(function (d) { return x(d.x) * 4; }).attr("x", function (d) { return x(d.x); }); t.selectAll(".postPop .cell").delay(function (d, i) { return x(i) * 4; }).attr("x", function (d, i) { return x(i); }); t.selectAll(".prePop .cell").delay(function (d, i) { return x(i) * 4; }).attr("y", function (d, i) { return x(i); }); t.selectAll(".column").delay(function (d, i) { return x(i) * 4; }).attr("transform", function (d, i) { return "translate(" + x(i) + ")rotate(-90)"; }); } }, { key: "hasTooltip", value: function hasTooltip() { return true; } }, { key: "hasToggle", value: function hasToggle() { return true; } }, { key: "hasSelect", value: function hasSelect() { return true; } }]); }();