Removing previous paths in d3.js with transition to new data - javascript

I currently am running a page which generates a graph with default values upon page load. The page takes the data from a TSV generated by a PHP script, modified by GET parameters.
The user can then input options, and update the graph through AJAX.
Currently the page is almost working, but it is is overlaying the new paths with the new data without removing the old paths.
The new data has the same x range and domain but different y coordinate values, sometimes with a different number of values.
Ideally I would like the old paths to fluidly transition from the old paths - how can I make this occur?
I've tried to include the relevant code below. Apologies for its poor quality, I am very new to d3.
...
var line = d3.svg.line()
.interpolate("basis")
.defined(function(d) {
return d.result != 0;
})
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.result);
});
var svg = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var txtDays = 7;
var txtStartDate = "01/01/2013";
var txtEndDate = "01/01/2014";
var txtInterval = 1;
requestDataURL = //removed for SO
d3.tsv("http://localhost" + requestDataURL, function(error, data) {
var varPolls = d3.keys(data[0]).filter(function(key) {
return key !== "date";
});
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var results = varPolls.map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.date,
result: +d[name]
};
})
};
});
x.domain(d3.extent(data, function(d) {
return d.date;
}));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var group = svg.selectAll(".group")
.data(results)
.enter().append("g")
.attr("class", "group")
.attr("data-name", function(d) {
return d.name;
});
group.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return colors[d.name];
});
group.append("text")
.datum(function(d) {
return {
name: d.name,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function(d) {
return "translate(" + x(d.value.date) + "," + y(d.value.result) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) {
return Math.round(d.value.result);;
});
d3.select(".submit")
.attr('disabled', null);
});
$(".submit").click(function(event) {
var data = [];
//SORT OUT VALIDATION
var req = $.ajax({
url: requestDataURL,
dataType: 'text',
success: function(response) {
data = response;
}
});
requestDataURL = //new data removed for SO
$.when(req).done(function() {
d3.tsv("http://localhost" + requestDataURL, function(error, data) {
var varPolls = d3.keys(data[0]).filter(function(key) {
return key !== "date";
});
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var results = varPolls.map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.date,
result: +d[name]
};
})
};
});
x.domain(d3.extent(data, function(d) {
return d.date;
}));
var group = svg.selectAll(".chart")
.data(results);
group.exit().remove();
group.enter().append("g");
group.attr("class", "group")
.attr("data-name", function(d) {
return d.name;
});
group.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return colors[d.name];
});
group.transition()
.duration(500)
.ease("linear")
.attr("d", group);
});
});
});

The problem is that you're not handling the enter and update selections correctly. As a rule, append operations should only happen on enter selections, not update. When you're getting new data, you have the following code:
group.enter().append("g");
// ...
group.append("path");
This will append new path elements to the update selection, which is what you're seeing in the graph. The proper way to handle new data would look as follows:
var enterSel = group.enter().append("g");
// set attributes on the g elements
enterSel.append("path"); // append path elements to the new g elements
group.select("path") // select the path elements that are present, this includes the newly appended ones
.attr("d", function(d) { // update the d attribute
return line(d.values);
});
This code will append new elements for data items that have no corresponding elements and update the paths for existing elements.

Related

How to auto-sort a bar-chart with a toggle function

