Joohun Lee Joohun Lee - 27 days ago 7
Javascript Question

how to remove old plot and transition to new plot by choosing menu in D3

I'm trying to transition from plot to plot by changing menu.
My menu includes new column(feature: y axis) extracted from dataset and I'd like to redraw plot with new dots on x/y axis. however, my codes won't remove previous plot but keep on adding additional plot below old plot.
how do I make below codes to transition plot with delay instead of adding new below?

thanks,

var cValue = function(d) { return d[cVar];},
color = d3.scale.category10();

// add the tooltip area to the webpage
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);


// force data to update when menu is changed
var menu = d3.select("#menu select")
.on("change", change);

// load data
d3.csv("sample_data.csv", function(error, data) {
formatted = data;
redraw();
});


d3.select(window)
.on("keydown", function() { altKey = d3.event.altKey; })
.on("keyup", function() { altKey = false; });
var altKey;


// set terms of transition that will take place
// when a new indicator is chosen
function change() {
d3.transition()
.duration(altKey ? 7500 : 1500)
.each(redraw)
}

function redraw() {
// setup x
var xValue = function(d) { return d[xVar];}, // data -> value
xScale = d3.scale.ordinal()
.rangeRoundBands([0,width],1), //value -> display
xMap = function(d) { return (xScale(xValue(d)) + Math.random()*10);}, // data -> display
xAxis = d3.svg.axis().scale(xScale).orient("bottom");

// setup y
var yVar = menu.property("value"),
yValue = function(d) { return d[yVar];}, // data -> value
yMap = function(d) { return yScale(yValue(d));}, // data -> display
yScale = d3.scale.linear().range([height, 0]), // value -> display
yAxis = d3.svg.axis().scale(yScale).orient("left");

data = formatted.filter(function(d, i)
{
if (d[cVar] == Prod)
{
//console.log(d);
return d;
}
});
//console.log(yVar)

// change string (from CSV) into number format
data.forEach(function(d) {
d[xVar] = d[xVar];
d[yVar] = +d[yVar];
});

xScale.domain(data.sort(function(a, b) { return d3.ascending(a[xVar], b[xVar])})
.map(xValue) );
// don't want dots overlapping axis, so add in buffer to data domain
yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]);

// add the graph canvas to the body of the webpage
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// x-axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text(xVar);

// y-axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yVar);

// draw dots
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", radius)
.attr("cx", xMap)
.attr("cy", yMap)
.style("fill", function(d) { return color(cValue(d));})
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d[SN] + "<br/> (" + xValue(d)
+ ", " + yValue(d) + ")")
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
};

Answer

I found a way to answer this myself. at every call on menu selection, I can reset "svg" using "svg.remove()" and call "draw()". but it will redraw entire plot including x-axis/y-axis/legend/dot. this is not completely how I want to do, however, this will temporarily solve it and I can move forward.