How to dynamically set dates from data in d3 calendar view? - d3.js

In the d3 calendar view example, I am trying to modify it to automatically determine the range of years to display from the data given it.
Is it possible to have d3 automatically figure out what arguments to pass to d3.range() to automatically determine the start and end year, rather than have hard-coded literals?
In the .data() line below, I've tried using d3.min() and d3.max() as arguments to d3.range(), but that's not correct. I've tried sorting the nested data beforehand to obtain the first and last entry in the array, but that has not worked. Suggestions?
return d3.select( "body" )
.selectAll( "svg" )
.data(d3.range(1990, 2010))
.enter()
.append( "svg" )
.attr( "width", width )
.attr( "height", height )
.attr( "class", "year" )
.append( "g" )
.attr( "transform", "translate(" + getOffsetX() + "," + getOffsetY() + ")" );

Put everything that is done before the d3.csv("dji.csv", inside the callback and after the d3.nest(), modify the following line
var range = d3.extent(csv, d => Number(d.Date.substring(0,4)));
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(range[0], range[1]))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");

Related

d3 Tree - How to auto adjust node spacing when zooming

I have a d3 tree with zoom and pan functionality. The tree can have a great number of child nodes for any parent. This can result in vertically squashed up nodes.
I would like the nodes to automatically adjust their spacing when zooming out, especially the vertical spacing.
The appending d3 svg and the zoom part of the d3 code:
var svg = d3.select("#tree_container")
.append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.call( d3.behavior.zoom().on( "zoom", function () {
svg.attr( "transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")" )
} ) )
.append("g");
Fiddle
Would it be enough to set the node sizes? Then d3 will automatically adjust positions of the nodes.
var radius = 10;
var tree = d3.layout.tree()
.size([height, width])
.nodeSize([radius*2+3]);
...
function update(source) {
...
nodeUpdate.select("circle")
.attr("r", radius)
As Fiddle

D3 - Position second x axis labels

I have a stackblitz here - https://stackblitz.com/edit/d3-stacked-trend-bar-positioned-months-1b93nz?file=src%2Fapp%2Fbar-chart.ts
I have a stacked bar chart using D3 in Angular.
I'm trying to position a second axis of labels on the x axis.
Currently I'm using the with of the graph but this means the labels dont line up correctly with the bars.
Is there a better D3 way to add these labels and positino them.
Use the x-position of the bars and position the text in the middle of it.
private drawBarTitle(data:any){
this.chart.append('g')
.attr("transform", "translate(" + 10 + "," + (this.height+10) + ")")
.selectAll('g')
.data(data)
.enter()
.append('g')
.attr('transform', (d:any, i:any)=>{
var x = this.x(d.date) + (i%2) * 0.525 * this.x.bandwidth();
return "translate(" + (x + this.x.bandwidth()*0.95*0.25) + "," + 0 + ")"
})
.append('text')
.text((d:any, i:any)=>{ return d.type; })
.attr("dy", "-0.3em")
.classed('trend-type', true)
.style("text-anchor", "end")
.attr("transform", "rotate(-90)");
}

d3 text only appears when added to a group. Why?

I have appended some text to a map I am working on in d3, here is my code:
countriesGroup = svg
.append("g")
.attr("id", "map");
//add background
countriesGroup.append('rect')
.attr("x", 0)
.attr("y", 0)
.attr("width", w)
.attr("height", h);
//Draw countries
countries = countriesGroup.selectAll("path")
.data(j.features)
.enter()
...Draw country borders
//Create Timer Text
countriesGroup.append("text") <-----This worked
.attr("transform", "translate(" + w/2 + "," + h/2 + ")")
.style("fill", "#ff0000")
.text("This is a test");
//Create Timer Text
svg.append("text") <-----This didn't
.attr("transform", "translate(" + w/2 + "," + h/2 + ")")
.style("fill", "#ff0000")
.text("This is a test");
I initially tried appending the Timer text directly to svg but that did not work. When I later tried appending it directly to the countriesGroup group, this worked. How come the text was only able to render when appended to the group, but not when appended directly to the svg?

Passing parameter with OnClick to Filemaker Using D3

I am trying to pass a parameter when I click on a pie slice, that was created using the D3 library, with the following code to a Filemaker database script. The dataset is in an Array of Objects format.
var dataset = [{key: 1, amt: 5}, {key: 2, amt: 10}, {key: 3, amt: 20}];
I can can put a constant in place of d.amt and pass the constant to Filemaker.
I initially was drawing the pie chart using an array format and the onclick worked fine using, d.value.
Is d.amt the correct syntax to use to pass the parameter for the Array of Objects data format?
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
.attr("onclick", function(d, i){
return "location.href='" + script + "&param=" + d.amt + "'";
});
Adding the .on("click", function(d, i) {.. the pie chart did not plot. For the location.href = you have "script&param=" + d.amt; I need it to be '" + script + "&param=" + d.amt + "'"; in case it makes a difference.
This is what I have;
...
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
.on("click", function(d, i) {
location.href ="script&param=" + d.amt;
};
d3's on function serves the purpose better:
svg.selectAll("g.arc)
...
.on("click", function(d, i) {
location.href = script + "&param=" + d.amt;
});
attr sets the target statically, while creating the elements. on determines the target dynamically, when the click occurs.
Apart from that, d.amt is correct, and I'd also expect your attr variant to work.

Removing single elements of svg in d3.js

I have the following code in d3.js
var svg = d3.select(".Canvas").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);
svg.append("g").attr("class", "y axis").call(yAxisMajor).append("text")
.attr("transform", "rotate(-90)").attr("y", 6).attr("dy",
".71em").style("text-anchor", "end");
I tried the following to remove only the y-axis, not the whole svg:
d3.select(".Canvas").selectAll("svg").selectAll("g").select(".y axis").remove();
Why is the code not working?
Here is a little demo with a couple of simple ways to do it (see my comments in the fiddle).
d3.select("svg > g > #the_one_circle")
.transition().duration(1000)
.attr("r",1)
.remove();
Note how the svg and g elements are still there after removing the circle.
Because when you set class attribute as y axis , you actually set two classes. So in order to select and match both class names you need to call select with .y.axis. So that the result should be:
d3.select(".canvas").selectAll("svg").selectAll("g").select(".y.axis").remove();
at least worked for me, demo.

Resources