I've uploaded a block (FIXED) where you can toggle a sorting function.
What I want to add now is some kind of if statement when the checkbox is on, and when it is on I want the bars to sort automatically when you change year or category, and when you toggle it again it stops auto-sorting.
I thought a simple
if (document.getElementsByClassName('myCheckbox').checked) {
change();
}
Within the update function would work but nothing happens.
Any help is appreciated!
I started an answer your direct question, but soon realized that your code needed a bit of refactor. You had a bit too much copy/paste going on with redundant code and too many things drawing. When coding with d3 you should try for a single function that does all the drawing.
Here's the code running.
Here's a snippet of the new one update function to rule them all:
function update() {
file = d3.select('#year').property('value') == 'data2017' ? 'data.csv' : 'data2.csv';
catInt = d3.select('#category').property('value');
d3.csv(file, type, function(error,data) {
if(error) throw error;
var sortIndex = data.map(function(d){ return d.month});
// Update domain
y.domain([0, d3.max(data, function(d) {
return d["Category" + catInt]; })
]).nice();
// Update axis
g.selectAll(".axis.axis--y").transition()
.duration(750)
.call(yAxis);
g.selectAll(".axis.grid--y").transition()
.duration(750)
.call(yGrid);
// Sums and averages
let sumOfAll = d3.sum(data, function(d) {
return d["Category" + catInt];
});
let avgValue = d3.sum(data, function(d) {
return d["Category" + catInt];
}) / data.length;
//sort data
data.sort( d3.select("#myCheckbox").property("checked")
? function(a, b) { return b["Category" + catInt] - a["Category" + catInt]; }
: function(a, b) { return sortIndex.indexOf(a.month) - sortIndex.indexOf(b.month);})
// set x domain
x.domain(data.map(function(d) { return d.month; }));
g.selectAll(".axis.axis--x").transition()
.duration(750)
.call(xAxis);
// Update rectangles
let bars = g.selectAll(".barEnter")
.data(data, function(d){
return d.month;
});
bars = bars
.enter()
.append("rect")
.attr("class", "barEnter") // Enter data reference
.attr("width", x.bandwidth())
.merge(bars);
bars.transition()
.duration(750)
.attr("height", function(d) {
return height - y(d["Category" + catInt]);
})
.attr("x", function(d) {
return x(d.month);
})
.attr("y", function(d) {
return y(d["Category" + catInt]);
});
bars.exit().remove();
// Update text on rectangles
let textUpdate = g.selectAll(".textEnter")
.data(data, function(d){
return d.month;
});
textUpdate = textUpdate.enter()
.append("text")
.style("text-shadow","1px 1px #777")
.attr("class", "textEnter") // Enter data reference
.attr("text-anchor","middle")
.attr("font-size",11)
.attr("fill","#fff")
.merge(textUpdate);
textUpdate.transition()
.duration(750)
.attr("y", function(d) {
return y(d["Category" + catInt]) + 15;
})
// Update text value
.text( function(d) {
return d["Category" + catInt];
})
.attr("x", function(d) {
return x(d.month) + x.bandwidth()/2;
})
// Update sum and avg value
g.selectAll("#totalValue").transition()
.duration(750)
.text(sumOfAll + " Category " + catInt)
g.selectAll("#avgValue").transition()
.duration(750)
.text(formatValue(avgValue))
});
}

d3 nested grouped bar chart

