UNPKG

vsup

Version:

Value-Suppressing Uncertainty Palettes. A technique for creating bivariate scales for depicting uncertainty, using D3.

593 lines (515 loc) 11.9 kB
/* A lightweight factory for making legends. */ import * as d3 from "d3"; import { simpleHeatmap, simpleArcmap } from "./heatmap"; export function simpleLegend( m_scale, m_size, m_height, m_format, m_title, m_x, m_y ) { var el = null, title = m_title, scale = m_scale || null, size = m_size || 200, height = m_height || 30, fmat = m_format || null, x = m_x || 0, y = m_y || 0; function legend(nel) { el = nel; legend.setProperties(); } legend.setProperties = function() { if (!el) { return; } var domain = scale.domain ? scale.domain() : [0, 1], w = size / scale.range().length, step = (domain[1] - domain[0]) / scale.range().length, dom = d3.range(domain[0], domain[1] + step, step), axisScale = d3 .scalePoint() .range([0, size]) .domain(dom) .round(true); el .attr("class", "legend") .attr("transform", "translate(" + x + "," + y + ")"); var rect = el.selectAll("rect").data(scale.range()); rect .enter() .append("rect") .merge(rect) .attr("x", function(d, i) { return i * w; }) .attr("y", 0) .attr("height", height) .attr("width", w) .attr("fill", function(d) { return d; }); var axis = el.select("g.legend > g"); if (axis.empty()) { axis = el.append("g"); } axis .attr("transform", "translate(0, " + height + ")") .call(d3.axisBottom(axisScale).tickFormat(d3.format(fmat || ""))); var label = el.select("g.legend > text"); if (label.empty()) { label = el.append("text"); } label .style("text-anchor", "middle") .style("font-size", 13) .attr("transform", "translate(" + size / 2 + ", " + (height + 30) + ")") .text(title); }; legend.title = function(t) { if (!arguments.length) { return title; } else { title = t; legend.setProperties(); return legend; } }; legend.scale = function(s) { if (!arguments.length) { return scale; } else { scale = s; legend.setProperties(); return legend; } }; legend.size = function(s) { if (!arguments.length) { return size; } else { size = s; legend.setProperties(); return legend; } }; legend.height = function(h) { if (!arguments.length) { return height; } else { height = h; legend.setProperties(); return legend; } }; legend.format = function(f) { if (!arguments.length) { return fmat; } else { fmat = f; legend.setProperties(); return legend; } }; legend.x = function(nx) { if (!arguments.length) { return x; } else { x = nx; legend.setProperties(); return legend; } }; legend.y = function(ny) { if (!arguments.length) { return y; } else { y = ny; legend.setProperties(); return legend; } }; return legend; } export function heatmapLegend( m_scale, m_size, m_format, m_utitle, m_vtitle, m_x, m_y ) { var el = null, utitle = m_utitle ? m_utitle : "Uncertainty", vtitle = m_vtitle ? m_vtitle : "Value", scale = m_scale ? m_scale : null, size = m_size ? m_size : 200, fmat = m_format || null, x = m_x ? m_x : 0, y = m_y ? m_y : 0, data = null; var heatmap = simpleHeatmap(); var legend = function(nel) { el = nel; legend.setProperties(); el.call(heatmap); }; legend.setProperties = function() { if (!el) { return; } var tmp = data; if (!tmp) { tmp = scale.quantize().data(); } var inverted = []; for (var i = 0; i < tmp.length; i++) { inverted[i] = tmp[tmp.length - i - 1]; } heatmap.y(1); // don't hide x-axis heatmap.data(inverted); heatmap.scale(scale); heatmap.size(size); el .attr("class", "legend") .attr("transform", "translate(" + x + "," + y + ")"); var uncertaintyDomain = scale && scale.quantize ? scale.quantize().uncertaintyDomain() : [0, 1]; var uStep = (uncertaintyDomain[1] - uncertaintyDomain[0]) / inverted.length; var uDom = d3.range( uncertaintyDomain[0], uncertaintyDomain[1] + uStep, uStep ); var valueDomain = scale && scale.quantize ? scale.quantize().valueDomain() : [0, 1]; var vStep = (valueDomain[1] - valueDomain[0]) / inverted.length; var vDom = d3.range(valueDomain[0], valueDomain[1] + vStep, vStep); var xAxisScale = d3 .scalePoint() .range([0, size]) .domain(vDom); el .append("g") .call(d3.axisTop(xAxisScale).tickFormat(d3.format(fmat || ""))); el .append("text") .style("text-anchor", "middle") .style("font-size", 13) .attr("transform", "translate(" + size / 2 + ", " + -25 + ")") .text(vtitle); var yAxis = d3 .scalePoint() .range([0, size]) .domain(uDom); el .append("g") .attr("transform", "translate(" + size + ", 0)") .call(d3.axisRight(yAxis).tickFormat(d3.format(fmat || ""))); el .append("text") .style("text-anchor", "middle") .style("font-size", 13) .attr( "transform", "translate(" + (size + 40) + ", " + size / 2 + ")rotate(90)" ) .text(utitle); }; legend.data = function(newData) { if (!arguments.length) { return data; } else { data = newData; legend.setProperties(); return legend; } }; legend.scale = function(s) { if (!arguments.length) { return scale; } else { scale = s; legend.setProperties(); return legend; } }; legend.size = function(s) { if (!arguments.length) { return size; } else { size = s; legend.setProperties(); return legend; } }; legend.format = function(f) { if (!arguments.length) { return fmat; } else { fmat = f; legend.setProperties(); return legend; } }; legend.x = function(nx) { if (!arguments.length) { return x; } else { x = nx; legend.setProperties(); return legend; } }; legend.y = function(ny) { if (!arguments.length) { return y; } else { y = ny; legend.setProperties(); return legend; } }; legend.utitle = function(t) { if (!arguments.length) { return utitle; } else { utitle = t; legend.setProperties(); return legend; } }; legend.vtitle = function(t) { if (!arguments.length) { return vtitle; } else { vtitle = t; legend.setProperties(); return legend; } }; return legend; } export function arcmapLegend( m_scale, m_size, m_format, m_utitle, m_vtitle, m_x, m_y ) { var el = null, utitle = m_utitle ? m_utitle : "Uncertainty", vtitle = m_vtitle ? m_vtitle : "Value", scale = m_scale ? m_scale : null, size = m_size ? m_size : 200, fmat = m_format || null, x = m_x ? m_x : 0, y = m_y ? m_y : 0, data = null; var arcmap = simpleArcmap(); var legend = function(nel) { el = nel; legend.setProperties(); el.call(arcmap); }; legend.setProperties = function() { if (!el) { return; } var tmp = data; if (!tmp) { tmp = scale.quantize().data(); } var inverted = []; for (var i = 0; i < tmp.length; i++) { inverted[i] = tmp[tmp.length - i - 1]; } arcmap.data(inverted); arcmap.scale(scale); arcmap.size(size); el .attr("class", "legend") .attr("transform", "translate(" + x + "," + y + ")"); var uncertaintyDomain = scale && scale.quantize ? scale.quantize().uncertaintyDomain() : [0, 1]; var uStep = (uncertaintyDomain[1] - uncertaintyDomain[0]) / inverted.length; var uDom = d3.range( uncertaintyDomain[0], uncertaintyDomain[1] + uStep, uStep ); var uAxisScale = d3 .scalePoint() .range([0, size]) .domain(uDom); var px = size / 180; el .append("g") .attr( "transform", "translate(" + (size + 6 * px) + "," + 28 * px + ")rotate(30)" ) .call(d3.axisRight(uAxisScale).tickFormat(d3.format(fmat || ""))); el .append("text") .style("text-anchor", "middle") .style("font-size", 13) .attr( "transform", "translate(" + (size + 10 * px) + "," + (40 * px + size / 2) + ")rotate(-60)" ) .text(utitle); var valueDomain = scale && scale.quantize ? scale.quantize().valueDomain() : [0, 1]; var vStep = (valueDomain[1] - valueDomain[0]) / inverted[0].length; var vTicks = d3.range(valueDomain[0], valueDomain[1] + vStep, vStep); var vAxisScale = d3 .scaleLinear() .range([0, size]) .domain(valueDomain); var valueFormat = fmat ? d3.format(fmat) : vAxisScale.tickFormat(vTicks.length); var angle = d3 .scaleLinear() .domain(valueDomain) .range([-30, 30]); var offset = 3 * px; var myArc = d3 .arc() .innerRadius(size + offset) .outerRadius(size + offset + 1) .startAngle(-Math.PI / 6) .endAngle(Math.PI / 6); var arcAxis = el .append("g") .attr("transform", "translate(" + size / 2 + "," + (size - offset) + ")"); arcAxis .append("path") .attr("fill", "black") .attr("stroke", "transparent") .attr("d", myArc); var labelEnter = arcAxis .selectAll(".arc-label") .data(vTicks) .enter() .append("g") .attr("class", "arc-label") .attr("transform", function(d) { return ( "rotate(" + angle(d) + ")translate(" + 0 + "," + (-size - offset) + ")" ); }); labelEnter .append("text") .style("font-size", "11") .style("text-anchor", "middle") .attr("y", -10) .text(valueFormat); labelEnter .append("line") .attr("x1", 0.5) .attr("x2", 0.5) .attr("y1", -6) .attr("y2", 0) .attr("stroke", "#000"); el .append("text") .style("text-anchor", "middle") .style("font-size", 13) .attr("x", size / 2) .attr("y", -30) .text(vtitle); }; legend.data = function(newData) { if (!arguments.length) { return data; } else { data = newData; legend.setProperties(); return legend; } }; legend.scale = function(s) { if (!arguments.length) { return scale; } else { scale = s; legend.setProperties(); return legend; } }; legend.size = function(s) { if (!arguments.length) { return size; } else { size = s; legend.setProperties(); return legend; } }; legend.format = function(f) { if (!arguments.length) { return fmat; } else { fmat = f; legend.setProperties(); return legend; } }; legend.x = function(nx) { if (!arguments.length) { return x; } else { x = nx; legend.setProperties(); return legend; } }; legend.y = function(ny) { if (!arguments.length) { return y; } else { y = ny; legend.setProperties(); return legend; } }; legend.utitle = function(t) { if (!arguments.length) { return utitle; } else { utitle = t; legend.setProperties(); return legend; } }; legend.vtitle = function(t) { if (!arguments.length) { return vtitle; } else { vtitle = t; legend.setProperties(); return legend; } }; return legend; }