I want to delete a particular group element from the svg.
The code is:
var margin = {top: 20, right: 20, bottom: 20, left: 60};
var width=800, height=450;
svg = d3.select("#svgchart").append("g").attr("id","groupid").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g").attr("id", "groupid2")
.attr("class", "x axis")
.attr("transform", "translate(1," + (height + 1) +")")
.call(xAxis)
.moveToBack();
//add the y-axis
svg.append("g").attr("id", "groupid3")
.attr("class", "y axis")
.attr("transform", "translate(1, 0)")
.call(yAxis)
.moveToBack();
//add an x-axis label
svg.append("text")
.attr("class", "x label axis")
.attr("text-anchor", "end")
.attr("x", width)
.attr("y", height - 6)
.text(varxaxis);
svg.append("text")
.attr("class", "y label axis")
.attr("text-anchor", "end")
.attr("y", 6)
.attr("dy", "3.75em")
.attr("transform", "rotate(-90)")
.text(yaxistext);
.....................................
.....................................
.....................................
To delete a particular group from svg:
svg.select("groupid").remove();
The group is not getting deleted.How do i remove a group?
A selection of select("groupid") will select the first element called "groupid". If you want to select the first element with an ID of "groupid", you must use: select("#groupid"). For classes, replace the "#" with a period.
In your case, "groupid" isn't an element. It is an ID you have provided to a 'g' element.
So, make sure you use select("#groupid").remove(). Don't forget the "#".
Related
I'm having challenges in setting the bar (fixed width) position aligned correctly width the x-axis label.
The bars and the x-ticks are not aligned correctly and also the last bar is rendered after the max xscale range.
Appreciate any help in fixing this issue.
Please check the sample here - https://jsfiddle.net/sjselvan/wsy5frh2/29/ - updated and fixed version
function generateChart(){
const data = [{
label: 100,
value: 10
},
{
label: 200,
value: 20
},
{
label: 300,
value: 30
},
{
label: 400,
value: 40
},
{
label: 500,
value: 50
}];
let margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
const xScale = d3.scaleLinear().domain([0,500]).range([0,width]);
const yScale = d3.scaleLinear().domain([0,50]).range([height,0]);
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
console.log(d3.select('#chart'));
let svg = d3.select('#chart')
.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)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return xScale(d.label); })
.attr("width", 15)
.attr("y", function(d) { return yScale(d.value); })
.attr("height", function(d) { return height - yScale(d.value); });
}
generateChart();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="chart"></div>
You're setting the x value of the bars, which sets the left-hand edge of the bars, using the same scale as the x axis. So, it makes sense that the left-hand edge of the bar representing 100 is lined up with the 100 tick in the axis.
In order to line up the bars, you need to move them to the left by half of their width. You would need to make the bar width an even number so that the bars fit nicely.
const barWidth = 16;
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return xScale(d.label) - (barWidth / 2); })
.attr("width", barWidth)
.attr("y", function(d) { return yScale(d.value); })
.attr("height", function(d) { return height - yScale(d.value); });
However, I would say that it doesn't really make sense for this chart to be a bar chart. Bars usually represent nominal (Banana, Apple, Pear), or ordinal values. Whereas your chart seems to more suit a line, or a scattergraph.
But if you do mean to use the numbers as labels, you will be better off using a band scale which will line up the bars above the labels nicely.
I'm writing d3.js (d3 v4) code to generate a simple bar chart, which I managed to do, but I am confused about the behavior of the code in generating axes.
So basically, I encapsulated the chart code into a function that contains basic accessors.
Here is some code showing the core of my chart function.
function chart(selection){
selection.each(function(data){
var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.5);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var div = d3.select(this)
var svg = div.selectAll("svg")
.data([data]).enter()
.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)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("fill", "#1CE6FF")
.attr("x", function(d) { return x(d.name); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
});
So I have two questions: 1) Is it okay to use multiple code blocks invoking svg.append("g") like shown above in the code?
2) When I replace the following code :
var svg = div.selectAll("svg")
.data([data]).enter()
.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)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
With this (which is basically merging the two blocks in a single chain code chunk):
var svg = div.selectAll("svg")
.data([data]).enter()
.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 + ")").append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
...why is my y axis not showing at the right place? The <g class="y axis">...</g> tag appears nested into of a <text> tag itself nested in the x axis tag. Why the 2-block code vs single block code not behaving the same?
The structure of the code defines the structure of the resulting SVG. In the function chart() the variable svg holds the reference to the lastly appended <g> not to the previously appended <svg> itself. Note, how all statements after its first creation append to that same outer group of svg. That's one perfectly fine way of doing this.
If you concatenate the statements, however, like you did in your last snippet, the value of svg changes because the right hand side, i.e. the return value of the expression, changes. Since you last selected all text elements of the appended x-axis svg contains exactly those texts. Given that, it is pretty easy to understand that this breaks the rest of the code which will now append other contents to the text elements. Even if it was syntactically valid, which it is not, it would most likely still break the layout.
If you want to rearrange the code structure you have to make sure to have the correct references at the time they are needed.
I want to format the x axis text with more padding and space and I am not able to achieve this. The actual text is around 6-7 characters long, but it is only showing 3. Here is the extract of the code and a screenshot:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("transform", "rotate(90)");
d3 bar chart
When rotating the text in the ticks, you have to set the x and y. Also, it's a good idea changing the text-anchor. Something like this:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 0)//tweak this value
.attr("x", 10)//tweak this value
.attr("dy", ".35em")//tweak this value
.attr("transform", "rotate(90)")
.style("text-anchor", "start");
Check the demo:
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 100);
var data = ["foo", "bar", "baz", "foobar", "foobaz"];
var scale = d3.scaleBand()
.range([0, 400])
.domain(data);
var axis = d3.axisBottom(scale);
var gX = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0,30)")
.call(axis)
.selectAll("text")
.attr("y", 0)//tweak this value
.attr("x", 10)//tweak this value
.attr("dy", ".35em")//tweak this value
.attr("transform", "rotate(90)")
.attr("font-size", 14)
.style("text-anchor", "start");
<script src="https://d3js.org/d3.v4.min.js"></script>
I am trying to extend the x and y axis length and add the arrow at the end. Here is my code and plunker. I need x axis to extend beyond 4.6 and y-axis beyond "AS" and add an arrow at the end. Kindly help.
https://plnkr.co/edit/tA6oyKQCCmhNadbARR89?p=preview
var margin = {top: 20, right: 20, bottom: 20, left: 40},
width = 420 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.ordinal().rangePoints([height, 0])
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom").outerTickSize(0);
var yAxis = d3.svg.axis()
.scale(y).tickSize(-width).outerTickSize(0)
.orient("left");
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 + ")");
d3.tsv("data.tsv", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.sepalWidth = +d.sepalWidth;
});
x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice();
y.domain(data.map(function(d) { return d.sepalLength;}));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.sepalWidth); })
.attr("cy", function(d) { return y(d.sepalLength); })
.style("fill", function(d) { return color(d.species); });
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
Easiest way is to just tack on a custom path to the end of the axis:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis)
.append("path")
// add extension arrow
.attr("d", "M" + width + ",0L" + (width + 20) + ",0L" + (width + 20) + ",-5L" + (width + 30) + ",0L" + (width + 20) + ",5L" + (width + 20) + ",0L");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("path")
// add extension arrow
.attr("d", "M0,0L0,-20L-5,-20L0,-30L5,-20,L0,-20Z");
Updated plunker.
Any thoughts on why the text is missing for the first rectangle yet others are all fine?
http://jsfiddle.net/sjp700/bhwpu/
vis = d3.select("#chart")
.append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.style("fill", "pink")
.attr('class', 'chart');
vis.append("g") // container element
.attr("class", "x axis") // so we can style it with CSS
.attr("transform", "translate(0," + height + ")") // move into position
.call(xAxis); // add to the visualisation
//add in the y axis
vis.append("g") // container element
.attr("class", "y axis") // so we can style it with CSS
.call(yAxis); // add to the visualisation