First of all sorry if my English is difficult to understand, I'll try my best...
I am rather new to D3.js and I'm trying to create a D3 grouped bar chart using nested data. I have looked at some solutions shared here, but they only show one-level grouping. In my case, data will come from a csv file that has this data structure:
groups,categories,value 1,value 2,value 3
group 1,A,61.0158803,25.903359,13.08076071
group 1,B,71.27703826,21.0180133,7.70494844
group 1,C,82.70203982,13.52731445,3.770645737
group 2,A,58.85721523,28.25939061,12.88339417
group 2,B,71.39695487,20.66010982,7.942935308
group 2,C,82.22389321,13.68924542,4.08686137
The chart is intended to have two x axis, one for the groups (level 0) and one for the categories (level 1).Values 1 to 3 will display as grouped bars for each catergory, and the categories will be displayed within the corresponding group.
The structure of the chart should be:
value 1 | value 2 | value 3 | value 1 | value 2 | value 3 | value 1 | value 2 | value 3 |
| category A | category B | category C |
| group 1 |
and the same for group 2, placed contiguous.
The problem is with the code I am working on, I get the right axis but data corresponding two both groups are shown, one on top of the other, in each group area. I am not able to link the data on the categories to their corresponding group in orther to draw them where it corresponds.
Here is the code I've got so far:
var x0 = d3.scale.ordinal()
.rangeRoundBands([0,width], 0);
var x1 = d3.scale.ordinal()
.rangeRoundBands([0,width]);
var x2 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height,0]);
var color = d3.scale.category10();
var x0Axis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var x1Axis = d3.svg.axis()
.scale(x1)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select(".chart")
.append("svg")
.attr("class", "svg")
.attr("viewBox", "" + margin* -1 + " " + margin* -1 + " " + (width + margin*2) + " " + (height + margin *2) + "")
.attr ("preserveAspectRatio", "xMidYMid")
.attr("width", "100%")
.attr("height", "100%")
d3.csv("../data/EQ01.csv", function(error, data){
if (error) throw error;
var seriesNames = d3.keys(data[0]).filter(function(key) { return key !== "categories" && key !== "groups";});
data.forEach(function(d) {
d.values = seriesNames.map(function(name) { return {
xValue: name,
yValue: +d[name]
};
});
});
nested = d3.nest()
.key(function(d) { return d.groups})
.key(function(d) { return d.categories})
.entries(data);
y.domain([0, d3.max(data, function(d) { return d3.max(d.values, function(d) { return d.yValue; }); })]);
x0.domain(nested.map(function(d) {return d.key;}));
x1.domain(data.map(function(d) { return d.categories; })).rangeRoundBands([0, x0.rangeBand() ], 0.1);
x2.domain(seriesNames).rangeRoundBands([0, x1.rangeBand()], 0);
svg.append("g")
.attr("class", "x0 axis")
.attr("transform", "translate(0," + (height+30) + ")")
.call(x0Axis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var group = svg.selectAll(".group")
.data(nested)
.enter().append("g")
.attr("class", "group")
.attr("transform", function(d) { return "translate(" + x0(d.key) + ",0)"; });
group.append("g")
.attr("class", "x1 axis")
.attr("transform", "translate(0," + height + ")")
.call(x1Axis);
var category = group.selectAll(".category")
.data(data)
.enter().append("g")
.attr("class", "category")
.attr("transform", function(d) { return "translate(" + x1(d.categories) + ",0)"; });
category.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x2.rangeBand())
.attr("x", function(d) { return x2(d.xValue); })
.attr("y", function(d) { return y(d.yValue); })
.attr("height", function(d) { return height - y(d.yValue); })
.style("fill", function(d){return color(d.xValue)})
Many thanks in advance for the help!
The issue is that you are not joining correctly your data with your elements.
We need to build different scales in order to obtain the correct rangeBand value.
var x_groups = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x_categories = d3.scale.ordinal();
var x_values = d3.scale.ordinal();
I created a nested data structure that will contain everything we need for our grouped bar chart approach.
var nested = d3.nest()
.key(function(d) {
return d.groups;
})
.key(function(d) {
return d.categories;
})
.rollup(function(leaves) {
return [{
key: 'v-a',
value: leaves[0]['value 1']
}, {
key: 'v-b',
value: leaves[0]['value 2']
}, {
key: 'v-c',
value: leaves[0]['value 3']
}];
})
.entries(data);
Next lets configure our scales with the information we just got.
x_groups.domain(nested.map(function(d) {
return d.key;
}));
//var categories = ['A', 'B', 'C'];
var categories = nested[0].values.map(function(d, i) {
return d.key;
});
x_categories.domain(categories).rangeRoundBands([0, x_groups.rangeBand()]);
//var values = ['value 1', 'value 2', 'value 3'];
var values = nested[0].values[0].values.map(function(d, i) {
return d.key;
});
x_values.domain(values).rangeRoundBands([0, x_categories.rangeBand()]);
Then we can finally start our data join. You can see that when we enter a new level of info we need to set the data function correctly.
var groups_g = svg.selectAll(".group")
.data(nested)
.enter().append("g")
.attr("class", function(d) {
return 'group group-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_groups(d.key) + ",0)";
});
var categories_g = groups_g.selectAll(".category")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'category category-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_categories(d.key) + ",0)";
});
var categories_labels = categories_g.selectAll('.category-label')
.data(function(d) {
return [d.key];
})
.enter().append("text")
.attr("class", function(d) {
return 'category-label category-label-' + d;
})
.attr("x", function(d) {
return x_categories.rangeBand() / 2;
})
.attr('y', function(d) {
return height + 25;
})
.attr('text-anchor', 'middle')
.text(function(d) {
return d;
})
var values_g = categories_g.selectAll(".value")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'value value-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_values(d.key) + ",0)";
});
var values_labels = values_g.selectAll('.value-label')
.data(function(d) {
return [d.key];
})
.enter().append("text")
.attr("class", function(d) {
return 'value-label value-label-' + d;
})
.attr("x", function(d) {
return x_values.rangeBand() / 2;
})
.attr('y', function(d) {
return height + 10;
})
.attr('text-anchor', 'middle')
.text(function(d) {
return d;
})
var rects = values_g.selectAll('.rect')
.data(function(d) {
return [d];
})
.enter().append("rect")
.attr("class", "rect")
.attr("width", x_values.rangeBand())
.attr("x", function(d) {
return 0;
})
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d) {
return color(d.key);
});
Working plnkr: https://plnkr.co/edit/qGZ1YuyFZnVtp04bqZki?p=preview

updating/modifying d3 word cloud with new data

