Related
Ive been at this for hours and cant seem to get my grouped bar chart to behave. Specifically trying to obtain a proper width for the 'g' translate property around each bar.
I have tried multiple methods and this seems to be the most elegant although im open to other solutions. The goal is something like this: http://www.cagrimmett.com/til/2016/04/26/responsive-d3-bar-chart.html
var data = [{"category":"Securily Provisions","values":[{"value":50,"rate":"Work Performed"},{"value":40,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Investigate","values":[{"value":25,"rate":"Work Performed"},{"value":21,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Operate and Maintain","values":[{"value":3,"rate":"Work Performed"},{"value":22,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Oversee and Govern","values":[{"value":12,"rate":"Work Performed"},{"value":7,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Protect and Defend","values":[{"value":6,"rate":"Work Performed"},{"value":15,"rate":"Knowledge, Skills, and Abilities"}]},{"category":"Collect and Operate","values":[{"value":92,"rate":"Work Performed"},{"value":85,"rate":"Knowledge, Skills, and Abilities"}]}]
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 ;
var x0 = d3.scale.ordinal().rangeRoundBands([0, width], .5);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#02bfe7","#fdb81e"]);
var svg = d3.select('#chart-area').append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("preserveAspectRatio", "xMinYMin meet")
.append("g").attr("class","container")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//d3.json("data.json", function(error, data) {
var categoriesNames = data.map(function(d) {
return d.category;
});
var rateNames = data[0].values.map(function(d) {
return d.rate;
});
x0.domain(categoriesNames);
x1.domain(rateNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(categorie) {
return d3.max(categorie.values, function(d) {
return d.value;
});
})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style('opacity','0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.text("Value");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform",function(d) { return "translate(" + x0(d.category) + ",0)"; });
slice.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.rate); })
.style("fill", function(d) { return color(d.rate) })
.attr("y", function(d) { return y(0); })
.attr("height", function(d) { return height - y(0); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.rate));
});
slice.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
.attr("class","bar")
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
//Legend
var legend = svg.selectAll(".legend")
.data(data[0].values.map(function(d) { return d.rate; }).reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d,i) { return "translate(0," + i * 20 + ")"; })
.style("opacity","0");
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(d); });
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {return d; });
legend.transition().duration(500).delay(function(d,i){ return 1300 + 100 * i; }).style("opacity","1");
document.addEventListener("DOMContentLoaded", resize);
d3.select(window).on('resize', resize);
function resize() {
console.log('----resize function----');
// update width
width = parseInt(d3.select('#chart-area').style('width'), 10);
width = width - margin.left - margin.right;
height = parseInt(d3.select("#chart-area").style("height"));
height = height - margin.top - margin.bottom;
console.log('----resiz width----'+width);
console.log('----resiz height----'+height);
// resize the chart
x0.range([0, width]);
x0.rangeRoundBands([0, width], .03);
y.range([height, 0]);
yAxis.ticks(Math.max(height/50, 2));
xAxis.ticks(Math.max(width/50, 2));
d3.select(svg.node().parentNode)
.style('width', (width + margin.left + margin.right) + 'px');
svg.selectAll('.g')
//.attr("x", function(d) { return x0(categoriesNames); })
//.attr("x", function(d) { return x1(d.rate); })
// Problem here applying new width within translate
.attr("transform", "translate(10,0)")
.attr("width", x1.rangeBand());
svg.selectAll("text")
// .attr("x", function(d) { return x0(categoriesNames); })
.attr("x", (function(d) { return x0(categoriesNames ) + x0.rangeBand() / 2 ; } ))
.attr("y", function(d) { return y(rateNames) + 1; })
.attr("dy", ".75em");
svg.select('.x.axis').call(xAxis.orient('bottom')).selectAll("text").attr("x",55);
}
//});
.bar{
fill: steelblue;
}
.bar:hover{
fill: brown;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
#chart-area {width: 100%;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart-area"></div>
Here's a solution. Is this the desired output? Try resizing the window.
JS FIDDLE
Resize function:
function resize() {
console.log('----resize function----');
// update width
width = parseInt(d3.select('#chart-area').style('width'), 10);
width = width - margin.left - margin.right;
height = parseInt(d3.select("#chart-area").style("height"));
height = height - margin.top - margin.bottom;
console.log('----resiz width----'+width);
console.log('----resiz height----'+height);
// resize the chart
x0.rangeRoundBands([0, width], .5);
x1.domain(rateNames).rangeRoundBands([0, x0.rangeBand()]);
y.range([height, 0]);
yAxis.ticks(Math.max(height/50, 2));
xAxis.ticks(Math.max(width/50, 2));
d3.select(svg.node().parentNode)
.style('width', (width + margin.left + margin.right) + 'px');
svg.selectAll('.g')
.attr("transform",function(d) {
return "translate(" + x0(d.category) + ",0)";
});
svg.selectAll('.g').selectAll("rect").attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.rate); })
svg.selectAll(".legend rect")
.attr("x", width - 18);
svg.selectAll('.legend text')
.attr("x", width - 24)
svg.select('.x.axis').call(xAxis.orient('bottom'));
}
I made a few changes to the resize function. Here's why:
x0 and x1 ranges (both) have to be reset on resize:
x0.rangeRoundBands([0,width],.5);
x1.domain(rateNames).rangeRoundBands([0,x0.rangeBand()]);
y.range([height, 0]);
Translate of (10,0) was being force set in the resize function and you cannot apply width to a (group).
Basically, you just need to call all the code from the original render that includes width and height changes. Take a look at the resize function.
Re-rendering X-axis at the bottom included a static value for the x ticks:
svg.select('.x.axis').call(xAxis.orient('bottom')).selectAll("text").attr("x",55);
Just removed the attr("x", 55)
Hope this helps. :)
This is a d3 bar chart. line 162 ,
.on("mouseover", console.log("I am on it"))
should only happen when user is over a bar on the bar chart, but the log is output from the time the page loads.
The running code is here, https://shanegibney.github.io/d3Mouseover/
The full code is here, https://github.com/shanegibney/d3Mouseover
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
body {
font-family: avenir next, sans-serif;
font-size: 12px;
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.axis {
stroke-width: 0.5px;
stroke: #888;
font: 10px avenir next, sans-serif;
}
.axis>path {
stroke: #888;
}
</style>
<body>
<div id="totalDistance">
</div>
</body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
/* Adapted from: https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172 */
var margin = {
top: 20,
right: 20,
bottom: 90,
left: 50
},
margin2 = {
top: 230,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom,
height2 = 300 - margin2.top - margin2.bottom;
var parseTime = d3.timeParse("%Y-%m-%d %H:%M");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]),
dur = d3.scaleLinear().range([0, 12]);
var xAxis = d3.axisBottom(x).tickSize(0),
xAxis2 = d3.axisBottom(x2).tickSize(0),
yAxis = d3.axisLeft(y).tickSize(0);
var brush = d3.brushX()
.extent([
[0, 0],
[width, height2]
])
.on("start brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([
[0, 0],
[width, height]
])
.extent([
[0, 0],
[width, height]
])
.on("zoom", zoomed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.json("dataDefault.json", function(error, data) {
if (error) throw error;
var parseTime = d3.timeParse("%Y-%m-%d %H:%M");
var mouseoverTime = d3.timeFormat("%a %e %b %Y %H:%M");
var minTime = d3.timeFormat("%b%e, %Y");
var parseDate = d3.timeParse("%b %Y");
data.forEach(function(d) {
d.mouseoverDisplay = parseTime(d.date);
d.date = parseTime(d.date);
d.end = parseTime(d.end);
d.duration = ((d.end - d.date) / (60 * 1000)); // session duration in minutes
d.distance = +d.distance;
d.intensityInverted = (1 / (d.distance / d.duration)); // inverse of intensity so that the light colour is for low intensity and dark colour is for high intensity
d.intensity = Math.round(d.distance / d.duration); // actually intensity, metres per minute.
d.course = d.course.toLowerCase();
return d;
},
function(error, data) {
if (error) throw error;
});
var total = 0;
data.forEach(function(d) {
total = d.distance + total;
});
var minDate = d3.min(data, function(d) {
return d.date;
});
total = String(total).replace(/(.)(?=(\d{3})+$)/g, '$1,') //place thousands comma in total distance string
var xMin = d3.min(data, function(d) {
return d.date;
});
var yMax = Math.max(20, d3.max(data, function(d) {
return d.distance;
}));
dur.domain([0, d3.max(data, function(d) {
return d.duration;
})]);
var colorScale = d3.scaleSequential(d3.interpolateInferno)
.domain([0, d3.max(data, function(d) {
return d.intensityInverted;
})]);
var totalDistance = d3.select("#totalDistance").append("p").text("Total distance: " + total + "m");
x.domain([xMin, new Date()]);
y.domain([0, yMax]);
x2.domain(x.domain());
y2.domain(y.domain());
// append scatter plot to main chart area
var messages = focus.append("g");
messages.attr("clip-path", "url(#clip)");
messages.selectAll("message")
.data(data)
.enter().append("rect")
.style("fill", function(d) {
return colorScale(d.intensityInverted);
})
.attr("class", "message")
.attr("x", function(d) {
return x(d.date);
})
.attr("y", function(d) {
return y(d.distance);
})
.attr("width", function(d) {
return dur(d.duration);
})
.attr("height", function(d) {
return height - y(d.distance);
})
// .on("mouseover", onit);
.on("mouseover", () => console.log("I am now on it for sure!"));
// function onit(d) {
// console.log("I am on it now!")
// }
focus.append("g")
.attr("class", "axis x-axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
// Summary Stats
focus.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Distance in meters");
// focus.append("text")
// .attr("x", width - margin.right)
// .attr("dy", "1em")
// .attr("text-anchor", "end")
// // .text("Messages: " + num_messages(data, x));
// .text("Total distance: " + total + "m");
svg.append("text")
.attr("transform",
"translate(" + ((width + margin.right + margin.left) / 2) + " ," +
(height + margin.top + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Date");
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
// append scatter plot to brush chart area
var messages = context.append("g");
messages.attr("clip-path", "url(#clip)");
messages.selectAll("message")
.data(data)
.enter().append("rect")
.style("fill", function(d) {
return colorScale(d.intensityInverted);
})
.attr("class", "message")
.attr("x", function(d) {
return x2(d.date);
})
.attr("y", function(d) {
return y2(d.distance);
})
.attr("width", function(d) {
return dur(d.duration);
})
.attr("height", function(d) {
return height2 - y2(d.distance);
});
context.append("g")
.attr("class", "axis x-axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
});
//create brush function redraw scatterplot with selection
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.selectAll(".message")
.attr("x", function(d) {
return x(d.date);
})
.attr("y", function(d) {
return y(d.distance);
})
.attr("width", function(d) {
return dur(d.duration);
})
.attr("height", function(d) {
return height - y(d.distance);
});
focus.select(".x-axis").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
var e = d3.event.selection;
var selectedMessages = focus.selectAll('.message').filter(function() {
var xValue = this.getAttribute('x');
return e[0] <= xValue && xValue <= e[1];
});
// console.log(selectedMessages.nodes().length);
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.selectAll(".message")
// .enter().append("rect")
// .style("fill", function(d) {
// return colorScale(d.intensityInverted);
// })
// .attr("class", "message")
.attr("x", function(d) {
return x(d.date);
})
.attr("y", function(d) {
return y(d.distance);
})
.attr("width", function(d) {
return dur(d.duration);
})
.attr("height", function(d) {
return height - y(d.distance);
});
focus.select(".x-axis").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function handleMouseOver(d) {
d3.select(this)
.style("fill", "lightBlue");
g.select('text')
.attr("x", 15)
.attr("y", 5)
.text("Session no. " + d.number)
.append('tspan')
.text("Date: " + mouseoverTime(d.mouseoverDisplay))
.attr("x", 15)
.attr("y", 30)
.append('tspan')
.text("Distance: " + d.distance + "m")
.attr("x", 15)
.attr("y", 50)
.append('tspan')
.text("Duration: " + d.duration + " mins")
.attr("x", 15)
.attr("y", 70)
.append('tspan')
.text("Intensity: " + d.intensity + " meters/mins")
.attr("x", 15)
.attr("y", 90)
.append('tspan')
.text("Pool: " + d.pool + " (" + d.course + ")")
.attr("x", 15)
.attr("y", 110);
console.log("handleMouseOver function");
}
function handleMouseOut(d) {
d3.select(this)
.style("fill", function(d) {
return colorScale(d.intensityInverted);
});
g.select('text').text("Total distance since " + minTime(minDate) + ": " + total + "m");
}
</script>
Sample data,
[{
"number": "1",
"date": "2016-11-09 11:15",
"end": "2016-11-09 11:45",
"distance": "1100",
"course": "LC",
"pool": "UCD"
},
{
"number": "2",
"date": "2016-11-10 10:40",
"end": "2016-11-10 11:20",
"distance": "1500",
"course": "LC",
"pool": "UCD"
},
{
"number": "3",
"date": "2016-11-11 16:45",
"end": "2016-11-11 17:50",
"distance": "2000",
"course": "LC",
"pool": "UCD"
},
{
"number": "4",
"date": "2016-11-12 12:48",
"end": "2016-11-12 13:53",
"distance": "2500",
"course": "LC",
"pool": "UCD"
}
]
I added the last two lines here, but still no luck,
var messages = focus.append("g");
messages.attr("clip-path", "url(#clip)");
messages.selectAll("message")
.data(data)
.enter().append("rect")
.style("fill", function(d) {
return colorScale(d.intensityInverted);
})
.attr("class", "message")
.attr("x", function(d) {
return x(d.date);
})
.attr("y", function(d) {
return y(d.distance);
})
.attr("width", function(d) {
return dur(d.duration);
})
.attr("height", function(d) {
return height - y(d.distance);
})
// .on("mouseover", onit);
.on("mouseover", () => console.log("I am now on it for sure!"));
// function onit(d) {
// console.log("I am on it now!")
// }
I suspect the problem is because I am using brushX() and zoom.
When you do this:
.on("mouseover", console.log("I am on it"))
You're passing the result of the console.log function to the callback. Instead of that, you want to pass its reference:
.on("mouseover", function(){
console.log("I am on it")
})
Check this snippet (don't hover over the circle!):
var circle = d3.select("circle");
circle.on("mouseover", console.log("I'm on it!"));
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
<circle cx="50" cy="50" r="15" fill="teal"></circle>
</svg>
Now the same code, with the reference to console.log:
var circle = d3.select("circle");
circle.on("mouseover", () => console.log("I'm on it!"));
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
<circle cx="50" cy="50" r="15" fill="teal"></circle>
</svg>
The issue is that you are calling the function at the time you are declaring it:
.on("mouseover", console.log("I am on it")) //function call
should be something like this:
.on("mouseover", console.log) //function ref
.on("mouseover", function(d) { console.log("I am on it") }) //function ref
I have been trying to implement a Line-Bar Combo Chart but I'm not much successfull.
Here's my code
function renderNormalizedStackBarChart(inputData,dom_element_to_append_to, path_to_data) {
var margin = {top: 20, right: 231, bottom: 140, left: 40},
width = $(dom_element_to_append_to).width() - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xscale = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var yScaleLeft = d3.scale.linear()
.rangeRound([height, 0]);
var yScaleRight = d3.scale.linear()
.rangeRound([height, 0]);
var colors = d3.scale.ordinal()
.range(["#63c172", "#ee9952", "#46d6c4", "#fee851", "#98bc9a"]);
var xaxis = d3.svg.axis()
.scale(xscale)
.orient("bottom");
var yAxisLeft = d3.svg.axis()
.scale(yScaleLeft)
.orient("left")
.tickFormat(d3.format(".0%"));
var yAxisRight = d3.svg.axis()
.scale(yScaleRight)
.orient("right")
.tickFormat(d3.format(".0%"));
var x = d3.time.scale()
.range([0, width - 25]);
/*category.selectAll("rect")
.data(function(d) { return d.responses; })
.enter().append("rect")
.attr("width", xscale.rangeBand())
.attr("y", function(d) { return yScaleLeft(d.yp1); })
.attr("height", function(d) { return yScaleLeft(d.yp0) - yScaleLeft(d.yp1); })
.style("fill", function(d) { return colors(d.response); });*/
var temp = 0;
var line = d3.svg.line()
.x(function(d, i) {
console.log(temp);
var temp2 = temp;
temp += xscale.rangeBand();
return temp2;
})
.y(function(d) {
console.log(yScaleRight(d.value));
return yScaleRight(d.value);
})
.interpolate("linear")
;
var svg = d3.select(dom_element_to_append_to).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.tsv(path_to_data, function(error, data) {
//data = inputData;
var categories = d3.keys(data[0]).filter(function(key) { return key !== "CategoryNames"; });
var parsedata = categories.map(function(name) { return { "CategoryNames": name }; });
data.forEach(function(d) {
parsedata.forEach(function(pd) {
pd[d["CategoryNames"]] = d[pd["CategoryNames"]];
});
});
colors.domain(d3.keys(parsedata[0]).filter(function(key) { return key !== "CategoryNames" && key !== "Base"; }));
parsedata.forEach(function(pd) {
var y0 = 0;
pd.responses = colors.domain().map(function(response) {
var responseobj = {response: response, y0: y0, yp0: y0};
y0 += +pd[response];
responseobj.y1 = y0;
responseobj.yp1 = y0;
return responseobj;
});
pd.responses.forEach(function(d) { d.yp0 /= y0; d.yp1 /= y0; });
pd.totalresponses = pd.responses[pd.responses.length - 1].y1;
});
console.log(parsedata);
xscale.domain(parsedata.map(function(d) { return d.CategoryNames; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xaxis)
.selectAll("text")
.attr("y", 5)
.attr("x", 7)
.attr("dy", ".35em")
.attr("transform", "rotate(65)")
.style("text-anchor", "start");
svg.append("g")
.attr("class", "y axisLeft")
.call(yAxisLeft);
svg.append("g")
.attr("class", "y axisRight")
.attr("transform", function() { return "translate(" + width + "," + 0 + ")"; })
.call(yAxisRight);
var category = svg.selectAll(".category")
.data(parsedata)
.enter().append("g")
.attr("class", "category")
.attr("transform", function(d) { return "translate(" + xscale(d.CategoryNames) + ",0)"; });
category.selectAll("rect")
.data(function(d) { return d.responses; })
.enter().append("rect")
.attr("width", xscale.rangeBand())
.attr("y", function(d) { return yScaleLeft(d.yp1); })
.attr("height", function(d) { return yScaleLeft(d.yp0) - yScaleLeft(d.yp1); })
.style("fill", function(d) { return colors(d.response); });
var convertedData = [];
parsedata.forEach(function(item) {
convertedData.push({response: item.CategoryNames, value: item.responses[0].yp1})
});
temp = xscale.rangeBand()/2;
console.log(convertedData);
svg.append("path")
.data(convertedData)
.attr("class", "line")
.attr("d", line(convertedData));
var legend = svg.selectAll(".legend")
.data(colors.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(82," + ((height - 18) - (i * 20)) + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", colors);
legend.append("text")
.attr("x", width + 10)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d; });
d3.selectAll("input").on("change", handleFormClick);
function handleFormClick() {
if (this.value === "bypercent") {
transitionPercent();
} else {
transitionCount();
}
}
function transitionPercent() {
yScaleLeft.domain([0, 1]);
var trans = svg.transition().duration(250);
var categories = trans.selectAll(".category");
categories.selectAll("rect")
.attr("y", function(d) { return yScaleLeft(d.yp1); })
.attr("height", function(d) { return yScaleLeft(d.yp0) - yScaleLeft(d.yp1); });
yAxisLeft.tickFormat(d3.format(".0%"));
svg.selectAll(".y.axisLeft").call(yAxisLeft);
}
function transitionCount() {
yScaleLeft.domain([0, d3.max(parsedata, function(d) { return d.totalresponses; })]);
var transone = svg.transition()
.duration(100);
var categoriesone = transone.selectAll(".category");
categoriesone.selectAll("rect")
.attr("y", function(d) { return this.getBBox().y + this.getBBox().height - (yScaleLeft(d.y0) - yScaleLeft(d.y1)) })
.attr("height", function(d) { return yScaleLeft(d.y0) - yScaleLeft(d.y1); });
var transtwo = transone.transition()
.delay(150)
.duration(200)
.ease("bounce");
var categoriestwo = transtwo.selectAll(".category");
categoriestwo.selectAll("rect")
.attr("y", function(d) { return yScaleLeft(d.y1); });
yAxisLeft.tickFormat(d3.format(".2s"));
svg.selectAll(".y.axisLeft").call(yAxisLeft);
}
});
d3.select(self.frameElement).style("height", (height + margin.top + margin.bottom) + "px");
}
var inputData = [];
renderNormalizedStackBarChart(inputData,"#normalizedChart", "data/normalizedChart.tsv");
rect.bordered {
stroke: #E6E6E6;
stroke-width: 2px;
}
body {
font-size: 9pt;
font-family: Consolas, courier;
}
text.axis {
fill: #000;
}
.axisLeft path,
.axisLeft line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axisRight path,
.axisRight line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
.legend line {
stroke: #000;
shape-rendering: crispEdges;
}
path .line {
stroke: #000;
shape-rendering: crispEdges;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<div class="row">
<form>
<label><input type="radio" name="mode" value="bypercent" checked> Percent</label>
<label><input type="radio" name="mode" value="bycount"> Number of Respondants</label>
</form>
<div id="normalizedChart"></div>
</div>
but all I'm getting is the graph shown in the image below. How to make the path appear as line.Here in the code InputData variable is of no use as I'm reading data through a tsv file.
You have to add the style to your fill : none to your path
svg.append("path")
.data(convertedData)
.attr("class", "line")
.attr("d", line(convertedData));
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");
I have a brush coordinated with a bar chart. When the brush is moved and resized the bar chart shows only the filtered bars. In the same page I have a pie chart that isn't coordinated with the bar chart and the brush, but I want it to be. I want that also the pie chart updates its content according to the filtered values. How can I do that?
This is my code, followed by the plnkr link where you can see what I've done so far:
<script type="text/javascript">
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40,
mid: 20
},
w = 750 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var barPadding = 1;
var padding = 20;
var miniHeight = 60;
var selected;
var svg = d3.select(".outer-wrapper .chart").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.mid + miniHeight + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var barsGroup = svg.append('g')
.attr("class","barsGroup");
var miniGroup = svg.append('g')
.attr("class","miniGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var brushGroup = svg.append('g')
.attr("class","brushGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var w2 = 400;
var h2 = 400;
var outerRadius = w2 / 2;
var innerRadius = w2 / 3;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.values; });
var color = d3.scale.category20c();
var svg2 = d3.select("body")
.append("svg")
.attr("width", w2)
.attr("height", h2);
d3.csv("data.csv", function(data) {
var dataset = d3.nest()
.key(function(d) {
return d.Year;
})
.sortKeys(d3.ascending)
.rollup(function(values) {
return values.length;
})
.entries(data)
.filter(function(d) {
return d.key != "UNK" && d.key != "VAR" && d.key != 199 && d.key != 211 && d.key != 2017;
});
//SCALES
var xScale = d3.scale.ordinal()
.domain(dataset.map(function(d) {
return d.key
}))
.rangeRoundBands([0, w], 0.05);
var xScaleBrush = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([h, 0]);
//AXIS
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickValues([1900,1920,1930,1940,1950,1960,1970,1980,1990,2000, 2010]);
var yAxis = d3.svg.axis()
.scale(yScale)
.ticks(6)
.orient("left");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class","x2 axis")
.attr("transform", "translate(" + 0 + "," + (margin.top + h + margin.mid + miniHeight) + ")" )
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.append("g")
.attr("class", "axisLabel")
.append("text")
.attr("transform", "translate(" + -(margin.left * 0.8) + "," + (h/2) + "), rotate(-90)")
.style("text-anchor", "middle")
.text("Score");
var brush = d3.svg.brush()
.x(xScaleBrush)
.extent([0, w])
.on("brush", display);
brushGroup.append("g")
.attr("class", "brush")
.call(brush)
.selectAll("rect")
.attr("opacity", 0.5)
.attr("height", miniHeight);
function display() {
selected = xScaleBrush.domain()
.filter(function(d){
return (brush.extent()[0] <= xScaleBrush(d)) && (xScaleBrush(d) <= brush.extent()[1]);
});
var start;
var end;
/* Keep a minimum amount of bars on there to avoid any jank */
if (selected.length > 2) {
start = selected[0];
end = selected[selected.length - 1] + 1;
} else {
start = 0;
end = dataset.length;
}
var updatedData = dataset.slice(start, end);
updateBars(updatedData);
}
function update(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.attr("x", function(d) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale(d.values) : 0;
})
.attr("width", function (d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
});
}
function enter(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale( d.values) : 0;
})
.attr("width", function(d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
})
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
})
.on("mouseover", function(d) {
if(main){
d3.select(this)
.attr("fill", "orange");
var xPosition = parseFloat(d3.select(this).attr("x"));
var yPosition = parseFloat(d3.select(this).attr("y")) / 2 + 100;
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.style("z-index", "10")
.select("#value")
.text(d.values);
d3.select("#tooltip")
.select("#key")
.text("Film del " + d.key + " rilasciati su DVD");
d3.select("#tooltip").classed("hidden", false);
}
})
.on("mouseout", function(d) {
d3.select(this)
.transition()
.duration(250)
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
});
d3.select("#tooltip").classed("hidden", true);
});
}
function exit(grp, data) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
}).exit()
.remove();
}
function updateBars(data) {
xScale.domain(data.map(function(d) {
return d.key
}));
yScale.domain([0, d3.max(data, function(d) {
return d.values;
})]);
/* Update */
update(barsGroup, data, true);
/* Enter… */
enter(barsGroup, data, true);
/* Exit */
exit(barsGroup, data);
svg.select(".outer-wrapper .chart .y")
.transition()
.duration(10)
.call(yAxis);
svg.select(".outer-wrapper .chart .x")
.transition()
.duration(50)
.call(xAxis);
}
enter(miniGroup, dataset, false);
updateBars(dataset);
var dataset2 = d3.nest()
.key(function(d) { return d.Genre; })
.sortKeys(d3.ascending)
.rollup(function(values) { return values.length; })
.entries(data);
var text = svg2.append("text")
.attr("dx", 200)
.attr("dy", 200)
.attr("font-size", 30)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text2 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 230)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text3 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 260)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
//Set up groups
var arcs = svg2.selectAll("g.arc")
.data(pie(dataset2))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
.on("mouseover", function(d) {
var total = data.length;
var percent = Math.round(1000 * d.value / total) / 10;
text.text(d.data.key).attr("class", "inner-circle");
text2.text(d.value + " DVD");
text3.text(percent +"%");
})
.on("mouseout", function(d) {
text.text(function(d) { return ""; });
text2.text(function(d) { return ""; });
text3.text(function(d) { return ""; });
});
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
});
</script>
http://plnkr.co/edit/cwNl6zUSOM4yPmUtSRr4?p=preview
You can do that by transforming the part where you build the pieChart into a function that receives the new data.
The only adjustment is that the first thing I'm doing is removing the previous pie chart, to draw it again with the new data:
function updatePie(data){
svg2.selectAll("g.arc").remove();
Here is the complete code:
<script type="text/javascript">
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40,
mid: 20
},
w = 750 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var barPadding = 1;
var padding = 20;
var miniHeight = 60;
var selected;
var svg = d3.select(".outer-wrapper .chart").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.mid + miniHeight + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var barsGroup = svg.append('g')
.attr("class","barsGroup");
var miniGroup = svg.append('g')
.attr("class","miniGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var brushGroup = svg.append('g')
.attr("class","brushGroup")
.attr("transform","translate(" + 0 + "," + (margin.top + h + margin.mid) + ")");
var w2 = 400;
var h2 = 400;
var outerRadius = w2 / 2;
var innerRadius = w2 / 3;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.values; });
var color = d3.scale.category20c();
var svg2 = d3.select("body")
.append("svg")
.attr("width", w2)
.attr("height", h2);
d3.csv("data.csv", function(data) {
var dataset = d3.nest()
.key(function(d) {
return d.Year;
})
.sortKeys(d3.ascending)
.rollup(function(values) {
return values.length;
})
.entries(data)
.filter(function(d) {
return d.key != "UNK" && d.key != "VAR" && d.key != 199 && d.key != 211 && d.key != 2017;
});
//SCALES
var xScale = d3.scale.ordinal()
.domain(dataset.map(function(d) {
return d.key
}))
.rangeRoundBands([0, w], 0.05);
var xScaleBrush = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([h, 0]);
//AXIS
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickValues([1900,1920,1930,1940,1950,1960,1970,1980,1990,2000, 2010,2020,2030,2040,2050,2060]);
var yAxis = d3.svg.axis()
.scale(yScale)
.ticks(6)
.orient("left");
//Appendi asse x
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
//Asse x per brush
svg.append("g")
.attr("class","x2 axis")
.attr("transform", "translate(" + 0 + "," + (margin.top + h + margin.mid + miniHeight) + ")" )
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.append("g")
.attr("class", "axisLabel")
.append("text")
.attr("transform", "translate(" + -(margin.left * 0.8) + "," + (h/2) + "), rotate(-90)")
.style("text-anchor", "middle")
.text("Score");
var brush = d3.svg.brush()
.x(xScaleBrush)
.extent([0, w])
.on("brush", display);
brushGroup.append("g")
.attr("class", "brush")
.call(brush)
.selectAll("rect")
.attr("opacity", 0.5)
.attr("height", miniHeight);
function display() {
selected = xScaleBrush.domain()
.filter(function(d){
return (brush.extent()[0] <= xScaleBrush(d)) && (xScaleBrush(d) <= brush.extent()[1]);
});
var start;
var end;
/* Keep a minimum amount of bars on there to avoid any jank */
if (selected.length > 2) {
start = selected[0];
end = selected[selected.length - 1] + 1;
} else {
start = 0;
end = dataset.length;
}
var updatedData = dataset.slice(start, end);
updateBars(updatedData);
updatePie(updatedData);
}
function update(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.attr("x", function(d) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale(d.values) : 0;
})
.attr("width", function (d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
});
}
function enter(grp, data, main) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
})
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(d.key);
})
.attr("y", function(d) {
return main ? yScale( d.values) : 0;
})
.attr("width", function(d) {
return xScale.rangeBand();
})
.attr("height", function(d) {
return main ? h - yScale(d.values) : miniHeight;
})
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
})
.on("mouseover", function(d) {
if(main){
d3.select(this)
.attr("fill", "orange");
var xPosition = parseFloat(d3.select(this).attr("x"));
var yPosition = parseFloat(d3.select(this).attr("y")) / 2 + 100;
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.style("z-index", "10")
.select("#value")
.text(d.values);
d3.select("#tooltip")
.select("#key")
.text("Film del " + d.key + " rilasciati su DVD");
d3.select("#tooltip").classed("hidden", false);
}
})
.on("mouseout", function(d) {
d3.select(this)
.transition()
.duration(250)
.attr("fill", function(d) {
var color = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d.values;
})])
.range([200, 244]);
var deg = color(d.values);
return "hsl(" + deg + ", 100%, 50%)";
});
d3.select("#tooltip").classed("hidden", true);
});
}
function exit(grp, data) {
grp.selectAll("rect").data(data, function(d) {
return d.key;
}).exit()
.remove();
}
function updateBars(data) {
xScale.domain(data.map(function(d) {
return d.key
}));
yScale.domain([0, d3.max(data, function(d) {
return d.values;
})]);
/* Update */
update(barsGroup, data, true);
/* Enter… */
enter(barsGroup, data, true);
/* Exit */
exit(barsGroup, data);
svg.select(".outer-wrapper .chart .y")
.transition()
.duration(10)
.call(yAxis);
svg.select(".outer-wrapper .chart .x")
.transition()
.duration(50)
.call(xAxis);
}
enter(miniGroup, dataset, false);
updateBars(dataset);
var dataset2 = d3.nest()
.key(function(d) { return d.Genre; })
.sortKeys(d3.ascending)
.rollup(function(values) { return values.length; })
.entries(data);
var text = svg2.append("text")
.attr("dx", 200)
.attr("dy", 200)
.attr("font-size", 30)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text2 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 230)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
var text3 = svg2.append("text")
.attr("dx", 200)
.attr("dy", 260)
.attr("font-size", 20)
.style("text-anchor", "middle")
.attr("fill", "#36454f");
function updatePie(data){
svg2.selectAll("g.arc").remove();
var arcs = svg2.selectAll("g.arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
.on("mouseover", function(d) {
var total = data.length;
var percent = Math.round(1000 * d.value / total) / 10;
text.text(d.data.key).attr("class", "inner-circle");
text2.text(d.value + " DVD");
text3.text(percent +"%");
})
.on("mouseout", function(d) {
text.text(function(d) { return ""; });
text2.text(function(d) { return ""; });
text3.text(function(d) { return ""; });
});
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
}
updatePie(dataset2);
});
I'm trying to make a d3 scatterplot recurring to json data. I know that d3 has d3.json to load json data but my code isn't working. I'm not that good dealing with js (it's my first time with this language), that's why I need help in this.
Basically, I need to plot this data (date in xAxis and IADP_mGycm2 in yAxis):
[
{
"imageID": 1,
"value": 288.3,
"date": "2015-10-22"
},
{
"imageID": 2,
"value": 188.1,
"date": "2015-10-22"
}
]
JS:
var margin = { top: 50, right: 300, bottom: 50, left: 50 },
outerWidth = 1050,
outerHeight = 500,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]).nice();
var y = d3.scale.linear()
.range([height, 0]).nice();
var xCat = "date",
yCat = "value";
d3.json("CR.json", function(error, rawData) {
if (error) {
console.error(error);
return;
}
var data = rawData.map(function (d) {
return {
date: d.date,
value: d.value
}
});
var xMax = d3.max(data, function(d) { return d["date"]; }),
xMin = d3.min(data, function(d) { return d["date"]; }),
xMin = xMin > 0 ? 0 : xMin,
yMax = d3.max(data, function(d) { return d["value"]; }) ,
yMin = d3.min(data, function(d) { return d["value"]; }),
yMin = yMin > 0 ? 0 : yMin;
x.domain([xMin, xMax]);
y.domain([yMin, yMax]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width);
var color = d3.scale.category10();
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return xCat + ": " + d["date"] + "<br>" + yCat + ": " + d["value"];
});
var zoomBeh = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([0, 500])
.on("zoom", zoom);
var svg = d3.select("#scatter")
.append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoomBeh);
svg.call(tip);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.classed("x axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.classed("label", true)
.attr("x", width)
.attr("y", margin.bottom - 10)
.style("text-anchor", "end")
.text(xCat);
svg.append("g")
.classed("y axis", true)
.call(yAxis)
.append("text")
.classed("label", true)
.attr("transform", "rotate(-90)")
.attr("y", -margin.left)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yCat);
var objects = svg.append("svg")
.classed("objects", true)
.attr("width", width)
.attr("height", height);
objects.append("svg:line")
.classed("axisLine hAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("transform", "translate(0," + height + ")");
objects.append("svg:line")
.classed("axisLine vAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", height);
objects.selectAll(".dot")
.data(data)
.enter().append("circle")
.classed("dot", true)
.attr("cy", function (d) { return d.value; })
.attr("cx", function (d) { return d.date; })
.attr("transform", transform)
.style("fill", "red")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.classed("legend", true)
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("circle")
.attr("r", 3.5)
.attr("cx", width + 20)
.attr("fill", color);
legend.append("text")
.attr("x", width + 26)
.attr("dy", ".35em")
.text(function(d) { return d; });
d3.select("input").on("click", change);
function change() {
xCat = "date";
xMax = d3.max(data, function(d) { return d["date"]; });
xMin = d3.min(data, function(d) { return d["date"]; });
zoomBeh.x(x.domain([xMin, xMax])).y(y.domain([yMin, yMax]));
var svg = d3.select("#scatter").transition();
svg.select(".x.axis").duration(750).call(xAxis).select(".label").text("date");
objects.selectAll(".dot").transition().duration(1000).attr("transform", transform);
}
function zoom() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll(".dot")
.attr("transform", transform);
}
function transform(d) {
return "translate(" + x(d["date"]) + "," + y(d["value"]) + ")";
}
});
HTML:
<html>
<head>
<meta charset="utf-8">
<title>Visualization</title>
<link rel="stylesheet" href="scatter.css" charset="utf-8">
</head>
<body>
<div id="scatter"></div>
<input type="button" name="xAxis" value="xAxis">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script src="scatter.js" charset="utf-8"></script>
</body>
</html>
CSS:
rect {
fill: transparent;
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: rgba(0, 0, 0, 0.1);
shape-rendering: crispEdges;
}
.axisLine {
fill: none;
shape-rendering: crispEdges;
stroke: rgba(0, 0, 0, 0.5);
stroke-width: 2px;
}
.dot {
fill-opacity: .5;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
Thanks in advance!
One issue I see is that you're missing a }) at the end of this code chunk:
var data = rawData.map(function (d) {
return {
date: d.date,
IADP_mGycm2: d.IADP_mGycm2
};
Try changing it to this:
var data = rawData.map(function (d) {
return {
date: d.date,
IADP_mGycm2: d.IADP_mGycm2
}
});
It also helps in debugging if you include the specific error message you're getting.
Well, you define xCat as:
var xCat = "Date"
but your mapping function uses:
date: d.date
so, when you reference d[xCat] what you are getting is d.Date (which is undefined and would cause NaN) instead of d.date. That's all I can see with a quick look through.
You can fix this by using d['date'] or d.date instead of d[xCat].
Ok, after looking a little further at this, I've identified a couple of problems. The main issue is that the chart you are trying to emulate has numeric values on both the x and y axes. However, you are trying to use dates. In order to do that, you have to use d3.time.scale() for the x-axis instead of a linear scale. You also have to transform the date strings from your data to date objects and use your time scale to scale your x-axis values. Here is scatter.js with the changes:
var margin = { top: 50, right: 300, bottom: 50, left: 50 },
outerWidth = 1050,
outerHeight = 500,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
// Use a time scale for the x-axis
var x = d3.time.scale()
.range([0, width]).nice();
var y = d3.scale.linear()
.range([height, 0]).nice();
var xCat = "date",
yCat = "Dose";
d3.json("CR.json", function(error, rawData) {
if (error) {
console.error(error);
return;
}
var data = rawData.map(function(d) {
return {
// Create date objects, not strings
date: new Date(d.date),
IADP_mGycm2: d.IADP_mGycm2
}
});
var xMax = d3.max(data, function(d) { return d["date"]; }),
xMin = d3.min(data, function(d) { return d["date"]; }),
//xMin = xMin > 0 ? 0 : xMin,
yMax = d3.max(data, function(d) { return d["IADP_mGycm2"]; }),
yMin = d3.min(data, function(d) { return d["IADP_mGycm2"]; });
//yMin = yMin > 0 ? 0 : yMin;
x.domain([xMin, xMax]);
y.domain([yMin, yMax]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width);
var color = d3.scale.category10();
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return xCat + ": " + d["date"] + "<br>" + yCat + ": " + d["IADP_mGycm2"];
});
var zoomBeh = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([0, 500])
.on("zoom", zoom);
var svg = d3.select("#scatter")
.append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoomBeh);
svg.call(tip);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.classed("x axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.classed("label", true)
.attr("x", width)
.attr("y", margin.bottom - 10)
.style("text-anchor", "end")
.text(xCat);
svg.append("g")
.classed("y axis", true)
.call(yAxis)
.append("text")
.classed("label", true)
.attr("transform", "rotate(-90)")
.attr("y", -margin.left)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yCat);
var objects = svg.append("svg")
.classed("objects", true)
.attr("width", width)
.attr("height", height);
objects.append("svg:line")
.classed("axisLine hAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("transform", "translate(0," + height + ")");
objects.append("svg:line")
.classed("axisLine vAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", height);
objects.selectAll(".dot")
.data(data)
.enter().append("circle")
.classed("dot", true)
.attr("cy", function(d) { return d.IADP_mGycm2; })
// Use the time scale to scale the values for the x-axis
.attr("cx", function(d) { return x(d.date); })
.attr("transform", transform)
.style("fill", "red")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.classed("legend", true)
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("circle")
.attr("r", 3.5)
.attr("cx", width + 20)
.attr("fill", color);
legend.append("text")
.attr("x", width + 26)
.attr("dy", ".35em")
.text(function(d) { return d; });
d3.select("input").on("click", change);
function change() {
xCat = "date";
xMax = d3.max(data, function(d) { return d["date"]; });
xMin = d3.min(data, function(d) { return d["date"]; });
zoomBeh.x(x.domain([xMin, xMax])).y(y.domain([yMin, yMax]));
var svg = d3.select("#scatter").transition();
svg.select(".x.axis").duration(750).call(xAxis).select(".label").text("date");
objects.selectAll(".dot").transition().duration(1000).attr("transform", transform);
}
function zoom() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll(".dot")
.attr("transform", transform);
}
function transform(d) {
return "translate(" + x(d["date"]) + "," + y(d["IADP_mGycm2"]) + ")";
}
});
This gets rid of the errors you were seeing, but it still doesn't plot the circles correctly. Sorry, I don't have the time to work all that out. However, this should move you forward and get you closer to figuring it out yourself. To learn more about time scales, see https://github.com/mbostock/d3/wiki/Time-Scales. Also, if you really want to learn D3, I highly recommend the book D3.js in Action by Elijah Meeks. https://www.manning.com/books/d3-js-in-action. One of the better programming books I have read.