I'm trying to build a legend to a calendar view graph using d3 js like this one
but i'm trying to build a legend to it like the kind of shown in the pic
but i'm not able to generate this
here's my code to generated calender view map
var Comparison_Type_Max = d3.max(inputData, function(d) { return d.value; });
var data = d3.nest()
.key(function(d) { return d.Date; })
.rollup(function(d) { return (d[0].value ); })
.map(inputData);
var margin = { top: 20, right: 50, bottom: 10, left: 60 },
width = $(dom_element_to_append_to).parent().width() - margin.left - margin.right,
cellSize = Math.floor(width/52),
height = cellSize * 7 + margin.top + margin.bottom ,
week_days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
$rootScope.defaultWidth = width;
$rootScope.cellSize = cellSize;
var day = d3.time.format("%w"),
week = d3.time.format("%U"),
percent = d3.format(".1%"),
format = d3.time.format("%Y%m%d"),
legendElementWidth = cellSize * 2,
buckets = 9,
parseDate = d3.time.format("%Y%m%d").parse;
var color = d3.scale.linear().range(colorRange)
.domain([0, 1]);
var colorScale = d3.scale.quantile()
.domain([0, buckets - 1, d3.max(data, function (d) { return d.value; })])
.range(colorRange);
var svg = d3.select(dom_element_to_append_to).selectAll("svg")
.data(d3.range(year, year+1))
.enter().append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("data-height", '0.5678')
.attr("class", "RdYlGn")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
console.log("1");
svg.append("text")
.attr("transform", "translate(-38," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.text(function(d) { return d; });
for (var i=0; i<7; i++)
{
svg.append("text")
.attr("transform", "translate(-5," + cellSize*(i+1) + ")")
.style("text-anchor", "end")
.attr("dy", "-.25em")
.text(function(d) { return week_days[i]; });
}
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter()
.append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) { return week(d) * cellSize; })
.attr("y", function(d) { return day(d) * cellSize; })
.attr("fill",'#fff')
.datum(format);
console.log("2");
/* var legend = svg.selectAll(".legend")
.data(data)
.enter().append("g")
.attr("class", "legend");
//.attr("transform", function(d, i) { return "translate(" + (((i+1) * cellSize*4.33)) + ",0)"; });
legend.append("rect")
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", cellSize / 2)
.style("fill", function(d, i) { return color(Math.sqrt(data[d] / Comparison_Type_Max )); });
legend.append("text")
.attr("class", "mono")
.text(function(d) { return "≥ " + Math.round(d); })
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height + cellSize);
*/
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) { return d; });
legend.enter().append("g")
.attr("class", "legend");
legend.append("rect")
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", cellSize / 2)
.style("fill", function(d, i) { return color(Math.sqrt(data[i] / Comparison_Type_Max )); });
legend.append("text")
.attr("class", "mono")
.text(function(d) { return "≥ " + Math.round(d); })
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height + cellSize);
legend.exit().remove();
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("id", function(d,i){ return month[i] + "" + varID })
.attr("d", monthPath);
console.log("4");
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
var year = d/10000;
year = Math.floor(year);
var month = d/100;
month = Math.floor(month % 100);
var day = d % 100;
if(day<10) day = "0" + day;
if(month < 10) month = "0" + month;
if(isCurrency)
return "<div><span>Date:</span> <span style='color:white'>" + day + "/" + month + "/" + year + "</span></div>" +
"<div><span>Value:</span> <span style='color:white'><span>₹</span>" + d3.format(",")(data[d]) + "</span></div>";
else
return "<div><span>Date:</span> <span style='color:white'>" + day + "/" + month + "/" + year + "</span></div>" +
"<div><span>Value:</span> <span style='color:white'>" + d3.format(",")(data[d]) + "</span></div>";
});
console.log("5");
svg.call(tip);
console.log("6");
rect.filter(function(d) { return d in data; })
.on("click", function(d){
console.log(d);
var year = d/10000;
year = Math.floor(year);
var monthInt = d/100;
console.log(dom_element_to_append_to);
var val,id;
if(dom_element_to_append_to=='.sms-yearheatmap-container-negative')
val = 0;
else if (dom_element_to_append_to=='.sms-yearheatmap-container-positive')
val = 1;
else val = 2;
monthInt = Math.floor(monthInt % 100);
for (var itr = 0; itr<12; ++itr) {
id = month[itr] + "" + varID;
$('#' + id).css("z-index",0);
$('#' + id).css("stroke","#000");
$('#' + id).css("stroke-width", "2.5px");
}
id = month[monthInt-1] + "" + varID;
$('#' + id).css("stroke","blue");
$('#' + id).css("position","relative");
$('#' + id).css("z-index",1000);
$('#' + id).css("stroke-width", "4.5px");
console.log("year " + year + " month" + monthInt);
$rootScope.loadDayHourHeatGraph(year, monthInt , val, isCurrency);
})
.attr("fill", function(d) { return color(Math.sqrt(data[d] / Comparison_Type_Max )); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
/*.attr("data-title", function(d) { return "value : "+Math.round(data[d])});
$("rect").tooltip({container: 'body', html: true, placement:'top'}); */
/* $("rect").on("click", function(d) {
console.log(d);
});*/
function numberWithCommas(x) {
x = x.toString();
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(x))
x = x.replace(pattern, "$1,$2");
return x;
it is generting the graph correctly but my legend is not generating with it
here's the code of legend which i wrote above
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) { return d; });
legend.enter().append("g")
.attr("class", "legend");
legend.append("rect")
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", cellSize / 2)
.style("fill", function(d, i) { return color(Math.sqrt(data[i] / Comparison_Type_Max )); });
legend.append("text")
.attr("class", "mono")
.text(function(d) { return "≥ " + Math.round(d); })
.attr("x", function(d, i) { return legendElementWidth * i; })
.attr("y", height + cellSize);
legend.exit().remove();
i don't want to use the colorscale variable instead i want to generate the legend according to the color variable defined in the main code, the colorscale variable is not used anywhere in the code but only in the legend just for a start, the whole calender view graph is generated using the the colorscheme provided by the color variable
Related
I'm trying to use some d3 javascript template.
In my solution I have to replace d3.csv with d3.csv.parse method.
I'm having big problem to do that. I just can't understand how I have to change my code.
Here is link to template i'm using.
http://bl.ocks.org/KathyZ/c2d4694c953419e0509b
Here is my code:
var width = 960,
height = 750,
cellSize = 25; // cell size
var no_months_in_a_row = Math.floor(width / (cellSize * 7 + 50));
var shift_up = cellSize * 3;
var day = d3.time.format("%w"), // day of the week
day_of_month = d3.time.format("%e") // day of the month
day_of_year = d3.time.format("%j")
week = d3.time.format("%U"), // week number of the year
month = d3.time.format("%m"), // month number
year = d3.time.format("%Y"),
percent = d3.format(".1%"),
format = d3.time.format("%Y-%m-%d");
var color = d3.scale.quantize()
.domain([-.05, .05])
.range(d3.range(11).map(function(d) { return "q" + d + "-11"; }));
var svg = d3.select("#chart").selectAll("svg")
.data(d3.range(2017, 2018))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "RdYlGn")
.append("g")
var rect = svg.selectAll(".day")
.data(function(d) {
return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1));
})
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) {
var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
return day(d) * cellSize + month_padding;
})
.attr("y", function(d) {
var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
var row_level = Math.ceil(month(d) / (no_months_in_a_row));
return (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;
})
.datum(format);
var month_titles = svg.selectAll(".month-title") // Jan, Feb, Mar and the whatnot
.data(function(d) {
return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.text(monthTitle)
.attr("x", function(d, i) {
var month_padding = 1.2 * cellSize*7* ((month(d)-1) % (no_months_in_a_row));
return month_padding;
})
.attr("y", function(d, i) {
var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
var row_level = Math.ceil(month(d) / (no_months_in_a_row));
return (week_diff*cellSize) + row_level*cellSize*8 - cellSize - shift_up;
})
.attr("class", "month-title")
.attr("d", monthTitle);
var year_titles = svg.selectAll(".year-title") // Jan, Feb, Mar and the whatnot
.data(function(d) {
return d3.time.years(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.text(yearTitle)
.attr("x", function(d, i) { return width/2 - 100; })
.attr("y", function(d, i) { return cellSize*5.5 - shift_up; })
.attr("class", "year-title")
.attr("d", yearTitle);
// Tooltip Object
var tooltip = d3.select("body")
.append("div").attr("id", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
/* This is what dji.csv have right now and its working. But I like to use string insteed. */
var dataIliketoUse = "Date,Open\n2010-10-01,1\n2010-09-30,1";
d3.csv("dji.csv", function(error, csv) {
var data = d3.nest()
.key(function(d) { return d.Date; })
.rollup(function(d) { return d[0].Value; })
.map(csv);
rect.filter(function(d) { return d in data; })
.attr("class", function(d) { return "day " + color(data[d]); })
.select("title")
.text(function(d) { return d + ": " + percent(data[d]); });
// Tooltip
rect.on("mouseover", mouseover);
rect.on("mouseout", mouseout);
function mouseover(d) {
tooltip.style("visibility", "visible");
var percent_data = (data[d] !== undefined) ? percent(data[d]) : percent(0);
var purchase_text = d + ": " + percent_data;
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(purchase_text)
.style("left", (d3.event.pageX)+30 + "px")
.style("top", (d3.event.pageY) + "px");
}
function mouseout (d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
var $tooltip = $("#tooltip");
$tooltip.empty();
}
});
function dayTitle (t0) {
return t0.toString().split(" ")[2];
}
function monthTitle (t0) {
return t0.toLocaleString("en-us", { month: "long" });
}
function yearTitle (t0) {
return t0.toString().split(" ")[3];
}
You should define variable csv this way:
var csv = d3.csv.parse(dataAsString, function(item) {
return item;
});
All code that was in callback function for d3.csv put after this variable definition.
var data = d3.nest()
.key(function(d) {
return d.Date;
})
.rollup(function(d) {
return (d[0].Close - d[0].Open) / d[0].Open;
})
.map(csv);
rect.filter(function(d) {
return d in data;
})
.attr("class", function(d) {
return "day " + color(data[d]);
})
.select("title")
.text(function(d) {
return d + ": " + percent(data[d]);
});
...
Check the working example here - https://jsfiddle.net/levsha/2zp8y7r8/
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);
});
hi I created a spiral chart in d3.js, and I want to add circle to different position of the spiral lines.according to there values.
circle closes to the center will have highest priority.
any idea how to do that.
here is the code which i wrote
var width = 400,
height = 430
num_axes = 8,
tick_axis = 1,
start = 0
end = 4;
var theta = function(r) {
return -2*Math.PI*r;
};
var arc = d3.svg.arc()
.startAngle(0)
.endAngle(2*Math.PI);
var radius = d3.scale.linear()
.domain([start, end])
.range([0, d3.min([width,height])/2-20]);
var angle = d3.scale.linear()
.domain([0,num_axes])
.range([0,360])
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/2 + "," + (height/2+8) +")");
var pieces = d3.range(start, end+0.001, (end-start)/1000);
var spiral = d3.svg.line.radial()
.interpolate("cardinal")
.angle(theta)
.radius(radius);
//svg.append("text")
// .text("And there was much rejoicing!")
// .attr("class", "title")
// .attr("x", 0)
// .attr("y", -height/2+16)
// .attr("text-anchor", "middle")
//svg.selectAll("circle.tick")
// .data(d3.range(end,start,(start-end)/4))
// .enter().append("circle")
// .attr("class", "tick")
// .attr("cx", 0)
// .attr("cy", 0)
// .attr("r", function(d) { return radius(d); })
svg.selectAll(".axis")
.data(d3.range(num_axes))
.enter().append("g")
.attr("class", "axis")
.attr("transform", function(d) { return "rotate(" + -angle(d) + ")"; })
.call(radial_tick)
.append("text")
.attr("y", radius(end)+13)
.text(function(d) { return angle(d) + "°"; })
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "rotate(" + -90 + ")" })
svg.selectAll(".spiral")
.data([pieces])
.enter().append("path")
.attr("class", "spiral")
.attr("d", spiral)
.attr("transform", function(d) { return "rotate(" + 90 + ")" });
function radial_tick(selection) {
selection.each(function(axis_num) {
d3.svg.axis()
.scale(radius)
.ticks(5)
.tickValues( axis_num == tick_axis ? null : [])
.orient("bottom")(d3.select(this))
d3.select(this)
.selectAll("text")
.attr("text-anchor", "bottom")
.attr("transform", "rotate(" + angle(axis_num) + ")")
});
}
please see the second solution for my implementation. Help me with connecting the circle with the center
Here is a model for the technique you seem to be looking for...
var width = 400,
height = 430,
num_axes = 8,
tick_axis = 1,
start = 0,
end = 4,
testValue = 2;
var theta = function (r) {
return -2 * Math.PI * r;
};
var arc = d3.svg.arc()
.startAngle(0)
.endAngle(2 * Math.PI);
var radius = d3.scale.linear()
.domain([start, end])
.range([0, (d3.min([width, height]) / 2 - 20)]);
var angle = d3.scale.linear()
.domain([0, num_axes])
.range([0, 360]);
var chart = d3.select("#chart")
.style("width", width + "px");
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 8) + ")");
var pieces = d3.range(start, end + 0.001, (end - start) / 500);
var spiral = d3.svg.line.radial()
.interpolate("linear")
.angle(theta)
.radius(radius);
svg.append("text")
.text("Title")
.attr("class", "title")
.attr("x", 0)
.attr("y", -height/2+16)
.attr("text-anchor", "middle")
svg.selectAll("circle.tick")
.data(d3.range(end,start,(start-end)/4))
.enter().append("circle")
.attr("class", "tick")
.style({fill: "black", opacity: 0.1})
.attr("cx", 0)
.attr("cy", 0)
.attr("r", function(d) { return radius(d); })
svg.selectAll(".axis")
.data(d3.range(num_axes))
.enter().append("g")
.attr("class", "axis")
.attr("transform", function (d) { return "rotate(" + -angle(d) + ")"; })
.call(radial_tick)
.append("text")
.attr("y", radius(end) + 13)
.text(function (d) { return angle(d) + "°"; })
.attr("text-anchor", "middle")
.attr("transform", function (d) { return "rotate(" + -90 + ")" })
svg.selectAll(".axis path")
.style({fill: "none", stroke: "black"})
.attr("stroke-dasharray", "5 5")
svg.selectAll(".spiral")
.data([pieces])
.enter().append("path")
.attr("class", "spiral")
.attr("fill", "none")
.attr("stroke", "black")
.attr("d", spiral)
.attr("transform", function (d) { return "rotate(" + 90 + ")" });
function radial_tick(selection) {
selection.each(function (axis_num) {
d3.svg.axis()
.scale(radius)
.ticks(5)
.tickValues(axis_num == tick_axis ? null : [])
.tickSize(1)
.orient("bottom")(d3.select(this))
d3.select(this)
.selectAll("text")
.attr("text-anchor", "bottom")
.attr("transform", "rotate(" + angle(axis_num) + ")")
});
}
function radialScale(x) {
var t = theta(x), r = radius(x);
d3.select(this)
.attr("cx", r * Math.cos(t))
.attr("cy", r * Math.sin(t))
}
slider = SliderControl("#circleSlider", "data", update, [start, end], ",.3f");
function update(x) {
if (typeof x != "undefined") testValue = x;
var circles = svg.selectAll(".dataPoints")
.data([testValue]);
circles.enter().append("circle");
circles.attr("class", "dataPoints")
.style({ fill: "black", opacity: 0.6 })
.attr("r", 10)
.each(radialScale)
circles.exit().remove();
return testValue
}
function SliderControl(selector, title, value, domain, format) {
var accessor = d3.functor(value), rangeMax = 1000,
_scale = d3.scale.linear().domain(domain).range([0, rangeMax]),
_$outputDiv = $("<div />", { class: "slider-value" }),
_update = function (value) {
_$outputDiv.css("left", 'calc( '
+ (_$slider.position().left + _$slider.outerWidth()) + 'px + 1em )')
_$outputDiv.text(d3.format(format)(value));
$(".input").width(_$outputDiv.position().left + _$outputDiv.outerWidth() - _innerLeft)
},
_$slider = $(selector).slider({
value: _scale(accessor()),
max: rangeMax,
slide: function (e, ui) {
_update(_scale.invert(ui.value));
accessor(_scale.invert(ui.value));
}
}),
_$wrapper = _$slider.wrap("<div class='input'></div>")
.before($("<div />").text(title + ":"))
.after(_$outputDiv).parent(),
_innerLeft = _$wrapper.children().first().position().left;
_update(_scale.invert($(selector).slider("value")))
return d3.select(selector)
};
.domain {
stroke-width: 1px;
}
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart">
<div id="circleSlider"></div>
</div>
I am have created chart using d3.js, when I zoom in or zoom out on web browser this charts do not re-size according to window.
Following is what I have done:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style type="text/css">
svg {
font-family: "Helvetica Neue", Helvetica;
}
.line {
fill: none;
stroke: #000;
stroke-width: 2px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var m = [20, 20, 30, 20],
w = 960 - m[1] - m[3],
h = 500 - m[0] - m[2];
var x,
y,
duration = 1500,
delay = 500;
var color = d3.scale.category10();
var svg = d3.select("body").append("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var stocks,
symbols;
// A line generator, for the dark stroke.
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
// A line generator, for the dark stroke.
var axis = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(h);
// A area generator, for the dark stroke.
var area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y1(function(d) { return y(d.price); });
d3.csv("stocks.csv", function(data) {
var parse = d3.time.format("%b %Y").parse;
// Nest stock values by symbol.
symbols = d3.nest()
.key(function(d) { return d.symbol; })
.entries(stocks = data);
// Parse dates and numbers. We assume values are sorted by date.
// Also compute the maximum price per symbol, needed for the y-domain.
symbols.forEach(function(s) {
s.values.forEach(function(d) { d.date = parse(d.date); d.price = +d.price; });
s.maxPrice = d3.max(s.values, function(d) { return d.price; });
s.sumPrice = d3.sum(s.values, function(d) { return d.price; });
});
// Sort by maximum price, descending.
symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; });
var g = svg.selectAll("g")
.data(symbols)
.enter().append("g")
.attr("class", "symbol");
setTimeout(lines, duration);
});
function lines() {
x = d3.time.scale().range([0, w - 60]);
y = d3.scale.linear().range([h / 4 - 20, 0]);
// Compute the minimum and maximum date across symbols.
x.domain([
d3.min(symbols, function(d) { return d.values[0].date; }),
d3.max(symbols, function(d) { return d.values[d.values.length - 1].date; })
]);
var g = svg.selectAll(".symbol")
.attr("transform", function(d, i) { return "translate(0," + (i * h / 4 + 10) + ")"; });
g.each(function(d) {
var e = d3.select(this);
e.append("path")
.attr("class", "line");
e.append("circle")
.attr("r", 5)
.style("fill", function(d) { return color(d.key); })
.style("stroke", "#000")
.style("stroke-width", "2px");
e.append("text")
.attr("x", 12)
.attr("dy", ".31em")
.text(d.key);
});
function draw(k) {
g.each(function(d) {
var e = d3.select(this);
y.domain([0, d.maxPrice]);
e.select("path")
.attr("d", function(d) { return line(d.values.slice(0, k + 1)); });
e.selectAll("circle, text")
.data(function(d) { return [d.values[k], d.values[k]]; })
.attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; });
});
}
var k = 1, n = symbols[0].values.length;
d3.timer(function() {
draw(k);
if ((k += 2) >= n - 1) {
draw(n - 1);
setTimeout(horizons, 500);
return true;
}
});
}
function horizons() {
svg.insert("defs", ".symbol")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", h / 4 - 20);
var color = d3.scale.ordinal()
.range(["#c6dbef", "#9ecae1", "#6baed6"]);
var g = svg.selectAll(".symbol")
.attr("clip-path", "url(#clip)");
area
.y0(h / 4 - 20);
g.select("circle").transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (-h / 4) + ")"; })
.remove();
g.select("text").transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (h / 4 - 20) + ")"; })
.attr("dy", "0em");
g.each(function(d) {
y.domain([0, d.maxPrice]);
d3.select(this).selectAll(".area")
.data(d3.range(3))
.enter().insert("path", ".line")
.attr("class", "area")
.attr("transform", function(d) { return "translate(0," + (d * (h / 4 - 20)) + ")"; })
.attr("d", area(d.values))
.style("fill", function(d, i) { return color(i); })
.style("fill-opacity", 1e-6);
y.domain([0, d.maxPrice / 3]);
d3.select(this).selectAll(".line").transition()
.duration(duration)
.attr("d", line(d.values))
.style("stroke-opacity", 1e-6);
d3.select(this).selectAll(".area").transition()
.duration(duration)
.style("fill-opacity", 1)
.attr("d", area(d.values))
.each("end", function() { d3.select(this).style("fill-opacity", null); });
});
setTimeout(areas, duration + delay);
}
function areas() {
var g = svg.selectAll(".symbol");
axis
.y(h / 4 - 21);
g.select(".line")
.attr("d", function(d) { return axis(d.values); });
g.each(function(d) {
y.domain([0, d.maxPrice]);
d3.select(this).select(".line").transition()
.duration(duration)
.style("stroke-opacity", 1)
.each("end", function() { d3.select(this).style("stroke-opacity", null); });
d3.select(this).selectAll(".area")
.filter(function(d, i) { return i; })
.transition()
.duration(duration)
.style("fill-opacity", 1e-6)
.attr("d", area(d.values))
.remove();
d3.select(this).selectAll(".area")
.filter(function(d, i) { return !i; })
.transition()
.duration(duration)
.style("fill", color(d.key))
.attr("d", area(d.values));
});
svg.select("defs").transition()
.duration(duration)
.remove();
g.transition()
.duration(duration)
.each("end", function() { d3.select(this).attr("clip-path", null); });
setTimeout(stackedArea, duration + delay);
}
function stackedArea() {
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse");
stack(symbols);
y
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
.range([h, 0]);
line
.y(function(d) { return y(d.price0); });
area
.y0(function(d) { return y(d.price0); })
.y1(function(d) { return y(d.price0 + d.price); });
var t = svg.selectAll(".symbol").transition()
.duration(duration)
.attr("transform", "translate(0,0)")
.each("end", function() { d3.select(this).attr("transform", null); });
t.select("path.area")
.attr("d", function(d) { return area(d.values); });
t.select("path.line")
.style("stroke-opacity", function(d, i) { return i < 3 ? 1e-6 : 1; })
.attr("d", function(d) { return line(d.values); });
t.select("text")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
setTimeout(streamgraph, duration + delay);
}
function streamgraph() {
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse")
.offset("wiggle");
stack(symbols);
line
.y(function(d) { return y(d.price0); });
var t = svg.selectAll(".symbol").transition()
.duration(duration);
t.select("path.area")
.attr("d", function(d) { return area(d.values); });
t.select("path.line")
.style("stroke-opacity", 1e-6)
.attr("d", function(d) { return line(d.values); });
t.select("text")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
setTimeout(overlappingArea, duration + delay);
}
function overlappingArea() {
var g = svg.selectAll(".symbol");
line
.y(function(d) { return y(d.price0 + d.price); });
g.select(".line")
.attr("d", function(d) { return line(d.values); });
y
.domain([0, d3.max(symbols.map(function(d) { return d.maxPrice; }))])
.range([h, 0]);
area
.y0(h)
.y1(function(d) { return y(d.price); });
line
.y(function(d) { return y(d.price); });
var t = g.transition()
.duration(duration);
t.select(".line")
.style("stroke-opacity", 1)
.attr("d", function(d) { return line(d.values); });
t.select(".area")
.style("fill-opacity", .5)
.attr("d", function(d) { return area(d.values); });
t.select("text")
.attr("dy", ".31em")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price) + ")"; });
svg.append("line")
.attr("class", "line")
.attr("x1", 0)
.attr("x2", w - 60)
.attr("y1", h)
.attr("y2", h)
.style("stroke-opacity", 1e-6)
.transition()
.duration(duration)
.style("stroke-opacity", 1);
setTimeout(groupedBar, duration + delay);
}
function groupedBar() {
x = d3.scale.ordinal()
.domain(symbols[0].values.map(function(d) { return d.date; }))
.rangeBands([0, w - 60], .1);
var x1 = d3.scale.ordinal()
.domain(symbols.map(function(d) { return d.key; }))
.rangeBands([0, x.rangeBand()]);
var g = svg.selectAll(".symbol");
var t = g.transition()
.duration(duration);
t.select(".line")
.style("stroke-opacity", 1e-6)
.remove();
t.select(".area")
.style("fill-opacity", 1e-6)
.remove();
g.each(function(p, j) {
d3.select(this).selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("x", function(d) { return x(d.date) + x1(p.key); })
.attr("y", function(d) { return y(d.price); })
.attr("width", x1.rangeBand())
.attr("height", function(d) { return h - y(d.price); })
.style("fill", color(p.key))
.style("fill-opacity", 1e-6)
.transition()
.duration(duration)
.style("fill-opacity", 1);
});
setTimeout(stackedBar, duration + delay);
}
function stackedBar() {
x.rangeRoundBands([0, w - 60], .1);
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse");
var g = svg.selectAll(".symbol");
stack(symbols);
y
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
.range([h, 0]);
var t = g.transition()
.duration(duration / 2);
t.select("text")
.delay(symbols[0].values.length * 10)
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
t.selectAll("rect")
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d.price0 + d.price); })
.attr("height", function(d) { return h - y(d.price); })
.each("end", function() {
d3.select(this)
.style("stroke", "#fff")
.style("stroke-opacity", 1e-6)
.transition()
.duration(duration / 2)
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.style("stroke-opacity", 1);
});
setTimeout(transposeBar, duration + symbols[0].values.length * 10 + delay);
}
function transposeBar() {
x
.domain(symbols.map(function(d) { return d.key; }))
.rangeRoundBands([0, w], .2);
y
.domain([0, d3.max(symbols.map(function(d) { return d3.sum(d.values.map(function(d) { return d.price; })); }))]);
var stack = d3.layout.stack()
.x(function(d, i) { return i; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; });
stack(d3.zip.apply(null, symbols.map(function(d) { return d.values; }))); // transpose!
var g = svg.selectAll(".symbol");
var t = g.transition()
.duration(duration / 2);
t.selectAll("rect")
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d.price0 + d.price) - 1; })
.attr("height", function(d) { return h - y(d.price) + 1; })
.attr("x", function(d) { return x(d.symbol); })
.attr("width", x.rangeBand())
.style("stroke-opacity", 1e-6);
t.select("text")
.attr("x", 0)
.attr("transform", function(d) { return "translate(" + (x(d.key) + x.rangeBand() / 2) + "," + h + ")"; })
.attr("dy", "1.31em")
.each("end", function() { d3.select(this).attr("x", null).attr("text-anchor", "middle"); });
svg.select("line").transition()
.duration(duration)
.attr("x2", w);
setTimeout(donut, duration / 2 + symbols[0].values.length * 10 + delay);
}
function donut() {
var g = svg.selectAll(".symbol");
g.selectAll("rect").remove();
var pie = d3.layout.pie()
.value(function(d) { return d.sumPrice; });
var arc = d3.svg.arc();
g.append("path")
.style("fill", function(d) { return color(d.key); })
.data(function() { return pie(symbols); })
.transition()
.duration(duration)
.tween("arc", arcTween);
g.select("text").transition()
.duration(duration)
.attr("dy", ".31em");
svg.select("line").transition()
.duration(duration)
.attr("y1", 2 * h)
.attr("y2", 2 * h)
.remove();
function arcTween(d) {
var path = d3.select(this),
text = d3.select(this.parentNode.appendChild(this.previousSibling)),
x0 = x(d.data.key),
y0 = h - y(d.data.sumPrice);
return function(t) {
var r = h / 2 / Math.min(1, t + 1e-3),
a = Math.cos(t * Math.PI / 2),
xx = (-r + (a) * (x0 + x.rangeBand()) + (1 - a) * (w + h) / 2),
yy = ((a) * h + (1 - a) * h / 2),
f = {
innerRadius: r - x.rangeBand() / (2 - a),
outerRadius: r,
startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
};
path.attr("transform", "translate(" + xx + "," + yy + ")");
path.attr("d", arc(f));
text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
};
}
setTimeout(donutExplode, duration + delay);
}
function donutExplode() {
var r0a = h / 2 - x.rangeBand() / 2,
r1a = h / 2,
r0b = 2 * h - x.rangeBand() / 2,
r1b = 2 * h,
arc = d3.svg.arc();
svg.selectAll(".symbol path")
.each(transitionExplode);
function transitionExplode(d, i) {
d.innerRadius = r0a;
d.outerRadius = r1a;
d3.select(this).transition()
.duration(duration / 2)
.tween("arc", tweenArc({
innerRadius: r0b,
outerRadius: r1b
}));
}
function tweenArc(b) {
return function(a) {
var path = d3.select(this),
text = d3.select(this.nextSibling),
i = d3.interpolate(a, b);
for (var key in b) a[key] = b[key]; // update data
return function(t) {
var a = i(t);
path.attr("d", arc(a));
text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
};
}
}
setTimeout(function() {
svg.selectAll("*").remove();
svg.selectAll("g").data(symbols).enter().append("g").attr("class", "symbol");
lines();
}, duration);
}
</script>
</body>
</html>
I am learning d3.js, so I don't know how to do it. Please help me.
Doing this ends up being a bit code heavy, but for my graphs I tend to have 3 different parts: setup, draw and redraw. In setup I set up all the SVG containers and bind the data. In draw, I do the initial data draw (this tends to have different animations, fade-ins, etc). Then I bind window.onresize to the redraw all of the SVG data based on window/container dimensions.
I can provide you with an example of my code if you would like.
Can anybody help me convert the d3.js Calendar View implementation which looks like the one depicted here (weeks as columns): D3 Calendar View using Associative Array
to something more like this (weeks as rows): http://kamisama.github.io/cal-heatmap/v2/ (See Months > days (horizontally) section)
I've had a go at playing around with the axes, but to no avail.
Any help would be greatly appreciated.
My current code looks like this:
raApp.directive('heatMapYear', function () {
var width = 1200,
height = 150,
cellSize = 17; // cell size
var day = d3.time.format("%w"),
week = d3.time.format("%U"),
month = d3.time.format("%m"),
monthName = d3.time.format("%b"),
format = d3.time.format("%Y-%m-%d");
var color = d3.scale.quantize()
.domain([1, 5])
.range(d3.range(5).map(function(d) { return "rank" + d; }));
return {
restrict: 'A'
, replace: false
, scope: {
chartData: '='
, dateField: '='
}
, link: function (scope, element, attrs) {
scope.$watch('chartData', function(newData, oldData) {
d3.select(element[0]).selectAll('*').remove();
if (newData != undefined) {
var svg = d3.select(element[0]).selectAll("svg")
.data(function() {
var years = [];
for (var i = 0; i < newData.length; i++) {
var date = newData[i][scope.dateField];
var year = parseInt(date.substring(0, 4));
if (years.indexOf(year) == -1) {
years.push(year);
}
}
return years;
})
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "heatClass")
.append("g")
.attr("transform", "translate(" + 50 + "," + (height - cellSize * 7 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-30," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(function(d) { return d; });
svg.selectAll(".monthName")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.attr("x", function(d) {return (week(d) * cellSize + 50); })
.attr("y", -5)
.style("text-anchor", "middle")
.text(function(d) { return monthName(d); });
svg.selectAll(".dayName")
.data(function(d) { return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"] })
.enter().append("text")
.attr("x", -10)
.attr("y", function(d, i) {return (i * cellSize) + 12; })
.style("text-anchor", "middle")
.text(function(d) { return d; });
var svg1 = d3.select(element[0]).select("svg")
var legend = svg1.selectAll(".legend")
.data([0])
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(130," + (i * (cellSize) + 30) + ")";
});
legend.append("svg:image")
.attr("xlink:href", "img/RA-scale-small.png")
.attr("x", width - 350)
.attr("y", 0)
.attr("width",200)
.attr("height", 47);
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) { return week(d) * cellSize; })
.attr("y", function(d) { return day(d) * cellSize; })
.datum(format);
rect.append("title")
.text(function(d) { return d; });
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("d", monthPath);
var data = d3.nest()
.key(function(d) { return d[scope.dateField]; })
.rollup(function(d) {return {rank:d[0]["rank"],revenue:d[0]["abbrRevenue"],volume:d[0]["abbrVolume"]}})
.map(newData);
rect.filter(function(d) { return d in data; })
.attr("class", function(d) {return "day " + color(data[d].rank); })
.select("title")
.text(function(d) { return d + "\nRevenue: " + data[d].revenue + "\nVolume: " + data[d].volume });
}
});
function monthPath(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = +day(t0), w0 = +week(t0),
d1 = +day(t1), w1 = +week(t1);
return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize
+ "H" + w0 * cellSize + "V" + 7 * cellSize
+ "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize
+ "H" + (w1 + 1) * cellSize + "V" + 0
+ "H" + (w0 + 1) * cellSize + "Z";
}
}
}
});
After much digging around and trial and error, I figured out a solution to this. Therefore I wanted to share the code in case it helps anyone else out there looking to achieve similar results.
The code is as follows:
raApp.directive('heatMapYearWeekRows', function () {
var width = 1490,
height = 200,
cellSize = 17; // cell size
var day = d3.time.format("%w"),
week = d3.time.format("%U"),
month = d3.time.format("%m"),
monthName = d3.time.format("%b"),
format = d3.time.format("%Y-%m-%d"),
displayFormat = d3.time.format("%a, %d %b %Y");
var color = d3.scale.quantize()
.domain([1, 5])
.range(d3.range(5).map(function(d) { return "rank" + d; }));
return {
restrict: 'A'
, replace: false
, scope: {
chartData: '='
, dateField: '='
}
, link: function (scope, element, attrs) {
scope.$watch('chartData', function(newData, oldData) {
d3.select(element[0]).selectAll('*').remove();
if (newData != undefined) {
var svg = d3.select(element[0]).selectAll("svg")
.data(function() {
var years = [];
for (var i = 0; i < newData.length; i++) {
var date = newData[i][scope.dateField];
var year = parseInt(date.substring(0, 4));
if (years.indexOf(year) == -1) {
years.push(year);
}
}
return years;
})
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "heatClass")
.append("g")
.attr("transform", "translate(" + 50 + "," + (height - cellSize * 7 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-30," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(function(d) { return d; });
svg.selectAll(".monthName")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.attr("x", function(d) {
return ((month(d) - 1) * (7 * cellSize) + 50);
})
.attr("y", 115)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(function(d) { return monthName(d); });
var svg1 = d3.select(element[0]).select("svg")
var legend = svg1.selectAll(".legend")
.data([0])
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(130," + (i * (cellSize) + 30) + ")";
});
legend.append("svg:image")
.attr("xlink:href", "img/RA-scale-small.png")
.attr("x", -80)
.attr("y", -30)
.attr("width",200)
.attr("height", 47);
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) {
var prevDay = new Date(d -1);
var monthOffset = (month(d) - 1) * (7 * cellSize);
var result = (day(d) * cellSize) + +monthOffset;
return result; })
.attr("y", function(d) {
var result = ((getMonthWeek(d) - 1) * cellSize);
return result; })
.datum(format);
rect.append("title")
.text(function(d) {
return d;
});
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("d", monthPath);
var data = d3.nest()
.key(function(d) { return d[scope.dateField]; })
.rollup(function(d) {return {rank:d[0]["rank"],revenue:d[0]["abbrRevenue"],volume:d[0]["abbrVolume"]}})
.map(newData);
rect.filter(function(d) { return d in data; })
.attr("class", function(d) {return "day " + color(data[d].rank); })
.select("title")
.text(function(d) { return displayFormat(new Date(d)) + "\nRevenue: " + data[d].revenue + "\nVolume: " + data[d].volume });
}
});
function getMonthWeek(date){
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
return Math.ceil((date.getDate() + firstDay)/7);
}
function monthPath(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = +day(t0), w0 = +getMonthWeek(t0) -1, m0 = +month(t0),
d1 = +day(t1), w1 = +getMonthWeek(t1) -1;
var monthOffsetX = (+m0 - 1) * (7 * cellSize);
return "M" + ((d0 * cellSize) + +monthOffsetX) + "," + ((w0 + 1) * cellSize)
+ "V" + w0 * cellSize + "H" + ((7 * cellSize) + +monthOffsetX)
+ "V" + w1 * cellSize + "H" + (((d1 + 1) * cellSize) + +monthOffsetX)
+ "V" + ((w1 + 1) * cellSize) + "H" + +monthOffsetX
+ "V" + ((w0 + 1) * cellSize) + "Z";
}
}
}
});
Hope that helps.