I'm trying to figure out how to modify and update from a selection of data with d3.js wordcloud.
Currently, I'm showing the top 10 results from a selection of data depending on indexed keys. I'd like to be able to switch this data depending on the keys, or if I want the top 10 or bottom 10 words.
here is a plnk so far;
http://plnkr.co/edit/cDTeGDaOoO5bXBZTHlhV?p=preview
I've been trying to refer to these guides, General Update Pattern, III and Animated d3 word cloud. However, I'm struggling to comprehend how to introduce a final update function, as almost all guides referring to this usually use a setTimeout to demonstrate how to update, and my brain just won't make the connection.
Any advice is most welcome!
Cheers,
(code here)
var width = 455;
var height = 310;
var fontScale = d3.scale.linear().range([0, 30]);
var fill = d3.scale.category20();
var svg = d3.select("#vis").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")")
// .selectAll("text")
d3.json("data.json", function(error, data) {
if (error) {
console.log(error)
}
else {
data = data
}
function sortObject(obj) {
var newValue = [];
var orgS = "MC";
var dateS = "Jan";
for (var question = 0; question < data.questions.length; question++) {
var organization = data.organizations.indexOf(orgS);
var date = data.dates.indexOf(dateS);
newValue.push({
label: data.questions[question],
value: data.values[question][organization][date]
});
}
newValue.sort(function(a, b) {
return b.value - a.value;
});
newValue.splice(10, 50)
return newValue;
}
var newValue = sortObject();
fontScale.domain([
d3.min(newValue, function(d) {
return d.value
}),
d3.max(newValue, function(d) {
return d.value
}),
]);
d3.layout.cloud().size([width, height])
.words(newValue)
.rotate(0)
.text(function(d) {
return d.label;
})
.font("Impact")
.fontSize(function(d) {
return fontScale(d.value)
})
.on("end", draw)
.start();
function draw(words) {
var selectVis = svg.selectAll("text")
.data(words)
selectVis
.enter().append("text")
.style("font-size", function(d) {
return fontScale(d.value)
})
.style("font-family", "Impact")
.style("fill", function(d, i) {
return fill(i);
})
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) {
return d.label;
})
selectVis
.transition()
.duration(600)
.style("font-size", function(d) {
return fontScale(d.value)
})
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.style("fill-opacity", 1);
selectVis.exit()
.transition()
.duration(200)
.style('fill-opacity', 1e-6)
.attr('font-size', 1)
.remove();
}
});
I did not see any update function within your code so I added that functionality in order to watch how the update works.
// Add a select elemnt to the page
var dropDown = d3.select("#drop")
.append("select")
.attr("name", "food-venues");
// Join with your venues
var foodVenues = data.organizations.map(function(d, i) {
return d;
})
// Append the venues as options
var options = dropDown.selectAll("option")
.data(foodVenues)
.enter()
.append("option")
.text(function(d) {
return d;
})
.attr("value", function(d) {
return d;
})
// On change call the update function
dropDown.on("change", update);
In order for a d3 word cloud to update correctly you need to calculate again the layout with the desired data
function update() {
// Using your function and the value of the venue to filter data
var filteredData = sortObject(data, this.value);
// Calculate the new domain with the new values
fontScale.domain([
d3.min(newValue, function(d) {
return d.value
}),
d3.max(newValue, function(d) {
return d.value
}),
]);
// Calculate the layout with new values
d3.layout.cloud()
.size([width, height])
.words(filteredData)
.rotate(0)
.text(function(d) {
return d.label;
})
.font("Impact")
.fontSize(function(d) {
return fontScale(d.value)
})
.on("end", draw)
.start();
}
I modified your sortObject function to receive an extra parameter which is the desired venue:
function sortObject(obj, venue) {
var newValue = [];
var orgS = venue || "MC";
// ....
}
Here is the working plnkr: http://plnkr.co/edit/B20h2bNRkyTtfs4SxE0v?p=preview
You should be able to use this approach to update with your desired restrictions. You may be able to add a checkbox with a event listener that will trigger the update function.
In your html:
<input checked type="checkbox" id="top" value="true"> <label for="top">Show top words</label>
In your javascript:
var topCheckbox = d3.select('#top')
.on("change", function() {
console.log('update!')
});

RHS assignment manipulated over LHS manipulation

