d3Js - how to arrange my values as around the 360d and automate data in a circle? - d3.js

I have a data like this:
var requiredDegrees = [0,30,60,90,120,150,180,210,240,270,300,330,360];
I would like to arrange this data in a cirlce around. how to calculate and palace the degrees across my circle.
And I would like to create the same as like this http://windhistory.com/station.html?KCFE by 3d.js any one suggest me the correct way here please?

Simplest example I can code up:
var requiredDegrees = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330, 360];
var diameter = 300;
var svg = d3.select("body").append("svg")
.attr("width", diameter + 50)
.attr("height", diameter + 50)
.append("g")
.attr("transform", "translate(25,25)");
svg.append("circle")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")")
.attr("r", diameter / 2)
svg.selectAll('text')
.data(requiredDegrees)
.enter()
.append('text')
.text(function(d) {
return d;
})
.attr('transform', function(d) {
return "translate(" + diameter / 2 + "," + 0 + ") rotate(" + d + ",0," + diameter / 2 + ")";
});
Demonstration here.

Related

D3 Pie Chart rotate only the arcs

My chart needs a label in the center of the donut that should not rotate when clicked.
https://codepen.io/scratchy303/pen/dyXMzrz
Can I append the label in a sibling "g"roup and rotate the arcs group?
Can I translate just the arcs rather than rotating the entire SVG?
What's the simplest solution?
var svg = d3.select("#pieChart").append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox', '0 0 ' + Math.min(width, height) + ' ' + Math.min(width, height))
.attr('preserveAspectRatio', 'xMinYMin')
.append("g")
.attr("transform", "translate(" + radius + "," + height / 2 + ")")
.style("filter", "url(#drop-shadow)");
svg.append("g")
.append("text")
.attr("text-anchor", "middle")
.text("Donut Name");
I found a solution by counter-rotating my text. My biggest hurdle was simply traversing my SVG in D3.
//start by selecting the parent "g"roup and then you can select the text
d3.select(i.parentNode).select(".donut-label")
.transition()
.duration(1000)
.attr("transform", "rotate(" + (-angle) + ")");

How to draw vertical text as labels in D3

I'm trying to draw vertical labels for the heatmap that I'm working. I'm using the example from http://bl.ocks.org/tjdecke/5558084. Here is the part of the code that I've changed:
var timeLabels = svg.selectAll(".timeLabel")
.data(ife_nr)
.enter().append("text")
.text(function(d) {
return d;
})
.attr("x", function(d, i) {
return (i * gridSize);
})
.attr("y", 0)
//.style("text-anchor", "middle")
//.attr("transform", "translate(" + gridSize / 2 + '-5' + ")")
.attr("transform", "translate(" + gridSize/2 + '-8' + "), rotate(-90)")
.attr("class", function(d, i) {
return ((i >= 0) ? "timeLabel mono axis axis-worktime" : "timeLabel mono axis");
});
But it appears the labels seems to be stacked on top one another on top of the first grid. How can I edit this code to get the labels correctly displayed?
Two problems: first, the translate should have a comma separating the values:
"translate(" + gridSize/2 + ",-8), rotate(-90)")
Assuming that -8 is the y value for the translate. If you don't have a comma, the value inside the parenthesis should be just the x translation (If y is not provided, it is assumed to be zero). But even if there is actually no comma and all that gridSize/2 + '-8' is just the x value you still have a problem, because number plus string is a string. You'll have to clarify this point.
Besides that, for rotating the texts over their centres, you'll have to set the cx and cy of the rotate. Have a look at this demo:
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 100);
var texts = svg.selectAll(".texts")
.data(["foo", "bar", "baz"])
.enter()
.append("text");
texts.attr("y", 50)
.attr("x", function(d,i){ return 50 + 80*i})
.text(function(d){ return d});
texts.attr("transform", function(d,i){
return "rotate(-90 " + (50 + 80*i) + " 50)";
});
<script src="https://d3js.org/d3.v4.js"></script>

How can I split an ordinal axis in d3?

