Zooming datasets in d3.js - javascript

I have overlayed two datasets, a boundary map and a point map in d3.js. I want to be able to zoom both datasets at the same time. With the current code, only the point map responds to the zoom. How can I zoom both datasets at the same time
The code is shown below
var canvas = d3.select("body").append("svg")
.attr("width",260)
.attr("height",400)
d3.json("/Maps/iowastate.json",function (data){
var group = canvas.selectAll("g")
.data(data.features)
.enter()
.append("g")
var projection =d3.geo.mercator()
.scale(250)
//.translate([0,0]);
var path = d3.geo.path().projection(projection);
var areas = group.append("path")
.attr("d", path)
.attr("class","area")
.attr("fill","black");
d3.csv("/Maps/detectors.csv",function (d){
var group = canvas.selectAll("g")
.data(d)
.enter()
.append("circle")
.attr("cx", function(d) {
return projection([d.StartLong,d.StartLat])[0];
})
.attr("cy", function(d,i) {
return projection([d.StartLong,d.StartLat])[1];
})
.attr("r", 0.1)
.style("fill", "red");
//console.log(projection(d[0].StartLat))
var zoom = d3.behavior.zoom()
.on("zoom",function(){
group.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
group.selectAll("path")
.attr("d", path.projection(projection));
});
canvas.call(zoom)
})
var zoom = d3.behavior.zoom()
.on("zoom",function(){
group.attr("transform","translate("+
d3.event.translate.join(",")+")scale("+d3.event.scale+")");
group.selectAll("path")
.attr("d", path.projection(projection));
});
canvas.call(zoom)
})

You are applying the right modifications, but twice to the same set of elements instead of the two different layers. To make it work, keep a reference to the other group (e.g. by using different variable names) and apply the transformations to both groups.

Related

d3.js - Pie chart with interactive legend hover problems