sap.ui.core.Control.extend("control.linechart", {
/* the control API */
metadata : {
properties : {
"items" : { type: "any" },
"height" : {type: "int"},
"width" : {type: "int"},
"popup" : {type: "any"}
},
events: {
"select" : {},
"selectEnd": {}
}
},
// the part creating the HTML:
renderer : function(oRm, oControl) { // static function, so use the given "oControl" instance instead of "this" in the renderer function
oRm.write("<div");
oRm.writeControlData(oControl); // writes the Control ID and enables event handling - important!
oRm.addClass("lineChart"); // add a CSS class for styles common to all control instances
oRm.writeClasses(); // this call writes the above class plus enables support for my.Bubble.addStyleClass(...)
oRm.write(">");
oRm.write("</div>");
},
onAfterRendering: function() {
data = this.getItems();
//alert(JSON.stringify(this.getItems()));
var passedheight = this.getHeight();
//var containerWidth = jQuery.sap.byId(this.oParent.sId).width() || 800; // gets super parent width
var containerWidth = $("#"+this.getId()).parent().width(); // gets immediate parent width
var margin = {top: 15, right: 30, bottom: 20, left: 30},
width = containerWidth- margin.left - margin.right,
height = passedheight - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y %H:%M %p").parse;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(4).tickSize(-width, 0, 0);
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.tonneValue); });
var svg = d3.select("#"+this.getId()).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 + ")");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var wsfs = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, tonneValue: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(wsfs, function(c) { return d3.min(c.values, function(v) { return v.tonneValue; }); }),
d3.max(wsfs, function(c) { return d3.max(c.values, function(v) { return v.tonneValue; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var wsf = svg.selectAll(".wsf")
.data(wsfs)
.enter().append("g")
.attr("class", "wsf");
wsf.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
var legendNames = d3.keys(data[0]).filter(function(key) { return key !== "date" });
data.forEach(function(d) {
d.ages = legendNames.map(function(name) { return {name: name, value: +d[name]}; });
});
var legend = svg.selectAll(".legend")
.data(legendNames.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 4)
.style("fill", function(d) {return color(d); });
legend.append("text")
.attr("x", width - 24)
.attr("y", 6)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
},
});
In this whole program why Right hand side value is changing i.e. when I do data = this.getItems(); I assume this.getItems is assigned to data. But data is manipulated in rest of the program but when oAfterRendering is invoked again I get the manipulated data thats there in variable data. How is this.getItems() i.e. items property is manipulated when data is the one that is manipulated.Due to use of Openui5 and custom controls there is no way to save the data in some temporary variable.
When you return an object from a function, JavaScript does not copy that object, but return a reference to it (similar a pointer in C).
This means that if it's modified, it will be reflected in all variables that point to it.
This is the same behaviour for Arrays and other objects.
Anything to avoid that.
You could return a clone of the object. Depending on how complex your object is, a deep clone could be necessary. Keep in mind that this shouldn't be done often, as it can likely affect performance.
An easy way of creating a shallow clone (really just copying properties, cloning any object is more nuanced in JavaScript) in ES6 is...
var cloned = Object.assign({}, objectToBeCloned);

On change event on d3.js library duplicate charts

I'm trying to do a chart with the help of the d3.js library,my data come from two sources and have the same format(tsv),I use a form to try to change the chart displayed according to which button has been clicked.My problem actually is that when I change the chart choice, the labels are duplicated as well as my charts.
My form look like this:
<form>
<label><input name="radio" type="radio" value="Incoming"/> Incoming</label>
<label><input name="radio" type="radio" value="Outgoing" checked="checked"/> Outgoing</label>
</form>
And the javascript part to retrieve values of the checked radio input:
draw("data.tsv");//on load load the default checked
d3.selectAll("input").on("change", change);
function change(){
var radios = document.getElementsByName('radio');
for (var i = 0, length = radios.length; i < length; i++) {
if (radios[i].checked) {
if(radios[i].value=="Outgoing"){
draw("data.tsv");
console.log(radios[i].value);
}
else{
draw("datasecond.tsv");
console.log(radios[i].value);
}
}
}
}
Thank you to give some advices!!!
EDIT:
the draw function:
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 + ")");
function draw(data){
d3.tsv(data, function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
//data.forEach(function(d) {
// d.date = parseDate(d.date);
//});
var cities="";
cities = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number");
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
city.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
});
}
it is hard to say without seeing the code of your draw function, but I guess that the explanation is that you are creating new axis() objects each time you call draw, instead of reusing the existing ones.
be sure that you keep references to your axis objects. create them once, and in your draw function reuse those instances.

Categories

Resources