Whenever the slider is dragged and a new date is selected it does not redraw the first bar, it redraws all the other bars. For example, try date 09/06 and then 09/17. The first bar for id 54042 will not redraw. This is the link to my bl.ocks http://blockbuilder.org/fall16mis/87a39bc00b1b356f78dfd0954f345444
This is the code:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
.tooltip {
opacity: 0;
background-color: #ffe047;
position: absolute;
}
.grid line {
stroke: lightgrey;
shape-rendering: crispEdges;
}
.ticks {
font-size: 11px;
}
.track,
.track-inset,
.track-overlay {
stroke-linecap: round;
}
.track {
stroke: #000;
stroke-opacity: 0.3;
stroke-width: 10px;
}
.track-inset {
stroke: #ddd;
stroke-width: 8px;
}
.track-overlay {
pointer-events: stroke;
stroke-width: 50px;
stroke: transparent;
cursor: crosshair;
}
.handle {
fill: #fff;
stroke: #000;
stroke-opacity: 0.5;
stroke-width: 1.25px;
}
.bar:hover{
fill:#0f9fff;
}
.legend{
color:#005ebc;
z-index:0;
}
</style>
</head>
<body>
<div id="slider"></div>
<script>
var json_data = "id,date,start_time,end_time\n\
54042,2017/09/06,5.50,5.53\n\
54042,2017/09/06,7.55,9.19\n\
54042,2017/09/16,11.12,12.28\n\
54042,2017/09/23,13.56,15.03\n\
54042,2017/09/07,16.29,17.33\n\
54042,2017/09/06,19.56,20.53\n\
54042,2017/09/20,21.3,22.14\n\
98765,2017/09/06,5.1,6.51\n\
98765,2017/09/06,11.4,11.53\n\
98765,2017/09/06,12.2,12.42\n\
98765,2017/09/06,12.55,14.2\n\
98765,2017/09/16,21.42,21.59\n\
98765,2017/09/16,22.01,23.13\n\
98765,2017/09/16,23.16,23.51\n\
98765,2017/09/23,13.41,14.03\n\
65299,2017/09/06,7.23,8.21\n\
65299,2017/09/06,9.37,10.23\n\
65299,2017/09/06,11.46,13.29\n\
65299,2017/09/06,18.07,19.57\n\
65299,2017/09/17,14.41,16.22\n\
65299,2017/09/17,21.39,23.39\n\
79408,2017/09/06,9.37,10.17\n\
79408,2017/09/06,11.03,12.08\n\
79408,2017/09/06,13.14,15.53\n\
79408,2017/09/06,16.05,17.48\n\
79408,2017/09/06,19.47,20.23\n\
38338,2017/09/06,8.22,9.28\n\
38338,2017/09/06,11.34,12.17\n\
38338,2017/09/07,12.43,13.35\n\
38338,2017/09/07,14.12,15.48\n\
38338,2017/09/07,16.09,17.23\n\
38338,2017/09/07,18.31,19.19\n\
38338,2017/09/07,21.49,23.26\n\
81757,2017/09/06,6.31,7.41\n\
81757,2017/09/06,8.18,9.39\n\
81757,2017/09/06,10.18,11.23\n\
81757,2017/09/06,13.02,14.04\n\
81757,2017/09/07,15.22,17.23\n\
81757,2017/09/07,20.32,22.01\n\
68077,2017/09/06,11.1,12.45\n\
68077,2017/09/06,15.23,16.54\n\
68077,2017/09/06,17.31,19.05\n\
68077,2017/09/06,20.39,21.3\n\
68077,2017/09/06,21.41,22.37\n\
58381,2017/09/06,16.51,17.55\n\
58381,2017/09/06,19.34,20.55\n\
58381,2017/09/06,21.33,22.51\n\
58381,2017/09/07,14.46,16.15\n\
37500,2017/09/06,8.2,10.18\n\
37500,2017/09/06,11.37,13.34\n\
37500,2017/09/06,19.22,20.16\n\
37500,2017/09/06,21.55,22.09\n\
37500,2017/09/16,14.16,16.26\n\
37500,2017/09/16,16.58,17.48\n\
39146,2017/09/06,19.47,20.21\n\
39146,2017/09/06,20.35,21.29\n\
39146,2017/09/06,22.01,23.25\n\
39146,2017/09/16,8.03,9.56\n\
39146,2017/09/16,10.23,12.52\n\
39146,2017/09/16,13.25,14.28";
window.data = d3.csvParse(json_data, function(d){ return {
id:d.id,
date:d.date,
start_time:+d.start_time,
end_time:+d.end_time}; });
window.minDate = d3.min(window.data,function(d){ return d.date; });
window.maxDate = d3.max(window.data,function(d){ return d.date; });
window.names = window.data.map(function(d){
return d.id; });
var parseDate = d3.timeParse("%Y/%m/%d");
var displayDate = d3.timeFormat("%m/%d");
var forChartDate = d3.timeFormat("%Y/%m/%d");
var height = 500;
var width = 800;
var margin = {left: 50, right: 20, bottom: 0, top: 70};
var tooltip = d3.select("body").append("div").attr("class", "tooltip")
var svg = d3.select("body").append("svg").attr("height","1000px").attr("width","100%");
var chartGroup = svg.append("g").attr("transform","translate("+margin.left+","+(margin.top+10)+")");
var legend = svg.append("g").attr("transform","translate("+margin.left+","+(margin.top+10)+")");
var chartDate = window.minDate;
var displaySlider = function(data){
window.x = d3.scaleLinear()
.domain([0, 24])
.range([0, width]);
window.y = d3.scaleBand()
.domain(window.names)
.rangeRound([height, 0])
.paddingInner(0.3);
function make_y_gridlines() {
return d3.axisLeft(y)
};
function make_x_gridlines() {
return d3.axisBottom(x)
};
chartGroup.append("g")
.attr("class","axis y")
.call(d3.axisLeft(y))
chartGroup.append("g")
.attr("class","axis x")
.call(d3.axisBottom(x))
.attr("transform","translate(0,"+height+")")
.call(d3.axisBottom(x)
.ticks(24));
chartGroup.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
);
chartGroup.append("g")
.attr("class", "grid")
.call(make_x_gridlines()
.tickSize(height)
.tickFormat("")
)
var newData = data.filter(function(d){
return d.date==chartDate;
})
displayBar(newData);
var x1 = d3.scaleTime()
.range([0, width])
.domain([parseDate(minDate), parseDate(maxDate)])
.clamp(true);
var slider = svg.append("g")
.attr("class", "slider")
.attr("transform", "translate(" + margin.left + ",30)");
slider.append("line")
.attr("class", "track")
.attr("x1", x1.range()[0])
.attr("x2", x1.range()[1])
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "track-inset")
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "track-overlay")
.call(d3.drag()
.on("start.interrupt", function() { slider.interrupt(); })
.on("drag end", function() { sliderFunc(x1.invert(d3.event.x)); }));
slider.insert("g", ".track-overlay")
.attr("class", "ticks")
.attr("transform", "translate(0," + 10 + ")")
.selectAll("text")
.data(x1.ticks(15))
.enter()
.append("text")
.attr("x", x1)
.attr("y", 10)
.attr("text-anchor", "middle")
.text(function(d) { return displayDate(d); });
var label = slider.append("text")
.attr("class", "label")
.attr("text-anchor", "middle")
.text(minDate)
.attr("transform", "translate(0," + (-10) + ")");
var handle = slider.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 7);
function sliderFunc(h) {
handle.attr("cx", x1(h));
label.attr("x", x1(h))
.text(displayDate(h));
chartDate = forChartDate(h);
console.log(chartDate);
newData = data.filter(function(d){
return d.date==chartDate;
})
//displayText(newData);
displayBar(newData);
}
};
var displayBar = function(data){
var bars = chartGroup.selectAll(".bar")
.data(data, function(d){
console.log(d);
return d;
});
bars.exit().remove();
bar_enter = bars.enter().append("rect")
bar_enter.attr("class", "bar")
.attr("x", function(d) {
console.log(d.start_time);
return window.x(d.start_time); })
.attr("y", function(d) { return window.y(d.id); })
.attr("height", window.y.bandwidth())
.attr("fill", "green")
.transition()
.duration(600)
.attr("width", function(d) { return window.x(d.end_time-d.start_time); });
bar_enter.on('mousemove', function(d,i){
tooltip.style("opacity","1")
.style("left",(d3.event.pageX+10)+"px")
.style("top",d3.event.pageY+"px");
tooltip.html(" Start Time:"+d.start_time+" End Time:"+d.end_time);
})
bar_enter.on('mouseout', function(){
tooltip.style("opacity","0")
});
};
displaySlider(window.data);
</script>
</body>
You cannot use the whole object in the key function:
var bars = chartGroup.selectAll(".bar")
.data(data, function(d){
return d;
});
The API explains it:
key function may be specified to control which datum is assigned to which element, replacing the default join-by-index, by computing a string identifier for each datum and element. (emphasis mine)
Therefore, instead of using the whole object, use a property (like the id):
var bars = chartGroup.selectAll(".bar")
.data(data, function(d){
return d.id;
});
Here is the updated bl.ocks: https://bl.ocks.org/GerardoFurtado/57d014aa5124bdbe5774e1457816ff43/07a233d46aa3ae91bcffb8682de9ed8376c99b9a
Following is my code. I have been trying to plot humidity and dew point in basis of months in the axis. But I am getting an error of data undefined and also the month in the axis comes in number.
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<title> Data Visualization - Binding Dataset to Shapes Using D3 </title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
</style>
<body>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 70, left: 50},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%b").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var priceline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.dew); });
// Adds the svg canvas
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 + ")");
// Get the data
d3.json("weatherdata.json", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.history.date.mon);
d.dew = +d.history.dailysummary[0].meandewptm;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.dew; }));
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {return d.dew;})
.entries(data);
var color = d3.scale.category10(); // set the colour scale
legendSpace = width/dataNest.length; // spacing for legend
// Loop through each symbol / key
dataNest.forEach(function(d,i) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key); })
.attr("d", priceline(d.values));
// Add the Legend
svg.append("text")
.attr("x", (legendSpace/2)+i*legendSpace) // spacing
.attr("y", height + (margin.bottom/2)+ 5)
.attr("class", "legend") // style the legend
.style("fill", function() { // dynamic colours
return d.color = color(d.key); })
.text(d.key);
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>
</html>
I am not sure how will i solve it. Can anyone please help. I am sharing the data file with the current issue I am facing.
I have attached the model data the way it should look like:
Thanks in advance.
For your question on Date format for the X axis , sorry i put an answer because i can't comment (need more reputation).
I think you need to do something like this
chart.xAxis
.tickFormat(function(d) {
return d3.time.format('%b')(format(d));
});
That will display only the month.
I have a data in csv like this:
date,partner,units
2012-05-01,team1,34.12
2012-04-30,team1,45.56
2012-04-27,team2,67.89
2012-04-26,team1,78.54
2012-04-25,team2,89.23
2012-04-24,team2,99.23
2012-04-23,team2,101.34
I want to plot two lines (one for team1, one for team2 using this data), but I am just getting a scatterplot using the following complete d3 code, is my filtering wrong?
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
#line1 {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
#line2 {
fill: none;
stroke: red;
stroke-width: 2px;
}
</style>
<input type="button" onclick="hideLine()">
<input type="button" onclick="showLine()">
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var parseTime = d3.timeParse("%Y-%m-%d");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the 1st line
var valueline = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.units); });
// define the 2nd line
var valueline2 = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.units); });
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 + ")");
// Get the data
d3.csv("data1.csv", function(error, data) {
if (error) throw error;
// format the data
data.forEach(function(d) {
d.date = parseTime(d.date);
d.units = +d.units;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
m = d3.max(data, function(d) {
var m = d.units;
return m;
});
console.log("Max:", m);
y.domain([0,m]);
// Add the valueline path.
svg.append("path")
.data([data])
.filter(function(d) { return d.partner == 'team1'; })
.attr("id", "line1")
.attr("d", valueline);
console.log("DATA", data)
svg.selectAll(".point")
.data(data)
.enter()
.append("circle")
.attr("class", "point")
.attr("cx", function (d, i) {
return x(d.date);
})
.attr("cy", function(d) {
return y(d.units);
})
.attr("r", 4)
.on("mouseover", function(d) { console.log(d.units) });
// Add the valueline2 path.
svg.append("path")
.data([data])
.filter(function(d) { return d.partner == 'team2'; })
.attr("id", "line2")
.style("stroke", "red")
.attr("d", valueline2)
.on("mouseover", function(d) {console.log(d)});
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y));
});
function hideLine() {
console.log("Hideline");
d3.select("#line2").attr("style", "opacity:0");
}
function showLine() {
console.log("ShowLine");
d3.select("#line2").attr("style", "opacity:1");
}
</script>
</body>
Yes, your filter is wrong. You are wrapping your data in another [] which means the filter is only operating on the outer array.
Do this instead:
svg.append("path")
.datum(data.filter(function(d) { return d.partner == 'team1'; }))
.attr("id", "line1")
.attr("d", valueline);
Working example here.
I'm wrestling with a problem of a brush not being removed correctly on a bar chart. You can see the Bl.ock here and see what's not working correctly.
In short, the brush highlights the bars that have been selected by the brush, as well as snaps to the edge of the rect to make selecting spans of time easier (there's a secondary bug here where the brush snapping isn't quite mapping correctly to the dates -- you'll see this if you try to draw the brush up to the edge of the barchart). Somewhere along the way (maybe with the rect snapping?) the background click-to-remove-brush feature stopped working (it now selects a single year span, although doesn't highlight the rect correctly). To make it easier for users, I wanted to add a button that a user can click to remove the brush when they're done (the resetBrush() function below).
My understanding was the brush selection can be cleared with brush.extent(), but when you clear the extent you then have to redraw the brush. I thought I was doing that correctly, but alas, I'm running into some problem somewhere that I can't seem to track down. Any pointers on where I'm tripping up would be greatly appreciated!
Code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: sans-serif;
color: #000;
text-rendering: optimizeLegibility;
}
.barchart {
z-index: 30;
display: block;
visibility: visible;
position: relative;
padding-top: 15px;
margin-top: 15px;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.resize path {
fill: #666;
fill-opacity: .8;
stroke: #000;
stroke-width: 1.5px;
}
.brush .extent {
stroke: #fff;
stroke-opacity: .6;
stroke-width: 2px;
fill-opacity: .1;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
brushYearStart = 1848;
brushYearEnd = 1905;
// Scales
var x = d3.scale.ordinal().rangeRoundBands([0, width - 60], .1);
var y = d3.scale.linear().range([height, 0]);
// Prepare the barchart canvas
var barchart = d3.select("body").append("svg")
.attr("class", "barchart")
.attr("width", "100%")
.attr("height", height + margin.top + margin.bottom)
.attr("y", height - height - 100)
.append("g");
var z = d3.scale.ordinal().range(["steelblue", "indianred"]);
var brushYears = barchart.append("g")
brushYears.append("text")
.attr("id", "brushYears")
.classed("yearText", true)
.text(brushYearStart + " - " + brushYearEnd)
.attr("x", 35)
.attr("y", 12);
d3.csv("years_count.csv", function (error, post) {
// Coercion since CSV is untyped
post.forEach(function (d) {
d["frequency"] = +d["frequency"];
d["frequency_discontinued"] = +d["frequency_discontinued"];
d["year"] = d3.time.format("%Y").parse(d["year"]).getFullYear();
});
var freqs = d3.layout.stack()(["frequency", "frequency_discontinued"].map(function (type) {
return post.map(function (d) {
return {
x: d["year"],
y: +d[type]
};
});
}));
x.domain(freqs[0].map(function (d) {
return d.x;
}));
y.domain([0, d3.max(freqs[freqs.length - 1], function (d) {
return d.y0 + d.y;
})]);
// Axis variables for the bar chart
x_axis = d3.svg.axis().scale(x).tickValues([1850, 1855, 1860, 1865, 1870, 1875, 1880, 1885, 1890, 1895, 1900]).orient("bottom");
y_axis = d3.svg.axis().scale(y).orient("right");
// x axis
barchart.append("g")
.attr("class", "x axis")
.style("fill", "#000")
.attr("transform", "translate(0," + height + ")")
.call(x_axis);
// y axis
barchart.append("g")
.attr("class", "y axis")
.style("fill", "#000")
.attr("transform", "translate(" + (width - 85) + ",0)")
.call(y_axis);
// Add a group for each cause.
var freq = barchart.selectAll("g.freq")
.data(freqs)
.enter().append("g")
.attr("class", "freq")
.style("fill", function (d, i) {
return z(i);
})
.style("stroke", "#CCE5E5");
// Add a rect for each date.
rect = freq.selectAll("rect")
.data(Object)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function (d) {
return x(d.x);
})
.attr("y", function (d) {
return y(d.y0) + y(d.y) - height;
})
.attr("height", function (d) {
return height - y(d.y);
})
.attr("width", x.rangeBand())
.attr("id", function (d) {
return d["year"];
});
// Draw the brush
brush = d3.svg.brush()
.x(x)
.on("brush", brushmove)
.on("brushend", brushend);
var arc = d3.svg.arc()
.outerRadius(height / 15)
.startAngle(0)
.endAngle(function(d, i) { return i ? -Math.PI : Math.PI; });
brushg = barchart.append("g")
.attr("class", "brush")
.call(brush);
brushg.selectAll(".resize").append("path")
.attr("transform", "translate(0," + height / 2 + ")")
.attr("d", arc);
brushg.selectAll("rect")
.attr("height", height);
});
// ****************************************
// Brush functions
// ****************************************
function brushmove() {
y.domain(x.range()).range(x.domain()).clamp(true);
b = brush.extent();
brushYearStart = Math.ceil(y(b[0]));
brushYearEnd = Math.ceil(y(b[1]));
// Snap to rect edge
d3.select("g.brush").call(brush.extent([y.invert(brushYearStart), y.invert(brushYearEnd)]));
// Fade all years in the histogram not within the brush
d3.selectAll("rect.bar").style("opacity", function (d, i) {
return d.x >= brushYearStart && d.x < brushYearEnd ? "1" : ".4"
});
}
function brushend() {
// Additional calculations happen here...
// filterPoints();
// colorPoints();
// styleOpacity();
// Update start and end years in upper right-hand corner of the map
d3.select("#brushYears").text(brushYearStart + " - " + brushYearEnd);
}
function resetBrush() {
d3.selectAll(".brush").remove();
d3.selectAll("brushg.resize").remove();
brush.clear();
brushg.call(brush);
}
</script>
<div id="resetMap">
<button
id="returnBrush"
class="btn btn-default"
onclick="resetBrush()"/>Remove Brush
</div>
</body>
</html>
If you execute d3.selectAll(".brush").remove(); you remove <g class="brush"></g> and his childs.
This d3.selectAll("brushg.resize").remove(); is a bug. Must to be brushg.selectAll(".resize").remove(); but is the same case that d3.selectAll(".brush").remove();.
You have to do this:
For reset the brush.extent() and fire the brush event.
function resetBrush() {
brush
.clear()
.event(d3.select(".brush"));
}
For reset #brushYears to the initial state
function brushend() {
var localBrushYearStart = (brush.empty()) ? brushYearStart : Math.ceil(y(b[0])),
localBrushYearEnd = (brush.empty()) ? brushYearEnd : Math.ceil(y(b[1]));
// Update start and end years in upper right-hand corner of the map
d3.select("#brushYears").text(localBrushYearStart + " - " + localBrushYearEnd);
}
For reset to initial values on brush event
function brushmove() {
y.domain(x.range()).range(x.domain()).clamp(true);
b = brush.extent();
3.1. To set the localBrushYearStart and localBrushYearEnd variables to initial state on brush.empty() or set to Math.ceil(brush.extent()))
var localBrushYearStart = (brush.empty()) ? brushYearStart : Math.ceil(y(b[0])),
localBrushYearEnd = (brush.empty()) ? brushYearEnd : Math.ceil(y(b[1]));
3.2. To execute brush.extent() on selection, or brush.clear() on brush.empty()
// Snap to rect edge
d3.select("g.brush").call((brush.empty()) ? brush.clear() : brush.extent([y.invert(localBrushYearStart), y.invert(localBrushYearEnd)]));
3.3. To set opacity=1 years on brush.empty() or selection, and opacity=.4 on not selected years
// Fade all years in the histogram not within the brush
d3.selectAll("rect.bar").style("opacity", function(d, i) {
return d.x >= localBrushYearStart && d.x < localBrushYearEnd || brush.empty() ? "1" : ".4";
});
}
Check the corrections on my BL.OCKS
Just do this
function resetBrush() {
d3.select("g.brush").call(brush.extent([0, 0]))
d3.selectAll("rect.bar").style("opacity", "0.4");
//reset year labels at top
}
I have extended the pie-chart example at:
with pies that vary in radius depending on a percentage. I would like to add gridlines (circles) every 20 percent, but I can't figure out how.
here is the updated csv:
age,population,percent
<5,2704659,67
5-13,4499890,38
14-17,2159981,91
18-24,3853788,49
25-44,14106543,71
45-64,8819342,88
=65,612463,64
and here is the updated code with pie-parts of different radius:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
background: #333;
}
.arc path {
stroke: #fff;
stroke-width: 2px;
}
.arc grid {
stroke: #fff;
stroke-width: 1;
stroke-dasharray: 5,5;
}
.arc text {
fill:#fff;
font-size:12px;
font-weight:bold;
}
.arc line {
stroke: #fff;
}
</style>
<body>
<script src="d3.js"></script>
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2 - 10;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(function(d) { return 50 + (radius - 50) * d.data.percent / 100; })
.innerRadius(20);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
var grid = d3.svg.area.radial()
.radius(150);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.population = +d.population;
d.percent = d.percent;
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.data.age; });
});
</script>
First set the number of ticks:
var numTicks = 5; // Each tick is 20%
Then create the data to create the gridlines:
var sdat = [];
for (i=0; i<=numTicks; i++) {
sdat[i] = (radius/numTicks) * i;
}
And then you can use a function to create the radial gridlines, and you can call it from within the d3.csv block:
addCircleAxes = function() {
var circleAxes, i;
svg.selectAll('.circle-ticks').remove();
circleAxes = svg.selectAll('.circle-ticks')
.data(sdat)
.enter().append('svg:g')
.attr("class", "circle-ticks");
// radial tick lines
circleAxes.append("svg:circle")
.attr("r", String)
.attr("class", "circle")
.style("stroke", "#CCC")
.style("opacity", 0.5)
.style("fill", "none");
// Labels for each circle
circleAxes.append("svg:text")
.attr("text-anchor", "center")
.attr("dy", function(d) { return d - 5 })
.style("fill", "#fff")
.text(function(d,i) { return i * (100/numTicks) });
};
An example is here: http://bl.ocks.org/3994129
(Borrowed from: http://kreese.net/blog/2012/08/26/d3-js-creating-a-polar-area-diagram-radial-bar-chart/)