基本上,我试图使用d3.js实时更新散点图。但是我每次单击复选框时都会实例化它的问题。我要实现的目标是确保能够使用复选框作为触发器来过滤数据集。
这是我的代码。
function volcanoPlot1() {
var width = 700,
height = 500,
margin = {top: 50, right:50, bottom: 50, left:50},
xColumn, // name of the variable to be plotted on the axis
yColumn,
xAxisLabel, // label for the axis
yAxisLabel,
xAxisLabelOffset, // offset for the label of the axis
yAxisLabelOffset,
xTicks, // number of ticks on the axis
yTicks,
sampleID = "Label",
expt_No = "Experiment_No",
significanceThreshold = 3, // significance threshold to colour by
foldChangeThreshold = 20.0, // fold change level to colour by
colorRange, // colour range to use in the plot
xScale = d3.scaleLinear(), // the values for the axes will be continuous
yScale = d3.scaleLinear();
function chart(selection){
var innerWidth = width - margin.left - margin.right, // set the size of the chart within its container
innerHeight = height - margin.top - margin.bottom;
selection.each(function(data) {
// set up the scaling for the axes based on the inner width/height of the chart and also the range
// of value for the x and y axis variables. This range is defined by their min and max values as
// calculated by d3.extent()
xScale.range([0, innerWidth])
.domain(d3.extent(data, function(d) { return d[xColumn]; }))
.nice();
// normally would set the y-range to [height, 0] but by swapping it I can flip the axis and thus
// have -log10 scale without having to do extra parsing
yScale.range([innerHeight,0])
.domain(d3.extent(data, function(d) { return d[yColumn]; }))
.nice(); // adds "padding" so the domain extent is exactly the min and max values
//scale extent 1 is start, 250 is zoomable size(resize as you see fit)
var zoom = d3.zoom()
.scaleExtent([1, 250])
.translateExtent([[0, 0], [width, height]])
.on('zoom', zoomFunction);
// append the svg object to the selection
var svg = d3.select(this).append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.call(zoom);
// position the reset button and attach reset function
d3.select('#resetBtn')
.style('top', margin.top * 1.0 + 'px')
.style('left', margin.left * 1.25 + 'px')
.on('click', reset);
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('height', innerHeight)
.attr('width', innerWidth);
// add the axes
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale)
.ticks(12* innerHeight/innerWidth)
//.tickFormat(yTickFormat);
var gX = svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + innerHeight + ')')
.call(xAxis);
gX.append('text')
.attr('class', 'label')
.attr('transform', 'translate(' + width / 2 + ',' + (margin.bottom - 6) + ')')
.attr('text-anchor', 'middle')
.html(xAxisLabel || xColumn);
var gY = svg.append('g')
.attr('class', 'y axis')
.call(yAxis);
gY.append('text')
.attr('class', 'label')
.attr('transform', 'translate(' + (0 - margin.left / 1.25) + ',' + (height / 2) + ') rotate(-90)')
.style('text-anchor', 'middle')
.html(yAxisLabel || yColumn);
// this rect acts as a layer so that zooming works anywhere in the svg. otherwise, if zoom is called on
// just svg, zoom functionality will only work when the pointer is over a circle.
var zoomBox = svg.append('rect')
.attr('class', 'zoom')
.attr('height', innerHeight)
.attr('width', innerWidth);
var circles = svg.append('g')
.attr('class', 'circlesContainer');
//filter happens here
d3.selectAll(".collapsibleChk").on("change", function() {
var type = this.value,
display = this.checked ? "inline" : "none";
console.log(this.value);
circles.selectAll(".dot")
.data(data)
.enter()
.append('circle')
.filter(function(d){ return d[expt_No] === type; })
.attr('r', 3)
.attr('cx', function(d) { return xScale(d[xColumn]); })
.attr('cy', function(d) { return yScale(d[yColumn]); })
.attr('class', circleClass)
.on('mouseenter', tipEnter)
.on("mousemove", tipMove)
.on('mouseleave', function(d) {
return tooltip.style('visibility', 'hidden');
})
.attr("display",display)
.exit()
.remove();
});
var thresholdLines = svg.append('g')
.attr('class', 'thresholdLines');
// add horizontal line at significance threshold
thresholdLines.append("svg:line")
.attr('class', 'threshold')
.attr("x1", 0)
.attr("x2", innerWidth)
.attr("y1", yScale(significanceThreshold))
.attr("y2", yScale(significanceThreshold));
// add vertical line(s) at fold-change threshold (and negative fold-change)
[foldChangeThreshold, -1 * foldChangeThreshold].forEach(function(threshold) {
thresholdLines.append("svg:line")
.attr('class', 'threshold')
.attr("x1", xScale(threshold))
.attr("x2", xScale(threshold))
.attr("y1", 0)
.attr("y2", innerHeight);
});
var tooltip = d3.select("body")
.append("div")
.attr('class', 'tooltip');
function tipEnter(d) {
tooltip.style('visibility', 'visible')
.style('font-size', '13px')
.html(
'<strong>' + sampleID + '</strong>: ' + d[sampleID] + '<br/>' +
'<strong>' + expt_No + '</strong>: ' + d[expt_No] + '<br/>' +
'<strong>' + xColumn + '</strong>: ' + d3.format('.2f')(d[xColumn]) + '<br/>' +
'<strong>' + yColumn + '</strong>: ' + d[yColumn]
);
}
function tipMove() {
tooltip.style("top", (event.pageY - 5) + "px")
.style("left", (event.pageX + 20) + "px");
}
function yTickFormat(n) {
return d3.format(".2r")(getBaseLog(10, n));
function getBaseLog(x, y) {
return Math.log(y) / Math.log(x);
}
}
function zoomFunction() {
var transform = d3.zoomTransform(this);
d3.selectAll('.dot')
.attr('transform', transform)
.attr('r', 3 / Math.sqrt(transform.k));
gX.call(xAxis.scale(d3.event.transform.rescaleX(xScale)));
gY.call(yAxis.scale(d3.event.transform.rescaleY(yScale)));
svg.selectAll('.threshold')
.attr('transform', transform)
.attr('stroke-width', 1 / transform.k);
}
function circleClass(d) {
if (d[yColumn] < significanceThreshold && Math.abs(d[xColumn]) > foldChangeThreshold) return 'dot grey';
else if (d[yColumn] <= significanceThreshold ) return 'dot black';
else if (d[xColumn] >= foldChangeThreshold) return 'dot sig';
else if (d[xColumn] < -foldChangeThreshold) return 'dot sigfold';
else return 'dot';
}
function reset() {
var ease = d3.easePolyIn.exponent(4.0);
svg.transition().duration(750)
.ease(ease)
.call(zoom.transform, d3.zoomIdentity);
}
});
}
chart.width = function(value) {
if (!arguments.length) return width;
width = value;
return chart;
};
chart.height = function(value) {
if (!arguments.length) return height;
height = value;
return chart;
};
chart.margin = function(value) {
if (!arguments.length) return margin;
margin = value;
return chart;
};
chart.xColumn = function(value) {
if (!arguments.length) return xColumn;
xColumn = value;
return chart;
};
chart.yColumn = function(value) {
if (!arguments.length) return yColumn;
yColumn = value;
return chart;
};
chart.xAxisLabel = function(value) {
if (!arguments.length) return xAxisLabel;
xAxisLabel = value;
return chart;
};
chart.yAxisLabel = function(value) {
if (!arguments.length) return yAxisLabel;
yAxisLabel = value;
return chart;
};
chart.xAxisLabelOffset = function(value) {
if (!arguments.length) return xAxisLabelOffset;
xAxisLabelOffset = value;
return chart;
};
chart.yAxisLabelOffset = function(value) {
if (!arguments.length) return yAxisLabelOffset;
yAxisLabelOffset = value;
return chart;
};
chart.xTicks = function(value) {
if (!arguments.length) return xTicks;
xTicks = value;
return chart;
};
chart.yTicks = function(value) {
if (!arguments.length) return yTicks;
yTicks = value;
return chart;
};
chart.significanceThreshold = function(value) {
if (!arguments.length) return significanceThreshold;
significanceThreshold = value;
return chart;
};
chart.foldChangeThreshold = function(value) {
if (!arguments.length) return foldChangeThreshold;
foldChangeThreshold = value;
return chart;
};
chart.colorRange = function(value) {
if (!arguments.length) return colorRange;
colorRange = value;
return chart;
};
chart.sampleID = function(value) {
if (!arguments.length) return sampleID;
sampleID = value;
return chart;
};
chart.expt_No = function(value){
if(!arguments.length) return expt_No;
expt_No = value;
return chart;
}
return chart;
}
//render chart 1
var yLabel = '-log(Adjusted P-value)',
xLabel = 'Mean change in Bacterial Intensity wrt DMSO (%)';
var volcanoPlot1 = volcanoPlot1()
.xAxisLabel(xLabel)
.yAxisLabel(yLabel)
.foldChangeThreshold(15.5)
.sampleID("Drug_No")
.expt_No("Experiment_No")
.xColumn("Perc_change_IntegInt")
.yColumn("p_value_IntegInt");
function updateData()
{
d3.csv('test.csv', parser,function(error, data){
if (error) console.log(error);
d3.select('#report-chart1')
.data([data])
.call(volcanoPlot1);
});
}
//parser for csv
// row parser to convert key values into numbers if possible
function parser(d) {
for (var key in d) {
if (d.hasOwnProperty(key)) {
d[key] = numberParser(d[key]);
}
}
return d;
}
// function to turn string into number if possible
function numberParser(value){
return (+value) ? +value : value;
}
当我单击不同的复选框时,呈现了多个图表。我该如何解决?我只想根据选择的内容来显示它们。