I made d3.js pie chart and related legend with population data popu. When I hover over pie segments I achieved to enlarge related legend square parts and the pie segment itself (larger outerRadius). Now I am trying to do contrary. When I hover over square of legend I want to enlarge square itself and related pie segment as well. Something like this example here https://www.amcharts.com/demos/pie-chart-with-legend/. I will write down just part of the code related to pie chart problem that I have.
var pie = d3.pie()
.value(function(d) {return d.pop})(popu);
var seg = d3.arc()
.innerRadius(100)
.outerRadius(150)
.padAngle(.1)
.padRadius(45);
var segover = d3.arc()
.innerRadius(100)
.outerRadius(170)
.padAngle(.1)
.padRadius(45);
So this part is working great.
svg.append("g")
.attr("class", "pieChart")
.attr("transform", "translate(1250,570)")
.selectAll("path")
.data(pie)
.append("path")
.attr("class", "pie")
.attr("id", function(d){return d.data.id})
.attr("d", seg)
.on("mouseenter", function(d){
d3.select(this)
.transition(10)
.duration(100)
.attr("d", segover)
})
Then I tried to change pie chart segment when hovering on legend related segments.
var pieEl = svg.selectAll(".pie");
var piePath = pieEl.nodes();
svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(-50,280)")
.selectAll(".mySquers")
.data(pie)
.enter()
.append("rect")
.attr("class", "rec")
.attr("x", 100)
.attr("y", function(d,i){ return 100 + i*25})
.attr("width", "15")
.attr("height", "15")
.attr("id", function(d,i){ return (popu[d,i].id)})
.style("fill",function(d,i){
if (this.id == piePath[i].id){
return piePath[i].getAttribute("fill")
}
})
.on("mouseenter", function(d){
for (var i=0; i<piePath.length; i++){
if (piePath[i].id == d.data.id){
piePath[i].setAttribute("d", segover);
}}
})
When I tray to setAttribute("d", segover) in DOM instead of d attribute written as string as usually (d="M144.58.....") I have a function (d="function(pie){ _e);}" and on hover pie segment dissapear. But for example if I set attribute fill to red on hover it change and segment is painted. So the notation of code is good. Is there some behavior of d path generated with d3.arc() that I am missing? Any suggestion is welcome.
I think you should be passing your data as an argument in your function. Normally, it is taken as default argument when you return the function directly.
piePath[i].setAttribute("d", segover(*data associated with segment*));
svg.append("g")
.attr("class", "pieChart")
.attr("transform", "translate(1250,570)")
.selectAll("path")...
.attr("d", seg) // this is same as : attr("d", seg(d))
.on("mouseenter", function(d){
d3.select(this)
.transition(10)
.duration(100)
.attr("d", segover) // same here
})

D3 skipping first two features in a TopoJson

I am creating an interactive visualization tool with D3. I just got my map working today and I noticed that the first two features from the topojson are not loading in.
The first two entries of the topojson look like this and geojson.io reads these countries in fine. (They appear on the map)
"objects":{"ne_10m_admin_0_countries":{"type":"GeometryCollection","geometries":[{"arcs":[[[0,1]],[[2,3,4,5]],[[6,7]],[[8,9]],[[10]],[[11]],[[12]],[[13]],[[14]],[[15]],[[16]],[[17]],[[18]],[[19]],[[20]],[[21]],[[22]],[[23]],[[24]],[[25]],[[26]],[[27]],[[28]],[[29]],[[30]],[[31]],[[32]],[[33]],[[34]],[[35]],[[36]],[[37]],[[38]],[[39]],[[40]],[[41]],[[42]],[[43]],[[44]],[[45]],[[46]],[[47]],[[48]],[[49]],[[50]],[[51]],[[52]],[[53]],[[54]],[[55]],[[56]],[[57]],[[58]],[[59]],[[60]],[[61]],[[62]],[[63]],[[64]],[[65]],[[66]],[[67]],[[68]],[[69]],[[70]],[[71]],[[72]],[[73]],[[74]],[[75]],[[76]],[[77]],[[78]],[[79]],[[80]],[[81]],[[82]],[[83]],[[84]],[[85]],[[86]],[[87]],[[88]],[[89]],[[90]],[[91]],[[92]],[[93]],[[94]],[[95]],[[96]],[[97]],[[98]],[[99]],[[100]],[[101]],[[102]],[[103]],[[104]],[[105]],[[106]],[[107]],[[108]],[[109]],[[110]],[[111]],[[112]],[[113]],[[114]],[[115]],[[116]],[[117]],[[118]],[[119]],[[120]],[[121]],[[122]],[[123]],[[124]],[[125]],[[126]],[[127]],[[128]],[[129]],[[130]],[[131]]],"type":"MultiPolygon","properties":{"featurecla":"Admin-0 country","scalerank":5,"LABELRANK":2,"SOVEREIGNT":"Indonesia","SOV_A3":"IDN","ADM0_DIF":0,"LEVEL":2,"TYPE":"Sovereign country","ADMIN":"Indonesia","ADM0_A3":"IDN","GEOU_DIF":0,"GEOUNIT":"Indonesia","GU_A3":"IDN","SU_DIF":0,"SUBUNIT":"Indonesia","SU_A3":"IDN","BRK_DIFF":0,"NAME":"Indonesia","NAME_LONG":"Indonesia","BRK_A3":"IDN","BRK_NAME":"Indonesia","BRK_GROUP":"","ABBREV":"Indo.","POSTAL":"INDO","FORMAL_EN":"Republic of Indonesia","FORMAL_FR":"","NAME_CIAWF":"Indonesia","NOTE_ADM0":"","NOTE_BRK":"","NAME_SORT":"Indonesia","NAME_ALT":"","MAPCOLOR7":6,"MAPCOLOR8":6,"MAPCOLOR9":6,"MAPCOLOR13":11,"POP_EST":260580739,"POP_RANK":17,"GDP_MD_EST":3028000,"POP_YEAR":2017,"LASTCENSUS":2010,"GDP_YEAR":2016,"ECONOMY":"4. Emerging region: MIKT","INCOME_GRP":"4. Lower middle income","WIKIPEDIA":-99,"FIPS_10_":"ID","ISO_A2":"ID","ISO_A3":"IDN","ISO_A3_EH":"IDN","ISO_N3":"360","UN_A3":"360","WB_A2":"ID","WB_A3":"IDN","WOE_ID":23424846,"WOE_ID_EH":23424846,"WOE_NOTE":"Exact WOE match as country","ADM0_A3_IS":"IDN","ADM0_A3_US":"IDN","ADM0_A3_UN":-99,"ADM0_A3_WB":-99,"CONTINENT":"Asia","REGION_UN":"Asia","SUBREGION":"South-Eastern Asia","REGION_WB":"East Asia & Pacific","NAME_LEN":9,"LONG_LEN":9,"ABBREV_LEN":5,"TINY":-99,"HOMEPART":1,"MIN_ZOOM":0,"MIN_LABEL":1.7,"MAX_LABEL":6.7,"NE_ID":1159320845,"WIKIDATAID":"Q252","NAME_AR":"إندونيسيا","NAME_BN":"ইন্দোনেশিয়া","NAME_DE":"Indonesien","NAME_EN":"Indonesia","NAME_ES":"Indonesia","NAME_FR":"Indonésie","NAME_EL":"Ινδονησία","NAME_HI":"इंडोनेशिया","NAME_HU":"Indonézia","NAME_ID":"Indonesia","NAME_IT":"Indonesia","NAME_JA":"インドネシア","NAME_KO":"인도네시아","NAME_NL":"Indonesië","NAME_PL":"Indonezja","NAME_PT":"Indonésia","NAME_RU":"Индонезия","NAME_SV":"Indonesien","NAME_TR":"Endonezya","NAME_VI":"Indonesia","NAME_ZH":"印度尼西亚"}},{"arcs":[[[132,-1]],[[133,134]],[[135,-8,136,137,138,139]],[[140]],[[141]],[[142]],[[143]],[[144]],[[145]]],"type":"MultiPolygon","properties":{"featurecla":"Admin-0 country","scalerank":5,"LABELRANK":3,"SOVEREIGNT":"Malaysia","SOV_A3":"MYS","ADM0_DIF":0,"LEVEL":2,"TYPE":"Sovereign country","ADMIN":"Malaysia","ADM0_A3":"MYS","GEOU_DIF":0,"GEOUNIT":"Malaysia","GU_A3":"MYS","SU_DIF":0,"SUBUNIT":"Malaysia","SU_A3":"MYS","BRK_DIFF":0,"NAME":"Malaysia","NAME_LONG":"Malaysia","BRK_A3":"MYS","BRK_NAME":"Malaysia","BRK_GROUP":"","ABBREV":"Malay.","POSTAL":"MY","FORMAL_EN":"Malaysia","FORMAL_FR":"","NAME_CIAWF":"Malaysia","NOTE_ADM0":"","NOTE_BRK":"","NAME_SORT":"Malaysia","NAME_ALT":"","MAPCOLOR7":2,"MAPCOLOR8":4,"MAPCOLOR9":3,"MAPCOLOR13":6,"POP_EST":31381992,"POP_RANK":15,"GDP_MD_EST":863000,"POP_YEAR":2017,"LASTCENSUS":2010,"GDP_YEAR":2016,"ECONOMY":"6. Developing region","INCOME_GRP":"3. Upper middle income","WIKIPEDIA":-99,"FIPS_10_":"MY","ISO_A2":"MY","ISO_A3":"MYS","ISO_A3_EH":"MYS","ISO_N3":"458","UN_A3":"458","WB_A2":"MY","WB_A3":"MYS","WOE_ID":23424901,"WOE_ID_EH":23424901,"WOE_NOTE":"Exact WOE match as country","ADM0_A3_IS":"MYS","ADM0_A3_US":"MYS","ADM0_A3_UN":-99,"ADM0_A3_WB":-99,"CONTINENT":"Asia","REGION_UN":"Asia","SUBREGION":"South-Eastern Asia","REGION_WB":"East Asia & Pacific","NAME_LEN":8,"LONG_LEN":8,"ABBREV_LEN":6,"TINY":-99,"HOMEPART":1,"MIN_ZOOM":0,"MIN_LABEL":3,"MAX_LABEL":8,"NE_ID":1159321083,"WIKIDATAID":"Q833","NAME_AR":"ماليزيا","NAME_BN":"মালয়েশিয়া","NAME_DE":"Malaysia","NAME_EN":"Malaysia","NAME_ES":"Malasia","NAME_FR":"Malaisie","NAME_EL":"Μαλαισία","NAME_HI":"मलेशिया","NAME_HU":"Malajzia","NAME_ID":"Malaysia","NAME_IT":"Malesia","NAME_JA":"マレーシア","NAME_KO":"말레이시아","NAME_NL":"Maleisië","NAME_PL":"Malezja","NAME_PT":"Malásia","NAME_RU":"Малайзия","NAME_SV":"Malaysia","NAME_TR":"Malezya","NAME_VI":"Malaysia","NAME_ZH":"马来西亚"}},{"arcs":[[[146,147,148,149]],[[150,151,152,153]],[[154]],[[155]],[[156]],[[157]],[[158]],[[159]],[[160]],[[161]],[[162]],[[163]],[[164]],[[165]],[[166]],[[167]],[[168]],[[169]],[[170]],[[171]],[[172]],[[173]],[[174]],[[175]],[[176]],[[177]],[[178]],[[179]],[[180]],[[181]],[[182]],[[183]],[[184]],[[185]],[[186]],[[187]],[[188]],[[189]],[[190]],[[191]],[[192]],[[193]],[[194]],[[195]],[[196]],[[197]],[[198]],[[199]],[[200]],[[201]],[[202]],[[203]],[[204]],[[205]],[[206]],[[207]],[[208]],[[209]],[[210]],[[211]],[[212]],[[213]],[[214]],[[215]],[[216]],[[217]],[[218]],[[219]],[[220]],[[221]],[[222]],[[223]],[[224]],[[225]],[[226]],[[227]],[[228]],[[229]],[[230]],[[231]],[[232]],[[233]],[[234]],[[235]],[[236]],[[237]]],
Here is my JS:
<script>window.onload = setMap();
function setMap(){
d3.csv("/data/fdata.csv").then(function(data) {
//console.log(data);
d3.json("/data/a.topojson").then(function(data2) {
//console.log(data2);
var width = 960,
height = 460;
//create new svg container for the map
var map = d3.select("body")
.append("svg")
.attr("class", "map")
.attr("width", width)
.attr("height", height);
var projection = d3.geoNaturalEarth1()
.center([0, 0])
.rotate([-2, 0, 0])
//.parallels([43, 62])
.scale(175)
.translate([width / 2, height / 2]);
var path = d3.geoPath()
.projection(projection);
d3.selectAll(".boundary")
.style("stroke-width", 1 / 1);
var b = topojson.feature(data2, data2.objects.ne_10m_admin_0_countries);
var graticule = d3.geoGraticule();
var attrArray = ["x1","x2","x3" ];
function joinData(b, data){
for (var i=0; i<data.length; i++){
var csvRegion = data[i]; //the current region
var csvKey = data[i].Country; //the CSV primary key
for (var a=0; a<b.features.length; a++){
var geojsonProps = b.features[a].properties; //gj props
var geojsonKey = geojsonProps.ADMIN; //the geojson primary key
if (geojsonKey == csvKey){
attrArray.forEach(function(attr){
var val = parseFloat(csvRegion[attr]);
geojsonProps[attr] = val;
});
};
};
};
return b;
};
joinData(b,data);
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var currentF = "B2";
var color = d3.scaleQuantile()
.domain(d3.range(0, 1000))
.range(d3.schemeReds[7]);
map.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
map.append("path")
.datum(graticule.outline)
.attr("class", "graticule outline")
.attr("d", path);
map.selectAll("path")
.data(b.features)
.enter()
.append("path")
.attr("d", path)
//.style("stroke", "black")
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9)
.style("stroke-opacity", 1.0);
tooltip.html(d.properties.ADMIN)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0)
.style("stroke-opacity", 0);
})
.style("fill", function(d) { return color(d.properties[currentF]); });
}); //csv
}); //json
};
I believe the issue is with the map.selectAll("path") chunk. When I run it without D3 iterating through features it seems to come out fine. (With Indonesia and Malaysia still there. )
The issue is here:
map.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
map.append("path")
.datum(graticule.outline)
.attr("class", "graticule outline")
.attr("d", path);
map.selectAll("path")
.data(b.features)
.enter()
.append("path")
.attr("d", path)
The two append statements create paths, you then select these existing paths when you do: map.selectAll("path"). To confirm, before you append the features, you can do console.log(map.selectAll("path").size()) to see how many elements are selected, it should be two.
An enter selection can be used to create elements in the DOM for each item in the data array that does not have a corresponding element in the DOM.
As there are two paths in your selection, the first two items in the data array correspond to these two elements, and thus do not need to be entered: they already exist (By binding the data with .data() you are binding the first two datums in the data array to the already existing paths). D3 doesn't "know" that these paths aren't supposed to be affiliated with those data array items.
In order to ensure all items are entered you can make sure that you have an empty selection before you bind data:
map.selectAll(null).data()...
map.selectAll().data()...
map.selectAll(".className").data()... // where no element has that class yet

D3: zoom fails to include elements as expected

I am trying to adjust my D3 zoom so that ALL elements zoom in as expected. My elements are as follows: countries, markers (circles) and flows (polygons).
So far, all elements load as expected. The countries first, then the circles and flows upon subsequent interaction. But the zoom only works for the countries. The circles and flows do not zoom but just stay static. What am I doing wrong?
Link to my jsfiddle
Countries I add to map as follows:
var country = g.append("g");
d3.json("countries.json", function(collection) {
country.selectAll("path")
.data(collection.features)
.enter().append("path")
.attr("d", path);
});
Circles I add after user interaction, as follows:
var g_circles = svg.append("g").attr("class", "circles");
$.each(circles, function(i, d) {
dz = projection(d);
g_circles.append("circle")
.attr("class", "marker")
.attr("d", path)
.attr("cx", dz[0])
.attr("cy", dz[1])
.call(zoom);
});
Flows I add to the map as follows:
var g_lines = svg.append("g").attr("class", "lines");
g_lines.selectAll(".link_line")
.data(links)
.enter()
.append("path")
.attr("class", "link_line")
.style('fill-opacity', 0.3)
.attr("d", "path")
.call(zoom);
Zoom is as follows:
var zoom = d3.behavior.zoom()
.translate(projection.translate())
.scale(projection.scale())
.scaleExtent([h, 350000 * h])
.on("zoom", zoomed);
function zoomed() {
projection.translate(d3.event.translate).scale(d3.event.scale);
svg.selectAll("path, circle, .link_line").attr("d", path);
}
Have you tried to add all the expected groups (g_circles and g_lines) into a new single group (g) and use the dimensions of this group to do the focus?
Zoom should be applied to the SVG:
See this other question as it's very similar to yours.
Zooms are commonly expected to work as a translation of the svg like in this example.

Placing Lat/Long on a azimuthalEqualArea map with D3

I'm trying to plot some lat/long points onto a map, but I can't get them to appear in the correct place.
The dots should be in San Francisco. I have a JSfiddle of the code.
var width = 400,
height = 400;
var projection = d3.geo.azimuthalEqualArea()
.clipAngle(180 - 1e-3)
.scale(100)
.translate([width / 2, height / 2])
.precision(.1);
var path = d3.geo.path()
.projection(projection);
var graticule = d3.geo.graticule();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("defs").append("path")
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path);
svg.append("use")
.attr("class", "stroke")
.attr("xlink:href", "#sphere");
svg.append("use")
.attr("class", "fill")
.attr("xlink:href", "#sphere");
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
d3.json("http://bl.ocks.org/mbostock/raw/4090846/world-50m.json", function(error, world) {
svg.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", path);
svg.insert("path", ".graticule")
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
.attr("class", "boundary")
.attr("d", path);
});
var latlong = {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838312,-122.0423922]},"properties":{"timestampMs":1415894666875}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838474,-122.0423972]},"properties":{"timestampMs":1415894601718}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838474,-122.0423972]},"properties":{"timestampMs":1415894536288}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838411,-122.0424015]},"properties":{"timestampMs":1415894471356}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.383878,-122.0423925]},"properties":{"timestampMs":1415894406257}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838317,-122.0423856]},"properties":{"timestampMs":1415894326769}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838287,-122.0423933]},"properties":{"timestampMs":1415894261810}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.383829,-122.0423847]},"properties":{"timestampMs":1415894196224}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838765,-122.0424141]},"properties":{"timestampMs":1415894131768}},{"type":"Feature","geometry":{"type":"Point","coordinates":[37.3838177,-122.0423668]},"properties":{"timestampMs":1415894066809}}]};
// THESE ARE THE POINTS THAT ARE NOT BEING PLACED CORRECTLY
svg.selectAll("circle")
.data(latlong.features).enter()
.append("circle")
.attr("cx", function (d) { return projection(d.geometry.coordinates)[1]; })
.attr("cy", function (d) { return projection(d.geometry.coordinates)[0]; })
.attr("r", "2px")
.attr("fill", "red");
You've specified the latitude and longitude the wrong way round for d3.geo and you're also taking the output the wrong way round. It is counter to the way that they are displayed by convention (N/S then E/W) but it is more consistent with a drawing convention of across then up/down.
From path.projection in the D3 API Geo reference:
A projection function takes a two-element array of numbers
representing the coordinates of a location, [longitude, latitude], and
returns a similar two-element array of numbers representing the
projected pixel position [x, y].
To fix this, I've reversed the coordinates of your FeatureCollection:
var latlong = {"type":"FeatureCollection","features":[
{"type":"Feature","geometry":{"type":"Point","coordinates":[-122.0423922,37.3838312]},"properties":{"timestampMs":1415894666875}},
etc...
and reversed the coordinates of your plot.
.attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; })
.attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; })
Everything else was fine. Amended JSFiddle here. So often it's the little things!

