I am new using d3.js. I like to represent a multiline chart. In the x axis the years, in the y axis the quantity of patents every country has. Every line should be a different country.
I have a csv file with the following information:
PATENT,GYEAR,GDATE,APPYEAR,COUNTRY
3070801,1963,1096,,"BE"
3070802,1963,1096,,"US"
3070802,1963,1096,,"US"
3070802,1963,1096,,"US"
3070802,1963,1096,,"US"
3070803,1964,1096,,"US"
3070804,1964,1096,,"US"
3070801,1964,1096,,"BE"
3070801,1964,1096,,"BE"
3070801,1964,1096,,"BE"
3070801,1964,1096,,"BE"
3070801,1964,1096,,"BE"
3070801,1964,1096,,"BE"
...
I use a nested structure like the following:
var countries = d3.nest()
.key(function(d) { return d.COUNTRY; })
.key(function(d) { return d.GYEAR; })
.rollup(function(v) { return { "total": v.length} })
.map(data);
This structure give me the information in the following way:
BE: Object
1963: Object
total: 1
1964: Object
total: 6
US: Object
1963: Object
total: 4
1964: Object
total: 2
My script:
<script>
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y").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");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) {...}) //not so sure how to obtain the x and y
.y(function(d) {... });
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 + ")");
d3.csv("data3", function(error, data) {
if (error) throw error;
color.domain(d3.keys(data[0]).filter(function (key) {
return key !== "GYEAR";
}));
data.forEach(function(d) {
d.GYEAR = parseDate(String(d.GYEAR));
});
var countries = d3.nest()
.key(function(d) { return d.COUNTRY; })
.key(function(d) { return d.GYEAR; })
.rollup(function(v) { return { "total": v.length} })
.map(data);
x.domain(d3.extent(data, function (d) {
return d.GYEAR;
}));
y.domain([0,10]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.style({'stroke': 'Black', 'fill': 'none', 'stroke-width': '1.5px'})
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style({'stroke': 'Black', 'fill': 'none', 'stroke-width': '1.5px'})
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Cantidad");
var city = svg.selectAll(".country")
.data(countries)
.enter().append("g")
.attr("class", "country");
//How to append path?
city.append("path")
.attr("class", "line")
.attr("d", function(d) {...})
.style("stroke", function(d) {...});
});
</script>
How can I construct my var line? How can I append the path?
Thanks in advance.
For generating line function you can do:
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) {console.log(x(d.year));return x(d.year)}) // x will be year
.y(function(d) {console.log(y(d.total));return y(d.total)}); //y will be total
For rollup function get all the data:
var countries = d3.nest()
.key(function(d) { return d.COUNTRY; })
.key(function(d) { return d.GYEAR.getFullYear(); })
.rollup(function(v){
var pat = 0;
var yr = 0;
var country = ""
v.forEach(function(r){
pat += parseInt(r.PATENT);
yr = r.GYEAR;
country = r.COUNTRY
});
//store all the info like patent year country
return { "total": v.length, patent:pat, year:yr, country: country}
})
.map(data);
For setting values for Line:
var city = svg.selectAll(".country")
.data([countries.BE, countries.US])//this will genrate 2 lines for the two datset.
.enter().append("g")
.attr("class", "country");
//How to append path?
city.append("path")
.attr("class", "line")
.attr("d", function(d) {
var d_array = []
//for all the years make it an array
for (key in d) {
d_array.push(d[key])
}
return line(d_array);
})
.style("stroke", function(d) {
var country = "";
//the first object will tell the country
for (key in d) {
country = d[key].country;
break;
}
return color(country)
});
EDIT
For putting the countries in general form:
Instead of doing this:
.data([countries.BE, countries.US]),
Do this to get the array:
var country_data = [];
for (key in countries) {
country_data.push(countries[key])
}
and later do
.data(country_data),
Working code here
Cleaner code here
Hope this helps!
i have data for the first and following attempt of seeking asylum in germany for refugees and therefore two graphs which are looking like this
First one
Second one
Transition from one to another shoulnd't be a problem i suppose but what I want is so show both of them in one graph too. So a combination of both datasets for each country. But is it possible to distinguish from one another if I combine countries and the first and following ("erst/folge")? Each country should have on layer divided by two, one is the first attempt the other is the second attempt of this country. One idea to differ those sub-layers is maybe custom coloscale which I try right now. How can I show both data in one graph? Is it even possible to join both datasets and still see the difference?
Here is my html:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.chart {
background: #fff;
}
p {
font: 12px helvetica;
}
.axis path, .axis line {
fill: none;
stroke: #000;
stroke-width: 2px;
shape-rendering: crispEdges;
}
button {
position: absolute;
right: 50px;
top: 10px;
}
</style>
<body>
<script src="http://d3js.org/d3.v2.js"></script>
<div id="option">
<input name="updateButton"
type="button"
value="Show Data for second Attemp"
onclick="updateSecond('folgeantraege_monatlich_2015_mitentscheidungenbisnovember.csv')" />
</div>
<div id="option">
<input name="updateButton"
type="button"
value="Show Data for first Attemp"
onclick="updateFirst('erstantraege_monatlich_2015_mitentscheidungenbisnovember.csv')" />
</div>
<div id="option">
<input name="updateButton"
type="button"
value="Show both"
onclick="updateBoth('erstantraege_monatlich_2015_mitentscheidungenbisnovember.csv', 'folgeantraege_monatlich_2015_mitentscheidungenbisnovember.csv')" />
</div>
<div class="chart">
</div>
<script>
var margin = {top: 20, right: 40, bottom: 30, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height-10, 0]);
var dateParser = d3.time.format("%Y-%m-%d").parse;
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.value; });
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.date); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var z = d3.scale.category20()
chart("erstantraege_monatlich_2015_mitentscheidungenbisnovember.csv");
var datearray = [];
var colorrange = [];
function chart(csvpath) {
// var dateParser = d3.time.format("%Y-%m-%d").parse;
// var margin = {top: 20, right: 40, bottom: 30, left: 30};
// var width = document.body.clientWidth - margin.left - margin.right;
// var height = 400 - margin.top - margin.bottom;
// var x = d3.time.scale()
// .range([0, width]);
//
// var y = d3.scale.linear()
// .range([height-10, 0]);
// var z = d3.scale.category20()
//var color = d3.scale.category10()
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.months);
var yAxis = d3.svg.axis()
.scale(y);
var yAxisr = d3.svg.axis()
.scale(y);
// var stack = d3.layout.stack()
// .offset("zero")
// .values(function(d) { return d.values; })
// .x(function(d) { return d.date; })
// .y(function(d) { return d.value; });
var nest = d3.nest()
.key(function(d) { return d.Land});
// var nestFiltered = nest.filter(function(d){
// return d.Land != 'Total';
// })
// var area = d3.svg.area()
// .interpolate("cardinal")
// .x(function(d) { return x(d.date); })
// .y0(function(d) { return y(d.y0); })
// .y1(function(d) { return y(d.y0 + d.y); });
var svg = d3.select(".chart").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 + ")");
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = dateParser(d.Datum);
d.value = +d.ErstanträgeZahl;
});
//onsole.log(data);
var layers = stack(nest.entries(data));
console.log(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
svg.selectAll(".layer")
.data(layers)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d.values); })
.style("fill", function(d, i) { return z(i); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
svg.append("g")
.attr("class", "y axis")
.call(yAxis.orient("left"));
});
}
function updateSecond(csvpath) {
var nest = d3.nest()
.key(function(d) { return d.Land});
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = dateParser(d.Datum);
d.value = +d.Summe;
console.log(d.date);
console.log(d.value);
});
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
d3.selectAll("path")
.data(layers)
.transition()
.duration(750)
.style("fill", function(d, i) { return z(i); })
.attr("d", function(d) { return area(d.values); });
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
function updateFirst(csvpath) {
var nest = d3.nest()
.key(function(d) { return d.Land});
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
d.date = dateParser(d.Datum);
d.value = +d.ErstanträgeZahl;
console.log(d.date);
console.log(d.value);
});
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
d3.selectAll("path")
.data(layers)
.transition()
.duration(750)
.style("fill", function(d, i) { return z(i); })
.attr("d", function(d) { return area(d.values); });
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
function updateBoth(csvpathFirst, csvpathSecond){
var nest = d3.nest()
.key(function(d) { return d.Land});
d3.csv(csvpathFirst, function(data1) {
d3.csv(csvpathSecond, function(data2) {
});
});
}
</script>
And my data is here at my repo
EDIT1:
For example csv1 contains
Datum,Land,Summe,Position,Antragsart,EntscheidungenInsgesamt,Asylberechtigt,Flüchtling,GewährungVonSubsidiäremSchutz,Abschiebungsverbot,UnbegrenzteAblehnungen,Ablehnung,sonstigeVerfahrenserledigungen
2015-01-01,Afghanistan,1129,5,Erst,418,0,105,4,58,66,6,179
2015-02-01,Afghanistan,969,5,Erst,849,9,186,16,100,131,10,397
2015-03-01,Afghanistan,885,5,Erst,1376,17,309,58,158,201,11,622
2015-04-01,Afghanistan,1119,6,Erst,1838,21,384,75,202,261,15,880
2015-05-01,Afghanistan,1151,6,Erst,2272,21,499,91,249,303,16,1093
2015-06-01,Afghanistan,2051,6,Erst,2911,23,683,132,313,377,19,1364
2015-07-01,Afghanistan,2104,6,Erst,3340,27,767,160,366,431,21,1568
2015-08-01,Afghanistan,2270,5,Erst,3660,28,922,172,409,453,23,1653
2015-09-01,Afghanistan,2724,4,Erst,4057,36,1049,201,455,475,26,1815
2015-10-01,Afghanistan,3770,4,Erst,4540,37,1188,234,516,538,29,1998
2015-11-01,Afghanistan,4929,0,Erst,5026,46,1340,253,620,623,49,2095
And csv2 contains
Datum,Antragsart,Land,Summe,Position,Datum2,Position,Herkunft,Entscheidungeninsgesamt,Asylberechtigt,Prozent,Flüchtling,Pronzent,GewährungvonsubisdiäremSchutz,Prozent,Abschiebungsverbot,Prozent,UnbegrenzteAblehnungen,Prozent,Ablehnung,Prozent,keinweiteresverfahren,Prozent,sonstigeVerfahrenserledigungen,Prozent
2015-01-01,Folge,Afghanistan,33,10,2015-01-01,10,Afghanistan,29,0,0,5,17.2,2,6.9,8,27.6,0,0,0,0,1,3.4,13,44.8
2015-02-01,Folge,Afghanistan,29,10,2015-02-01,10,Afghanistan,81,0,0,13,16,4,4.9,22,27.2,0,0,0,0,10,12.3,32,39.5
2015-03-01,Folge,Afghanistan,41,9,2015-03-01,9,Afghanistan,135,0,0,21,15.6,10,7.4,37,27.4,1,0.7,0,0,23,17,43,31.9
2015-04-01,Folge,Afghanistan,25,10,2015-04-01,10,Afghanistan,165,0,0,34,20.6,12,7.3,41,24.8,4,2.4,0,0,30,18.2,44,26.7
2015-05-01,Folge,Afghanistan,37,9,2015-05-01,9,Afghanistan,212,0,0,54,25.5,12,5.7,50,23.6,4,1.9,0,0,32,15.1,60,28.3
2015-06-01,Folge,Afghanistan,35,9,2015-06-01,9,Afghanistan,261,0,0,72,27.6,17,6.5,59,22.6,6,2.3,0,0,35,13.4,72,27.6
2015-07-01,Folge,Afghanistan,35,9,2015-07-01,9,Afghanistan,288,0,0,82,28.5,17,5.9,64,22.2,6,2.1,0,0,42,14.6,77,26.7
2015-08-01,Folge,Afghanistan,34,9,2015-08-01,9,Afghanistan,321,0,0,100,31.2,20,6.2,66,20.6,6,1.9,0,0,52,16.2,77,24
2015-09-01,Folge,Afghanistan,27,4,2015-09-01,9,Afghanistan,354,0,0,120,33.9,20,5.6,72,20.3,7,2,0,0,54,15.3,81,22.9
2015-10-01,Folge,Afghanistan,24,9,2015-10-01,9,Afghanistan,389,0,0,136,35,20,5.1,83,21.3,7,1.8,0,0,54,13.9,89,22.9
2015-11-01,Folge,Afghanistan,47,,,,,431,1,0.2,148,34.3,23,5.3,97,22.5,8,1.9,0,0,58,13.5,96,22.3
The values ("Summe") should sum up the values per month of each country (Afghanistan) but also should reflect the values for their stacks on their own (Right now I'm trying to figur out how to use texture.js and custom scales to use textures to distinguish the colors from another because every country should have it's own color in this graph but as I already mentioned they should be different in their sublayers
When I try to put both csv fiels in one file I get not exactly but something similar to this
Can you give me some tips how to archive sub-layers (data structure/algorithm or what i takes to achieve this) so I can proceed and try to implement textures?
Thanks in advance
Final EDIT as answer to Cyrils :
var margin = {top: 20, right: 40, bottom: 30, left: 30};
var width = document.body.clientWidth - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height-10, 0]);
var dateParser = d3.time.format("%Y-%m-%d").parse;
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
.x(function(d) { return d.graphDate; })
.y(function(d) { return d.value; });
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.graphDate); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var z = d3.scale.category20()
doInit();
updateFirst('data/all.csv');
function doInit(){
//make the svg and axis
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.months);
yAxis = d3.svg.axis()
.scale(y);
yAxisr = d3.svg.axis()
.scale(y);
//make svg
var graph = d3.select(".chart").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 + ")");
graph.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
graph.append("g")
.attr("class", "y axis yright")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis.orient("right"));
graph.append("g")
.attr("class", "y axis yleft")
.call(yAxis.orient("left"));
}
function updateFirst(csvpath) {
var nest = d3.nest()
.key(function(d) { return d.Land+ "-" + d.Antragsart});
//console.log(nest);
d3.csv(csvpath, function(data) {
data.forEach(function(d) {
//console.log(data);
d.graphDate = dateParser(d.Datum);
d.value = +d.Summe;
d.type= d.Antragsart;
});
var layers = stack(nest.entries(data)).sort(function(a,b){return d3.ascending(a.key, b.key)});
console.log(layers);
x.domain(d3.extent(data, function(d) { return d.graphDate; }));
y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
var k = d3.select("g .x")
.call(xAxis);
d3.select("g .yright")
.call(yAxis);
d3.select("g .yleft")
.call(yAxis);
d3.selectAll("defs").remove();
d3.select(".chart svg g").selectAll("path").remove();
d3.select(".chart svg g").selectAll("path")
.data(layers).enter().append("path")
//.style("fill", function(d, i) { console.log(d.key);return z(d.key); })
.attr("class", function(d){
var country = d.key.split("-")[0];
var src = d.key.split("-")[1];
return src;
})
.style("fill", function(d){
var country = d.key.split("-")[0];
var src = d.key.split("-")[1];
if (src === "Folge"){
var t = textures.lines().thicker(2).stroke(z(country));
d3.select(".chart").select("svg").call(t);
return t.url();
} else {
return z(country);
}
})
.attr("d", function(d) { return area(d.values); });
});
}
For merging the records I am making use of d3 queue..Read here
The purpose of this is to load 2 CSV via ajax and when both loaded calls the callback.
queue()
.defer(d3.csv, csvpathFirst) //using queue so that callback is called after loading both CSVs
.defer(d3.csv, csvpathSecond)
.await(makeMyChart);
function makeMyChart(error, first, second) {
var data = [];
Make the nested function based on country and csv
var nest = d3.nest()
.key(function(d) {
return d.Land + "-" + d.src; //d.src is first if first csv second if vice versa
});
Next I am merging the records like this:
//iterate first
first.forEach(function(d) {
d.graphDate = dateParser(d.Datum);
d.value = +d.Summe;
d.src = "first"
data.push(d)
});
//iterate second
second.forEach(function(d) {
d.graphDate = dateParser(d.Datum);
d.value = +d.Summe;
d.src = "second"
data.push(d)
});
//sort layers on basis of country
var layers = stack(nest.entries(data)).sort(function(a, b) {
return d3.ascending(a.key, b.key)
});
Regenerate the axis like this:
//regenerate the axis with new domains
var k = d3.select("g .x")
.call(xAxis);
d3.select("g .yright")
.call(yAxis);
d3.select("g .yleft")
.call(yAxis);
Remove all old paths and defs DOM like this:
d3.selectAll("defs").remove();
d3.select(".chart svg g").selectAll("path").remove();
Next based on country and first csv and second csv add style fill.
.style("fill", function(d) {
var country = d.key.split("-")[0];
var src = d.key.split("-")[1];
if (src === "first") {
//use texture.js for pattern
var t = textures.lines().thicker().stroke(z(country));
d3.select(".chart").select("svg").call(t);
return t.url();
} else {
return z(country);
}
})
Working code here
Hope this helps!
I'm trying to build this trend component that is able to zoom and pan in data fetched with d3.json. First off, here's my code:
<script>
var margin = { top: 20, right: 80, bottom: 20, left: 50 },
width = $("#trendcontainer").width() - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var format = d3.time.format("%Y-%m-%d").parse;
var x = d3.time.scale()
.domain([-width / 2, width / 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([-height / 2, height / 2])
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-width);
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.value);
});
var svg = d3.select(".panel-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 + ")")
.call(zoom);
d3.json('#Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = 5})', function(error, json) {
$('#processing').hide();
color.domain(d3.keys(json[0]).filter(function(key) {
return key !== "Time" && key !== "Id";
}));
data.forEach(function(d) { var date = new Date(parseInt(d.Time.substr(6))); d.Time = date; });
var instruments = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.Time,
value: +d[name]
};
})
};
});
x.domain(d3.extent(data, function(d) { return d.Time; }));
y.domain([
d3.min(instruments, function(c) {
return d3.min(c.values, function(v) {
return v.value;
});
}),
d3.max(instruments, function(c) {
return d3.max(c.values, function(v) {
return v.value;
});
})
]);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var instrument = svg.selectAll(".instrument")
.data(instruments)
.enter().append("g")
.attr("class", "instrument");
instrument.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) { return color(d.name); });
instrument.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.value) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
});
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
};
var make_x_axis = function() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
};
</script>
Problem here being that the zooming / panning does not interact with my lines. The just stay the same, 'below' the zoomable / pannable grid. Also, one of the lines disappear when trying to zoom / pan and my console says the following:
Error: Problem parsing d="" - referring to the following snippet, last line:
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
};
Here's the content of my json result from the controller:
[{"Weight":0.0,"Speed":59.9,"Depth":362.24000,"Time":"2014-04-09T10:01:23","Id":0},{"Weight":10.0,"Speed":59.9,"Depth":394.07000,"Time":"2014-04-09T10:01:56","Id":1},{"Weight":971.0,"Speed":70.1,"Depth":425.84650,"Time":"2014-04-09T10:02:28","Id":2},{"Weight":0.0,"Speed":-29.9,"Depth":422.07465,"Time":"2014-04-09T10:03:00","Id":3},{"Weight":1321.0,"Speed":-21.6,"Depth":406.32840,"Time":"2014-04-09T10:03:32","Id":4},{"Weight":-6.0,"Speed":-30.0,"Depth":390.57880,"Time":"2014-04-09T10:04:04","Id":5},{"Weight":3.0,"Speed":59.9,"Depth":404.50380,"Time":"2014-04-09T10:04:36","Id":6},{"Weight":609.0,"Speed":59.9,"Depth":435.79380,"Time":"2014-04-09T10:05:08","Id":7},{"Weight":1.0,"Speed":59.9,"Depth":467.95280,"Time":"2014-04-09T10:05:40","Id":8},{"Weight":-2149.0,"Speed":34.6,"Depth":498.61060,"Time":"2014-04-09T10:06:12","Id":9},{"Weight":2.0,"Speed":59.9,"Depth":529.83060,"Time":"2014-04-09T10:06:44","Id":10}]
Trend looks like this in my view now, but the actual lines don't zoom or pan. Only the overlaying grid (black lines) does;
For simplicitys sake, I've considered just starting over, following the original example found here, but I really struggle with placing json-loaded data into this.
Hopefully, someone can help me figure this out :)
Thanks to Lars, I was finally able to solve this. Ultimately, I had to do some changes to my controller in addition to using this fiddle which assigns the scales to the zoom behaviour after setting the domains, so it returns a json string to my view like this:
string json = JsonConvert.SerializeObject(Model.Trend.ToArray());
return Json(json, JsonRequestBehavior.AllowGet);
This was due to the fact that some errors appeared when zooming / panning on the array returned without being serialized before returned to the view.
Also had to do the following for it to work:
d3.json('#Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = 5})', function(error, tmparray) {
var json = JSON.parse(tmparray);
...
)};
If this step is skipped, my data will not be displayed properly for some reason, being squeezed to the left side of my graph.