My goal here is to translate a group of svg elements with a translation. It is not working. Here is the code:
Create an SVG container
// create svg container
canvas = d3.select("body").append("svg")
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height);
Append a translation of x=200, y=200
// apply a transform
canvas.append("g")
.attr("transform", function(d) { return scarpa.translate(200, 200); });
Add a box
// render a background
canvas.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.style("opacity", 1)
.style("fill", function(d) { return scarpa.rgb_SVG(0,255,0); });
Add a y-axis
// render y-axis
canvas.append("g")
.attr("class", "y axis")
.append("line")
.attr("stroke", function(d) { return scarpa.grey_SVG(64); })
.attr("x1", histogram.xScale(0))
.attr("y1", 0)
.attr("x2", histogram.xScale(0))
.attr("y2", canvasBBox.height);
The box + y-axis line never translates. For a sanity check I applied the translation direction to the box and it did translate. Sigh.
I am assuming the group translation implies a local coordinate system within with x = y = 0 would be the origin of the translated coordinate frame. No? What am I missing here?
The problem is, that the .append() function does not change the selection that it is called on, but returns a new selection.
Therefore the g element gets appended to the svg and the rect gets also appended to the svg and not inside the translated g element. You should see this if you inspect the svg output.
There are two possible solutions:
1: If you want to translate everything, append the g element in the first statement like so:
var canvas = d3.select("body").append("svg")
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.append("g")
.attr("transform", function(d) { return scarpa.translate(200, 200); });
canvas.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.style("opacity", 1)
.style("fill", function(d) { return scarpa.rgb_SVG(0,255,0); });
canvas.append("g")
.attr("class", "y axis")
.append("line")
.attr("stroke", function(d) { return scarpa.grey_SVG(64); })
.attr("x1", histogram.xScale(0))
.attr("y1", 0)
.attr("x2", histogram.xScale(0))
.attr("y2", canvasBBox.height);
2: If you want to append something outside of the translated group,
assign the groupselection to a new variable like so:
var canvas = d3.select("body").append("svg")
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height);
var canvasGroup = canvas.append("g")
.attr("transform", function(d) { return scarpa.translate(200, 200); });
canvasGroup.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.style("opacity", 1)
.style("fill", function(d) { return scarpa.rgb_SVG(0,255,0); });
canvasGroup.append("g")
.attr("class", "y axis")
.append("line")
.attr("stroke", function(d) { return scarpa.grey_SVG(64); })
.attr("x1", histogram.xScale(0))
.attr("y1", 0)
.attr("x2", histogram.xScale(0))
.attr("y2", canvasBBox.height);
Related
This question already has answers here:
Adding text to d3 circle
(2 answers)
Closed 3 years ago.
I am writing a text element (x axis measure value) for each circle but even after showing text element in inspect in browser its not showing
I have appended the text under circle given same x and y for the circle but its coming through
!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 40, left: 100},
width = 460 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
// Parse the Data
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/7_OneCatOneNum_header.csv", function(data) {
// sort data
data.sort(function(b, a) {
return a.Value - b.Value;
});
// Add X axis
var x = d3.scaleLinear()
.domain([0, 13000])
.range([ 0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([ 0, height ])
.domain(data.map(function(d) { return d.Country; }))
.padding(1);
svg.append("g")
.call(d3.axisLeft(y))
// Lines
svg.selectAll("myline")
.data(data)
.enter()
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y1", function(d) { return y(d.Country); })
.attr("y2", function(d) { return y(d.Country); })
.attr("stroke", "grey")
// Circles -> start at X=0
svg.selectAll("mycircle")
.data(data)
.enter()
.append("circle")
.attr("cx", x(0) )
.attr("cy", function(d) { return y(d.Country); })
.attr("r", "7")
.style("fill", "#69b3a2")
.attr("stroke", "black")
// Change the X coordinates of line and circle
svg.selectAll("circle")
.transition()
.duration(2000)
.attr("cx", function(d) { return x(d.Value); })
svg.selectAll("line")
.transition()
.duration(2000)
.attr("x1", function(d) { return x(d.Value); })
// this is the line i have added at my end and it showing as well while i do the inspect element.
svg.selectAll("circle")
.append(Text)
.attr("x", function (d) { return x(d.Value); })
.attr("y", function (d) { return y(d.Country); })
.text(function (d) { return d.Value})
.attr("font-family", "sans-serif")
.attr("font-size", "6px")
.attr("fill", "black")
.style("text-anchor", "middle")
})
</script>
Would like to show measure value under circle so user dont have to guess the x axis. circle is at 13000 so it should show as 13 in circle divided by 1000
From what I can see there's a couple of things going on.
Firstly, instead of:
...
.append(Text)
which is trying to pass in a variable called Text to the append function, it should be:
...
.append('text')
i.e. append an svg text element.
However, this is still appending text elements to circle elements. If you look at the elements via Chrome Devtools, you can see that there will be a text element inside each circle element, which doesn't actually display anything.
Instead, the label text needs to be rendered separately from the circles using something like.
svg.selectAll("mytext")
.data(data)
.enter()
.append('text')
.attr("x", function (d) { return x(d.Value) + 10; })
.attr("y", function (d) { return y(d.Country) + 4; })
.text(function (d) { return d.Value})
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "black")
.style("text-anchor", "start")
.style('opacity', 0)
.transition()
.delay(1500)
.duration(500)
.style('opacity', 1);
I've made the font a bit bigger, and adjusted the x and y values and used text-anchor: start so that now the text appears just off the right of the circles. I've also put in a transition based on opacity with a delay so that the text only appears at the end of the circles' animation.
I'm working on a modified version of this D3 code for parallel coordinates. I would like to add a background color for the axis labels. I realize I cannot set a background color using CSS styles because this is SVG text, so I tried to append rectangles but to no avail. Here is what I wrote but it's not drawing anything:
d3.selectAll(".label")
.append("rect")
.attr("x", function(d){ return d3.select(this).node().getBBox().x - 5;})
.attr("y", function(d){ return d3.select(this).node().getBBox().y - 5;})
.attr("width", function(d){ return d3.select(this).node().getBBox().width;})
.attr("height", function(d) {return d3.select(this).node().getBBox().height;})
.style("stroke", "black")
.style("fill", "yellow");
What am I doing wrong?
EDIT:
based on comments, I appended to the parent g rather than the text label itself. Now the code looks like this:
// Add an axis and title.
var gsvg= g.append("svg:g")
.attr("class", "axis")
.attr("id", "gsvg")
.each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
.attr("transform", "translate(0,0)");
d3.selectAll("#gsvg")
.append("rect")
.attr("x", function(d){ return this.parentNode.getBBox().x - 5;})
.attr("y", function(d, i){ return i%2 === 0 ? this.parentNode.getBBox().y - 20: this.parentNode.getBBox().y - 35;})
.attr("width", function(d){ return this.parentNode.getBBox().width;})
.attr("height", function(d) {return 20;})
.style("stroke", "lightgrey")
.style("stroke-width", 2)
.style("fill", function(d){
return self.fcolorMap[d];
})
.style("opacity", 0.5);
gsvg.append("svg:text")
.style("text-anchor", "middle")
.attr("y", function(d,i) { return i%2 == 0 ? -14 : -30 } )
.attr("x",0)
.attr("class", "axis-label")
.text(function(d) {
var s = d.split("|");
return s[s.length-1]; });
The only problem is now I need to figure out how to get the bounding boxes of the labels rather than those of the axes.
I'm trying to add text to a vertical line using d3. In principle the text is attached to the line but it is not showing. Any idea why? Here is my code and and image of the current state.Code problem
Thanks in advance!
var espanya = aggregatevalue(data)[0]['2015'];
var svg = d3.select("#UnemploymentRate")
.append("svg")
.attr("id", "chart")
.attr("width", w)
.attr("height", h);
svg.append("g")
.attr("class", "espanya line")
var lespanya = d3.select(".espanya.line")
.append("line")
.attr("class", "line")
.style("stroke-width", 2)
.style("stroke", "black")
.style("stroke-dasharray", ("3, 3"))
.style("fill", "none");
lespanya.attr("x1", padding.left + widthScale(espanya))
.attr("y1", heightScale(maximo))
.attr("x2", padding.left + widthScale(espanya))
.attr("y2", h - padding.bottom);
lespanya.append("text")
.attr("x", 486.78)
.attr("y", 300)
.text("Spain Average unemployment");
You should not append that group to the line element. You can append both text and line to .espanya.
It has to be more or less like this,
var svg = d3.select("#UnemploymentRate")
.append("svg")
.attr("id", "chart")
.attr("width", w)
.attr("height", h);
var container = svg.append("g")
.attr("class", "espanya")
var lespanya = container
.append("line")
.attr("class", "line")
.style("stroke-width", 2)
.style("stroke", "black")
.style("stroke-dasharray", ("3, 3"))
.style("fill", "none");
var text = container
.append("text")
.attr("x", 486.78)
.attr("y", 300)
.text("Spain Average unemployment");
Try this and provide a jsfiddle if it doesn't work.
I have a line (& area) graph which works ok, when horizontal. But I really need it to be vertical, to stand up. I have tried all kinds of changes to the existing code. Mostly with some strange results.
Here’s the code (modified it a bit). Is there a way to change it to make the graph vertical?:
var x = d3.scale.linear().domain([1, itemCount]).range([0, width]);
var y = d3.scale.linear().domain([0, maxValue]).rangeRound([height, 0]);
// Set up linar x and y axis.
var xAxis = d3.svg.axis().scale(x).ticks(10);
var yAxis = d3.svg.axis().scale(y).ticks(2).orient("left");
// Line graph.
line = d3.svg.line()
.interpolate("basis")
.x(function (d) {
return x(d.x);
})
.y(function (d) {
return y(d.y);
});
// Create SVG element.
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// X-Axis, to bottom.
svg.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(1," + height + ")")
.call(xAxis);
//Y-Axis
svg.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(40, 1)")
.call(yAxis);
// Horizontal axis guide lines.
svg.selectAll("line.y")
.data(y.ticks(5))
.enter()
.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", y)
.attr("y2", y)
.style("stroke", "#000000")
.style("stroke-opacity", 0.1);
// Vertical axis guide lines.
svg.selectAll("line.x")
.data(y.ticks(5))
.enter()
.append("line")
.attr("x1", x)
.attr("x2", x)
.attr("y1", 0)
.attr("y2", this.heightInside - pushDown)
.style("stroke", "#000000")
.style("stroke-opacity", 0.1);
// Set up domains. Nice ensures the domains ends on nice round values.
x.domain([dataValues[0].x, dataValues[dataValues.length - 1].x]).nice();
y.domain([d3.min(dataValues, function (d) { return (d.y); }),
d3.max(dataValues, function (d) { return (d.y); })])
.nice();
// Draw line on graph.
svg.append("svg:path")
.attr("class", "line")
.attr("d", line(dataValues))
.style("stroke", function(d) { return colors[i]; });
// Marks.
svg.selectAll("circle_" + i)
.data(dataValues)
.enter()
.append("circle")
.style("fill", function(d) { return _this.colors[i]; })
.attr("r", 4)
.attr('cx', function (d) { return x(d.x); })
.attr('cy', function (d) { return y(d.y); });
I'm trying to draw multiple 'cross' symbols inside of a circle for use in a visualization. I'd like to draw the crosses in a 'g' tag and then apply a clipping path.
Is it possible to use clip paths with d3.svg.symbol ?
In the below example, the svg circle is masked correctly with the clip path; however the cross (the last part of the code) isn't.
Am I doing something wrong or is this not a feature?
var svg = d3.select("#maskingExample")
.append("svg:svg")
.attr("width", 500)
.attr("height", 200);
svg.append("svg:clipPath")
.attr("id", "clipper")
.append("svg:rect")
.style("stroke", "gray")
.style("fill", "black")
.attr("x", 50)
.attr("y", 25)
.attr("width", 300)
.attr("height", 45);
svg.append("g").append("svg:circle")
.style("stroke", "gray")
.style("fill", "blue")
.attr("cx", 175)
.attr("cy", 55)
.attr("r", 50)
.attr("clip-path", "url(#clipper)");
svg.append("g").append("path")
.attr("d", d3.svg.symbol()
.size( function(d) { return 3000; })
.type( function(d) { return d3.svg.symbolTypes[1]; }))
.attr("transform", "translate(150, 50)")
.attr("clip-path", "url(#clipper")
.style("fill", "black");
You're missing a close paren. Instead of
.attr("clip-path", "url(#clipper")
it should read
.attr("clip-path", "url(#clipper)")