D3js - Creating and easily updating a multi-line chart

I've created a little test line chart using D3, but since I am quite new to the library I am not sure what the best way would be to add multiple lines to a chart, at the moment I only have one line displayed in this fiddle.
I would like to display 2 lines on the chart, but I am unsure of how to achieve that without copy pasting code, which I am sure would be very inefficient as I would like to update/animate the graph at regular intervals based on user selection.
Instead of this,
var data = [12345,22345,32345,42345,52345,62345,72345,82345,92345,102345,112345,122345,132345,142345];
I would like to display something like this,
var data = [
[12345,42345,3234,22345,72345,62345,32345,92345,52345,22345], // line one
[1234,4234,3234,2234,7234,6234,3234,9234,5234,2234] // line two
];
Would this be a possibility? If so, what would be the best way to approach this, so that I can easily update/animate the graph when needed?
Note: I am merely trying to learn and to familiarize myself with D3 best practices and the library as a whole. Thanks.
This is possible and reasonable.
There is a tutorial that approaches this at the
D3 Nested Selection Tutorial
which describes nesting of data.
Below is code that I hacked from your fiddle to demonstrate this.
var data = [
[12345,42345,3234,22345,72345,62345,32345,92345,52345,22345],
[1234,4234,3234,2234,7234,6234,3234,9234,5234,2234]
];
var width = 625,
height = 350;
var x = d3.scale.linear()
.domain([0,data[0].length]) // Hack. Computing x-domain from 1st array
.range([0, width]);
var y = d3.scale.linear()
.domain([0,d3.max(data[0])]) // Hack. Computing y-domain from 1st array
.range([height, 0]);
var line = d3.svg.line()
.x(function(d,i) { return x(i); })
.y(function(d) { return y(d); });
var area = d3.svg.area()
.x(line.x())
.y1(line.y())
.y0(y(0));
var svg = d3.select("body").append("svg")
//.datum(data)
.attr("width", width)
.attr("height", height)
//.append("g");
var lines = svg.selectAll( "g" )
.data( data ); // The data here is two arrays
// for each array, create a 'g' line container
var aLineContainer = lines
.enter().append("g");
/*svg.append("path")
.attr("class", "area")
.attr("d", area);*/
aLineContainer.append("path")
.attr("class", "area")
.attr("d", area);
/*svg.append("path")
.attr("class", "line")
.attr("d", line);*/
aLineContainer.append("path")
.attr("class", "line")
.attr("d", line);
/*svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", line.x())
.attr("cy", line.y())
.attr("r", 3.5);*/
// Access the nested data, which are values within the array here
aLineContainer.selectAll(".dot")
.data( function( d, i ) { return d; } ) // This is the nested data call
.enter()
.append("circle")
.attr("class", "dot")
.attr("cx", line.x())
.attr("cy", line.y())
.attr("r", 3.5);
​
One deficiency is that I computed the domain for the x and y axes off the first array, which is a hack, but not pertinent to your question exactly.

Categories