D3js - Add transparent gap between path in pie chart - javascript

I have a simple pie chart made with d3js and I would like to add transparent gap between each path.
paths = pieWrap.selectAll("path")
.data(pie(data)).enter()
.append("path")
.style("fill", "rgba(90, 168, 217, 1)")
.style("stroke", "#FFF")
.style("stroke-width", "1")
.style("stroke-opacity", "0")
.attr("d", arc);
Example here : http://jsfiddle.net/x4p0eLmL/2/
Just to know, in my case the background is an image so I can't use its color.
I tried stroke-opacity but it doesn't seem to work.
Is there a proper way to do that with d3js?
Thanks

I have had the same idea as #redress suggested: http://jsfiddle.net/x4p0eLmL/9/. The added part is as follows:
.attr("transform", function(path) {
middleAngle = -Math.PI/2 + (path.startAngle+path.endAngle)/2;
dx = 3 * Math.cos(middleAngle);
dy = 3 * Math.sin(middleAngle);
return "translate("+dx+", "+dy+")";
})
path has the attributes startAngle and endAngle. There is computed middle angle and translated. It is suitable for smaller gaps between the paths. Each path is translated to outer circle with radius+3 in the current example. There is the problem with "wider" gaps where the circle may be "distorted"

Related

d3 5+ - Appending circles about a semi-circle or arc

Suppose we wanted to make a list-like visual. Setting the y logic for the circles can be as simple as:
var data = [0,1,2,3,4,5,6,7,8,9];
var yScale = d3.scaleLinear()
.range([height,0])
.domain([0,9]);
svg.selectAll(null)
.data(data)
.enter()
.append('circle')
.attr('cy', function(d) { return yScale(d) })
.attr('cx', 100)
.attr('r', 10)
.style('fill', "#a6a6a6");
However, suppose we wanted to go for some style points and arrange the circles not in a blocky / tabular arrangement but rather arrange them about a circle or arc. I had this result in mind (only concerned with the outer circles):
While I think d3 does have trigonometric functions, I have never seen them used in pixel coordinates. I'd imagine the pseudo-code to be something like:
var semiCircleScale = d3.?????
.range([250 degrees, 110 degrees])
.domain([0,9]);
svg.selectAll(null)
.data(data)
.enter()
.append('circle')
.attr('cy', function(d) { return semiCircleScale(d) })
.attr('cx', 100)
.attr('r', 10)
.style('fill', "#a6a6a6");
Question
Is anyone familiar with using circle / arc scales for use with x,y logic for appending shapes? Or is there an easier/less-math-intensive way?
So the idea is to create 2 different path of arc and then calculate the circumference and place the circles along with.
d3.svg.arc()
.append("path")
.attr("d", arc1)
Here is a fiddle link with minimum code to establish the idea
https://jsfiddle.net/Dibyanshu/g03p6sxj/

Is there a way to not change the size of a line when zooming in D3?

I'm trying to remove the size update of my line when i zoom on my svg.
Basically my line is like that
points = [[this.x(first.longitude), this.y(0)], [this.x(first.longitude), this.y(first.altitude)]];
this.line[i] = this.chart
.append('path')
.attr('d', curveafter(points))
.attr('p', id.segmentName)
.attr('stroke', "black")
.attr('fill', 'none')
.on('click', this.filter)
.attr("stroke-width", 1)
and when i'm zooming, i'm updating the position of the line like that
updateChart(d) {
var newX = d.transform.rescaleX(this.x);
var newY = d.transform.rescaleY(this.y);
this.xAxis.call(d3.axisBottom(newX))
this.yAxis.call(d3.axisLeft(newY))
this.line.forEach((line) => {
line
.attr("transform", d.transform)
.attr("stroke-width", 1)
}
)
},
But when i'm zooming, the size of my line increases, and when I zoom out it decreases.
How do I block the stroke-width (size) and not move it no matter what I do?
You have 2 options:
Don't put your <line> under transformed <g>. When you handle a zoom event, recalculate the line endpoint coordinates and update the <line> attributes (x1,y1,x2,y2)
Set the line's stroke-width according to the zoom factor: strokeWidth = 1 / e.transform.k (I don't like this option but it can work)

D3 colour gradient not forming mathematical circle around centre of area

I am trying to do a radial area plot with a colour gradient to reflect this. However the gradient does not appear to ever want to sit perfectly in line / at the correct side with the circle (see image below).
I have tried constraining the width and hight of the svg so that they are equal, but with no avail.Every refresh (with random data), the central ring for the gradient will shift and warp into a different shape, but never lie on the mean line where it should be.
I have ensured that the svg is square
var width = window.innerWidth , height = window.innerHeight;
width = height = d3.min([width,height])
var data = d3.range(0,100).map(d=>Math.random())
Given the gradient the following properties
var linearGradient = defs.append("radialGradient")
.attr("id", "rad-gradient")
.attr("cx", "50%") //The x-center of the gradient, same as a typical SVG circle
.attr("cy", "50%") //The y-center of the gradient
.style("r", "50%");
and my area mathematically as
var area = d3.area()
.x1(function(d,i) { return width/2+Math.cos(i\*angle)*(h(d)) }) .x0(function(d,i) { return > width/2+Math.cos(i\*angle)*(h(mean)) }) .y0(function(d,i) {> return height/2+Math.sin(i\*angle)*(h(mean)) }) .y1(function(d,i) { return height/2+Math.sin(i\*angle)*(h(d)) })
And appended the created gradient to the svg path
svg.append("path")
.data([data])
.attr("class", "area")
.attr("d", area)
.style("fill", "url(#rad-gradient)")
The solution lies in creating a circle and filling it with the correct gradient. This ensures that the radial gradient will always be centered around the origin.
You can then use clipPath to extract only the path you wish to use from the circle. After a little fiddling to align the gradient radius, we get the desired effect.
// previous definition for area path appended as a clip path
clip = defs.append("clipPath")
.attr('id','clip')
.append("path")
.data([data])
.attr("class", "area")
.attr("d", area)
//extracting this path from a circle with the desired gradient
svg.append("circle")
.attr("cx", width/2)
.attr("cy", height/2)
.attr("r", rmax)
.attr("clip-path","url(#clip)")
.style("fill", "url(#linear-gradient)")

