I want to exchange the current node label with a curved label, placed above the node. I miss knowledge regarding, how to use paths proper and how to append a text to a path. Maybe you guys could enlight me.
The text should have the same curve as the node itself.
UPDATE
I implemented the solution but it seems either the path or textPath is to short. Its possible to adjust the innerRadius, outerRadius as well as the startAngle and endAngle. I guess the startAngle and endAngle define the length of the arc. No matter which value I test, the full label isn´t shown.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Curved Text</title>
<!-- Script Import -->
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<style>
body {
background: white;
overflow: hidden;
margin: 0px;
}
circle {
fill: whitesmoke;
stroke-width: 2;
stroke: black;
transform: scale(1);
transition: all 200ms ease-in-out;
}
circle:hover {
transform: scale(1.5)
}
</style>
<body>
<svg id="svg"></svg>
<script>
var width = window.innerWidth,
height = window.innerHeight,
radius = 40, // circle radius
offset = 35; // arrow offset
const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.append("g")
var graph = {
"nodes": [
{ "id": "Stackoverflow" },
{ "id": "Reddit" },
{ "id": "Google" }
],
"links": [
{ "source": "Stackoverflow", "target": "Reddit"},
{ "source": "Reddit", "target": "Google"},
{ "source": "Google", "target": "Stackoverflow"},
]
}
const arc = d3.arc()
.innerRadius(radius + 5)
.outerRadius(radius + 5)
.startAngle(-Math.PI / 15)
.endAngle(Math.PI / 2 )
svg.append("defs")
.append("path")
.attr("id", "curvedLabelPath")
.attr("d", arc())
svg.append('defs').append('marker')
.attr('id', 'arrowhead')
.attr('viewBox', '-0 -5 10 10')
.attr('refX', 0)
.attr('refY', 0)
.attr('orient', 'auto')
.attr('markerWidth', 10)
.attr('markerHeight', 10)
.attr('xoverflow', 'visible')
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#999')
.style('stroke', 'none');
var linksContainer = svg.append("g").attr("class", "linksContainer")
var nodesContainer = svg.append("g").attr("class", "nodesContainer")
const simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id }).distance(250))
.force("charge", d3.forceManyBody().strength(-1000))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(radius))
link = linksContainer.selectAll("g")
.data(graph.links)
.join("g")
.attr("curcor", "pointer")
link = linksContainer.selectAll("path")
.data(graph.links)
.join("path")
.attr("id", function (_, i) {
return "path" + i
})
.attr("stroke", "#000000")
.attr("opacity", 0.75)
.attr("stroke-width", 3)
.attr("fill", "transparent")
.attr("marker-end", "url(#arrowhead)")
node = nodesContainer.selectAll(".node")
.data(graph.nodes, d => d.id)
.join("g")
.attr("cursor", "pointer")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseenter", function (d) {
d3.select(this).select("text").attr("font-size", 15)
})
node.selectAll("circle")
.data(d => [d])
.join("circle")
.attr("r", radius)
node.append("text")
.append("textPath")
.attr("href", "#curvedLabelPath")
.attr("text-anchor", "middle")
.attr("startoffset", "5%")
.text(function (d) {
return d.id
})
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation
.force("link")
.links(graph.links);
function ticked() {
link.attr("d", function (d) {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
// Neuberechnung der Distanz
link.attr("d", function (d) {
// Länge des aktuellen Paths
var pl = this.getTotalLength(),
// Kreis Radius und Distanzwert
r = radius + offset,
// Umlaufposition wo der Path den Kreis berührt
m = this.getPointAtLength(pl - r);
var dx = m.x - d.source.x,
dy = m.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
});
node
.attr("transform", d => `translate(${d.x}, ${d.y})`);
}
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
dataFlow()
function dataFlow() {
var lines = linksContainer.selectAll("path")
dataflow = window.setInterval(function () {
lines.style("stroke-dashoffset", offset)
.style("stroke", "black")
.style("stroke-dasharray", 5)
.style("opacity", 0.5)
offset -= 1
}, 40)
var offset = 1;
}
</script>
</body>
</html>
Here's an example for one circle and label that uses a <textPath>.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
// set up
const width = 200;
const height = 200;
const svg = d3.select('#chart')
.append('svg')
.attr('width', width)
.attr('height', height);
// radius of the circle that the label is above
const radius = 50;
// arc generator for the curved path
const arc = d3.arc()
// add a bit of space so that the label
// won't be right on the circle
.innerRadius(radius + 5)
.outerRadius(radius + 5)
.startAngle(-Math.PI / 2)
.endAngle(Math.PI / 2);
// add the path that the label will follow to <defs>
svg.append('defs')
.append('path')
.attr('id', 'curvedLabelPath')
.attr('d', arc());
// create a group for the circle and label
const g = svg.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);
// draw the circle
g.append('circle')
.attr('stroke', 'black')
.attr('fill', '#d3d3d3')
.attr('r', radius);
// draw the label
g.append('text')
.append('textPath')
.attr('href', '#curvedLabelPath')
// these two lines center along the arc.
// the offset is 25% instead of 50% because d3.arc() creates
// an arc that has an outer and inner part. in this case,
// each parth is ~50% of the path, so the middle of the
// outer arc is 25%
.attr('text-anchor', 'middle')
.attr('startOffset', '25%')
.text('stackoverflow');
</script>
</body>
</html>
Here are the changes to your updated code to make the labels not get cutoff, as explained in my comment below:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Curved Text</title>
<!-- Script Import -->
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<style>
body {
background: white;
overflow: hidden;
margin: 0px;
}
circle {
fill: whitesmoke;
stroke-width: 2;
stroke: black;
transform: scale(1);
transition: all 200ms ease-in-out;
}
circle:hover {
transform: scale(1.5)
}
</style>
<body>
<svg id="svg"></svg>
<script>
var width = window.innerWidth,
height = window.innerHeight,
radius = 40, // circle radius
offset = 35; // arrow offset
const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.append("g")
var graph = {
"nodes": [
{ "id": "Stackoverflow" },
{ "id": "Reddit" },
{ "id": "Google" }
],
"links": [
{ "source": "Stackoverflow", "target": "Reddit"},
{ "source": "Reddit", "target": "Google"},
{ "source": "Google", "target": "Stackoverflow"},
]
}
const arc = d3.arc()
.innerRadius(radius + 5)
.outerRadius(radius + 5)
.startAngle(-Math.PI / 2)
.endAngle(Math.PI / 2 )
svg.append("defs")
.append("path")
.attr("id", "curvedLabelPath")
.attr("d", arc())
svg.append('defs').append('marker')
.attr('id', 'arrowhead')
.attr('viewBox', '-0 -5 10 10')
.attr('refX', 0)
.attr('refY', 0)
.attr('orient', 'auto')
.attr('markerWidth', 10)
.attr('markerHeight', 10)
.attr('xoverflow', 'visible')
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#999')
.style('stroke', 'none');
var linksContainer = svg.append("g").attr("class", "linksContainer")
var nodesContainer = svg.append("g").attr("class", "nodesContainer")
const simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id }).distance(250))
.force("charge", d3.forceManyBody().strength(-1000))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(radius))
link = linksContainer.selectAll("g")
.data(graph.links)
.join("g")
.attr("curcor", "pointer")
link = linksContainer.selectAll("path")
.data(graph.links)
.join("path")
.attr("id", function (_, i) {
return "path" + i
})
.attr("stroke", "#000000")
.attr("opacity", 0.75)
.attr("stroke-width", 3)
.attr("fill", "transparent")
.attr("marker-end", "url(#arrowhead)")
node = nodesContainer.selectAll(".node")
.data(graph.nodes, d => d.id)
.join("g")
.attr("cursor", "pointer")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseenter", function (d) {
d3.select(this).select("text").attr("font-size", 15)
})
node.selectAll("circle")
.data(d => [d])
.join("circle")
.attr("r", radius)
node.append("text")
.append("textPath")
.attr("href", "#curvedLabelPath")
.attr("text-anchor", "middle")
.attr("startOffset", "25%")
.text(function (d) {
return d.id
})
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation
.force("link")
.links(graph.links);
function ticked() {
link.attr("d", function (d) {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
// Neuberechnung der Distanz
link.attr("d", function (d) {
// Länge des aktuellen Paths
var pl = this.getTotalLength(),
// Kreis Radius und Distanzwert
r = radius + offset,
// Umlaufposition wo der Path den Kreis berührt
m = this.getPointAtLength(pl - r);
var dx = m.x - d.source.x,
dy = m.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
});
node
.attr("transform", d => `translate(${d.x}, ${d.y})`);
}
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
dataFlow()
function dataFlow() {
var lines = linksContainer.selectAll("path")
dataflow = window.setInterval(function () {
lines.style("stroke-dashoffset", offset)
.style("stroke", "black")
.style("stroke-dasharray", 5)
.style("opacity", 0.5)
offset -= 1
}, 40)
var offset = 1;
}
</script>
</body>
</html>
I am fairly new to using d3, but what I am trying to do is make a chord diagram of some site traffic, and I am trying to make it interactive by changing the color of the paths when a user clicks on the group for a certain site.here is the style and script section of my code:
<style type="text/css">
.group text {
font: 11px sans-serif;
pointer-events: none;
}
#circle circle {
fill: none;
pointer-events: all;
}
.group path {
stroke: #000;
fill-opacity: .5;
}
path.chord {
stroke-width: .75;
fill-opacity: .75;
}
#circle:hover path.fade {
display: none;
}
</style>
</head>
<body>
<script type="text/javascript">
// Chart dimensions.
var w = 600,
h = 700,
r1 = Math.min(w, h) / 2 - 4,
r0 = r1 - 20,
format = d3.format(",.3r");
// Square matrices, asynchronously loaded; credits is the transpose of sitename.
var sitename = [];
// The chord layout, for computing the angles of chords and groups.
var layout = d3.layout.chord()
.sortGroups(d3.descending)
.sortSubgroups(d3.descending)
.sortChords(d3.descending)
.padding(.04);
// The color scale, for different categories of "worrisome" risk.
var fill = d3.scale.ordinal();
// The arc generator, for the groups.
var arc = d3.svg.arc()
.innerRadius(r0)
.outerRadius(r1);
// The chord generator (quadratic Bézier), for the chords.
var chord = d3.svg.chord()
.radius(r0);
// Add an SVG element for each diagram, and translate the origin to the center.
var svg = d3.select("body").selectAll("div")
.data([sitename])
.enter().append("div")
.style("display", "inline-block")
.style("width", w + "px")
.style("height", h + "px")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
// Load our data file…
d3.csv("data2.csv", function(data) {
var uniqueids = {},
array = [],
n = 0;
// Compute a unique id for each site.
data.forEach(function(d) {
d.siteid1 = uniqueIDMaker(d.siteid1);
d.siteid2 = uniqueIDMaker(d.siteid2);
d.valueOf = value; // convert object to number implicitly
});
// Initialize a square matrix of sitename and users
for (var i = 0; i < n; i++) {
sitename[i] = [];
for (var j = 0; j < n; j++) {
sitename[i][j] = 0;
}
}
// Populate the matrices, and stash a map from id to site.
data.forEach(function(d) {
sitename[d.siteid1.id][d.siteid2.id] = d;
array[d.siteid1.id] = d.siteid1;
array[d.siteid2.id] = d.siteid2;
});
// For each diagram…
svg.each(function(matrix, j) {
var svg = d3.select(this);
// Compute the chord layout.
layout.matrix(matrix);
// Add chords.
svg.selectAll(".chord")
.data(layout.chords)
.enter().append("svg:path")
.attr("class", "chord")
.style("fill", function(d) { return fill(d.source.value); })
.style("stroke", function(d) { return d3.rgb(fill(d.source.value)).darker(); })
.attr("d", chord)
.on("dblclick",function(){
d3.select(this)
.style("fill","red")
.style("stroke","yellow")
})
.append("svg:title")
.text(function(d) { return "site " + d.source.value.siteid2.name + " and site " + d.source.value.siteid1.name + " have " + format(d.source.value) + " common users"; })
;
// Add groups.
var g = svg.selectAll("g.group")
.data(layout.groups)
.enter().append("svg:g")
.attr("class", "group");
// Add the group arc.
g.append("svg:path")
.style("fill", function(d) { return fill(array[d.index]); })
.attr("id", function(d, i) { return "group" + d.index + "-" + j; })
.attr("d", arc)
.append("svg:title")
.text(function(d) { return "site " + array[d.index].name + " has " + format(d.value) + "users"; });
g.append("svg:text")
.attr("x", 6)
.attr("dy", 15)
.filter(function(d) { return d.value > 110; })
.append("svg:textPath")
.attr("xlink:href", function(d) { return "#group" + d.index + "-" + j; })
.text(function(d) { return array[d.index].name; });
});
function uniqueIDMaker(d) {
return uniqueids[d] || (uniqueids[d] = {
name: d,
id: n++
});
}
function value() {
return +this.count;
}});
</script>
any help would be greatly appreciated
http://jsfiddle.net/Rw3aK/2/ is a jsFiddle of the script, not sure how to make it read from a file, so here is the contents of data2.csv:
siteid1,siteid2,count,pubid1,pubid2
8,94,11132,57141,57141
201,94,10035,57141,57141
201,8,9873,57141,57141
0,94,8488,45020,57141
0,8,8258,45020,57141
0,201,7644,45020,57141
0,1,6973,45020,45020
94,1,5719,57141,45020
8,1,5670,57141,45020
1,201,5410,57141,45020
I forked your jsfiddle and converted your CSV data to JSON, now in a variable data: http://jsfiddle.net/mdml/K6FHW/.
I also modified your code slightly so that when you click on a group, all outgoing chords are highlighted red. When you click on a group again, the chords change back to their original color. Here're the relevant snippets:
When adding the chords, label each chord with a class according to the chord's source
svg.selectAll(".chord")
.data(layout.chords)
.enter().append("svg:path")
.attr("class", function(d){ return "chord chord-" + d.source.index; })
...
When clicking a group, check if that group's chords are highlighted.
If so, fill the chords with their default color
If not, fill the chords red
Then record whether or not the group's chords are highlighted in a variable d.chordHighlighted
g.append("svg:path")
...
.attr("id", function (d, i) {
return "group" + d.index + "-" + j;
})
...
.on("click", function(d){
if (d.chordHighlighted)
d3.selectAll(".chord-" + d.index)
.style("fill", fill(d.value));
else{
d3.selectAll(".chord-" + d.index)
.style("fill", "red");
}
d.chordHighlighted = d.chordHighlighted ? false : true;
})
I have setup a basic IIS server and am trying to demonstrate a d3js example. First I create an html page with the example code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.State; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
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("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(color.domain().slice().reverse())
.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", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
</script>
and then i create the data.csv file:
State,Under 5 Years,5 to 13 Years,14 to 17 Years,18 to 24 Years,25 to 44 Years,45 to 64 Years,65 Years and Over
AL,310504,552339,259034,450818,1231572,1215966,641667
AK,52083,85640,42153,74257,198724,183159,50277
AZ,515910,828669,362642,601943,1804762,1523681,862573
AR,202070,343207,157204,264160,754420,727124,407205
CA,2704659,4499890,2159981,3853788,10604510,8819342,4114496
CO,358280,587154,261701,466194,1464939,1290094,511094
CT,211637,403658,196918,325110,916955,968967,478007
DE,59319,99496,47414,84464,230183,230528,121688
DC,36352,50439,25225,75569,193557,140043,70648
FL,1140516,1938695,925060,1607297,4782119,4746856,3187797
GA,740521,1250460,557860,919876,2846985,2389018,981024
HI,87207,134025,64011,124834,356237,331817,190067
ID,121746,201192,89702,147606,406247,375173,182150
IL,894368,1558919,725973,1311479,3596343,3239173,1575308
IN,443089,780199,361393,605863,1724528,1647881,813839
IA,201321,345409,165883,306398,750505,788485,444554
KS,202529,342134,155822,293114,728166,713663,366706
KY,284601,493536,229927,381394,1179637,1134283,565867
LA,310716,542341,254916,471275,1162463,1128771,540314
ME,71459,133656,69752,112682,331809,397911,199187
MD,371787,651923,316873,543470,1556225,1513754,679565
MA,383568,701752,341713,665879,1782449,1751508,871098
MI,625526,1179503,585169,974480,2628322,2706100,1304322
MN,358471,606802,289371,507289,1416063,1391878,650519
MS,220813,371502,174405,305964,764203,730133,371598
MO,399450,690476,331543,560463,1569626,1554812,805235
MT,61114,106088,53156,95232,236297,278241,137312
NE,132092,215265,99638,186657,457177,451756,240847
NV,199175,325650,142976,212379,769913,653357,296717
NH,75297,144235,73826,119114,345109,388250,169978
NJ,557421,1011656,478505,769321,2379649,2335168,1150941
NM,148323,241326,112801,203097,517154,501604,260051
NY,1208495,2141490,1058031,1999120,5355235,5120254,2607672
NC,652823,1097890,492964,883397,2575603,2380685,1139052
ND,41896,67358,33794,82629,154913,166615,94276
OH,743750,1340492,646135,1081734,3019147,3083815,1570837
OK,266547,438926,200562,369916,957085,918688,490637
OR,243483,424167,199925,338162,1044056,1036269,503998
PA,737462,1345341,679201,1203944,3157759,3414001,1910571
RI,60934,111408,56198,114502,277779,282321,147646
SC,303024,517803,245400,438147,1193112,1186019,596295
SD,58566,94438,45305,82869,196738,210178,116100
TN,416334,725948,336312,550612,1719433,1646623,819626
TX,2027307,3277946,1420518,2454721,7017731,5656528,2472223
UT,268916,413034,167685,329585,772024,538978,246202
VT,32635,62538,33757,61679,155419,188593,86649
VA,522672,887525,413004,768475,2203286,2033550,940577
WA,433119,750274,357782,610378,1850983,1762811,783877
WV,105435,189649,91074,157989,470749,514505,285067
WI,362277,640286,311849,553914,1487457,1522038,750146
WY,38253,60890,29314,53980,137338,147279,65614
When I access the page, nothing displays...A quick look through fiddler shows the html content downloads fine (you can also see it in show source). You can also look at the data.csv file directly by accessing it from the url
http://localhost/data.csv
The problem shown in fiddler is a 406 error when d3js attempts to load the CSV file. Any ideas?
Thanks
What does your HTTP Request's Accept header contain? Apache is probably configured in such a way so as to return a 406 because the value in the Accept header does not include whatever MIME type your CSV is returning.
See
http://blogs.msdn.com/b/ieinternals/archive/2011/03/27/http-406-not-acceptable-php-ie9-standards-mode-accepts-only-text_2f00_css-for-stylesheets.aspx for a similar problem sometimes seen in browsers.
Change the build action for the csv file to "Resource" in the file's properties using your Visual Studio.