The following is my draw axis code:
var seasons = ["summer", "winter", "fall", "spring"];
var margin = {top:80, right:30, bottom:30, left:30},
width = 1200 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(seasons)
.rangeRoundBands([0, width], 0.9);
xAxis = d3.svg.axis()
.scale(x)
.tickSize(4, 6)
.tickPadding(6)
.orient("bottom");
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 + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
</script>
However, the tickPadding function does now introduce a space between the ordinal axis categories.
More specifically, I want that each of the summer, winter, fall and spring parts of the axis are separate from each other, sort of like dashed line. How can I get this?
I don't know of any way built into the d3 axis to accomplish this, but you can remove the path it draws and replace it with a dashed line, like so:
// Draw the axis, as you currently are
var axisElem = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Remove the line
axisElem.selectAll("path.domain").remove();
// Figure out how big each dash should be
var gapFraction = 0.1; // The portion of the line that should be a gap
var total = x(seasons[1]) - x(seasons[0]);
var dash = total * (1 - gapFraction);
var gap = total * gapFraction;
// Draw the dashed line
axisElem.append("line")
.classed("domain", true)
.attr("x1", x(seasons[0]) - dash / 2 + gap / 2)
.attr("x2", x(seasons[seasons.length - 1]) + dash / 2 - gap / 2)
.attr("y1", 0)
.attr("y2", 0)
.attr("stroke", "black")
.attr("stroke-dasharray", dash + "," + gap);

D3.js - why is this histogram generating a negative width and throwing an error?

I'm trying to start from Mike Bostock's histogram example:
http://bl.ocks.org/mbostock/3048450
Initially I'm just trying to change the data and domain to get an understanding of how it works and get closer to what I need. But in doing that, my script throws an error due to negative widths on the rects.
What is this line doing exactly and why does it generate a negative value?
.attr("width", x(data[0].dx) - 1)
My fiddle is here: http://jsfiddle.net/rolfsf/p96dH/1/
and my script currently is this:
//generate some data with a median of 75
var values = d3.range(1000).map(d3.random.logNormal(Math.log(75), 0.4));
// A formatter for counts.
var formatCount = d3.format(",.0f");
var margin = {top: 10, right: 30, bottom: 30, left: 30},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([60, 95])
.range([0, width]);
// Generate a histogram using twenty uniformly-spaced bins.
var data = d3.layout.histogram()
.bins(x.ticks(7))
(values);
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.y; })])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
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 + ")");
var bar = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });
bar.append("rect")
.attr("x", 1)
.attr("width", x(data[0].dx) - 1)
.attr("height", function(d) { return height - y(d.y); });
bar.append("text")
.attr("dy", ".75em")
.attr("y", 6)
.attr("x", x(data[0].dx) / 2)
.attr("text-anchor", "middle")
.text(function(d) { return formatCount(d.y); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
UPDATE: The answer in this question: D3 Histogram with negative values actually gives me the chart layout I wanted, though Lars is correct that my domain function is causing problems.
an updated fiddle is here (note that due to the domain issue, the first and last bars have incorrect heights) http://jsfiddle.net/rolfsf/p96dH/3/
I replaced my width function with the barWidth variable:
var numbins = data.length;
var barWidth = width/numbins - 1;
It's simply the way you've set up your x scale. You're assuming that all values are going to be in the interval (60,95), which they are not. For values smaller than 60, you get negative numbers.
You can fix this easily by getting the actual extent of the data for the domain:
var x = d3.scale.linear()
.domain(d3.extent(data))
.range([0, width]);
You're right, it is due to the domain; the reason it works in Mike's example is that the domain minimum he uses is 0.
A better approach would be to do the following, replace every occurrence of
x(data[0].dx) - 1
with
x(60 + data[0].dx) - 1
More, generally, you can define your x scale with:
var x = d3.scale.linear()
.domain(d3.extent(data))
.range([0, width]);
And then the above snippets (setting bar width), become:
x(d3.min(datasetBars) + data[0].dx) - 1)

Rotate D3 symbol

I'm rendering a d3 symbol that looks like this:
svg.append('path')
.attr("d", d3.svg.symbol().type("triangle-up").size(10))
.attr("transform", function(d) { return "translate(" + 100 + "," + 100 + ")"; })
.style("fill", "red")
I'd like to rotate this triangle so that the triangle points left <|. How can I rotate this symbol while keeping it at the same position in my viz? I've been trying to do the following, but the symbol moves to the upper left corner of my viz (it doesn't stay in the position created by the transformation):
svg.append('path')
.attr("d", d3.svg.symbol().type("triangle-up").size(10))
.attr("transform", function(d) { return "translate(" + 100 + "," + 100 + ")"; })
.attr("transform", "rotate(-45)")
.style("fill", "red")
The problem is that the second call to set transform overrides the first value here:
.attr("transform", function(d) { return "translate(" + 100 + "," + 100 + ")"; })
.attr("transform", "rotate(-45)") // Only this value will remain as the value of the attr
To fix it, you should append the rotation to the original value of transform:
.attr("transform", function(d) { return "translate(" + 100 + "," + 100 + ") rotate(-45)"; })
Another solution is to put the symbol in nested g elements and apply individual transforms to each of them, example.

Resources