Painting different vertical segments under curve using d3

I am trying to create a simple line graph using d3 which segments the curve and paint each segment with a different colour. Currently I am only able to colour the whole area under the curve.
Current:
Attempting to achieve (Pardon me for the terrible colouring. In a rush for time):
This is bits of relevant code. Please help!
var x = d3.scaleLinear();
var y = d3.scaleLinear();
//Set the range of the data
x.domain([0, Math.max(endGrowth, endPlateau) ,maxX]).range([0, width*0.8, width]);
y.domain([0, maxY]).range([height, 0]);
//Define the area under the Graph
var area1 = d3.area()
.x0(function(d){
return x(d.Rank);
})
.y1(function(d){ return y(d.Elements);})
.y0(height);
//Add the colored regions
svg.append("path")
.data([data])
.attr("class", "areaUnderGraph")
.attr("fill", "blue")
.attr("transform", "translate(" + leftMarginLabel + ",0)")
.attr("d", area1);
Right now, the area under the curve is one path, so it can only be colored one color. The simplest way to color different portions under the curve different colors is to split them up in data. It's not clear where data is coming from, but you'd take sub-sections of the array, like
var segments = [data.slice(0, 2), data.slice(2)];
svg.selectAll("path")
.data(segments)
.enter()
.append("path")
.attr("fill", function(d) { /* use d to choose a color */ })
That's the gist: you'd have multiple slices of the data, and instead of one path, you'd create multiple paths that you can color as you wish.

append a circle in middle of all my path (sunburst)

Hello I do an sunburst or bilevel chart it's middle of a pie & donut chart ^^ When I append all path it works fine:
this.path = this.svg.selectAll("path")
.data(this.partition.nodes(rootData).slice(1))
.enter().append("path")
.attr("d", this.arc)
.style("fill", function(d) { return d.fill; })
.each(function(d){ this._current = thiss.updateArc(d);});
But the probleme is when I'm trying to add a circle in middle-extern of all my path so it didn't work, this code add circle in the middle-middle of all my path fine
var indicator = this.svg.selectAll('circle')
.data(this.partition.nodes(rootData))
.enter().append("circle")
.attr("cx", function(d){return thiss.arc.centroid(d)[0]})
.attr("cx", function(d){return thiss.arc.centroid(d)[1]})
.attr("r", 5).style('fill','#ff0000');
But I need to add this little circle in the midle but on extern border of the path.
I don't know how I can get the right cx and cy attributs, help please ?
This is screenshot of my goal (black points are what I had) and (red points are what I want to do)
http://i.stack.imgur.com/GXPYM.jpg
This is in part a repeat of Lars' equations from the comments, but I thought it was worth recapping all at once because the trig identities for converting from angles to x/y coordinates won't match your trig text book.
Most text books assume that angles start at the right horizontal axis and increase counter-clockwise, and that the vertical axis has larger values higher up on the page.
In SVG, larger y values are lower on the page, and the angles created by the pie chart layout (and the example code the OP is using for the sunburst layout) draw an angle of zero as vertical line to the top of the circle, with angles increasing clockwise.
With that information, you can convert to x and y values with the following trig equations:
g.append("circle") //circles inherit pie chart data from the <g>
.attr("r", 5)
.attr("cx", function(d) {
return Math.sin((d.startAngle + d.endAngle)/2) *radius;
})
.attr("cy", function(d) {
return -Math.cos((d.startAngle + d.endAngle)/2) *radius;
});
Live example: http://fiddle.jshell.net/4x9ap/1/
Again, this simple example uses a pie chart layout, so the data has startAngle and endAngle values, and the radius is constant. For a sunburst diagram made with the partition layout, you would replace (d.startAngle + d.endAngle)/2 with d.x + d.dx/2, and you would replace radius with a function based on d.depth.
As an alternative to trigonometry, you could use transformations to position the circles. If the first step in a transformation is a rotation, and then you apply a translation afterwards, the translation will be applied in the rotated coordinate system.
A little extra complication, though, is that the d3 pie chart gives angles in radians (since that's what the trigonometry functions use), but the rotation needs angles in degrees.
var degreesPerRadian = 180/Math.PI;
g.append("circle") //circles inherit pie chart data from the <g>
.attr("r", 5)
.attr("transform", function(d) {
return "rotate(" + degreesPerRadian*((d.startAngle + d.endAngle)/2)
+ ")" +
//rotate by the average of the start and end angle
//Note that d3 specifies angles in radians, but the rotate
//function needs them in degrees
"translate(0," + -radius + ")";
//then translate "up" the distance of the radius;
//"up" is interpretted according to the rotated coordinates,
//but for zero rotation it will position the dot at the top
//of the circle, which is the zero angle for d3
});
Live example: http://fiddle.jshell.net/4x9ap/
(based on this simple pie chart code )

Categories

Resources