I want to redraw dots every time I click update - javascript

Right now I have a bubble chart that plots bubbles at different point with different radius. I want to be able to click a button and the re-populate the chart with new random bubbles.
I created a function update(), where I have tried putting d3.selectall("circles").remove() before appending new circles to it. But it only removes the circles after I click it.
<body>
<button class="btn" onclick="update()">Update</button>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var r = d3.scaleLinear().range([10, 50]);
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 getdata = function() {
var dataset = []
for (var i = 0; i < 20; i++) {
var x = d3.randomUniform(-50,50)();
var y = d3.randomUniform(-50,50)();
var r = d3.randomUniform(-50,50)();
dataset.push({"x": x, "y": y,"r":r});
}
return dataset
}
var data = getdata()
data.forEach(function(d) {
d.x = +d.x;
d.y = +d.y;
d.r = +d.r;
});
x.domain([-50, 50]);
y.domain([-50, 50]);
r.domain([-50, 50]);
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", function(d) { return r(d.r); })
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.style("stroke", "black")
.style("fill", "none")
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.call(d3.axisLeft(y));
function update(){
d3.selectAll("circle").remove()
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", function(d) { return r(d.r); })
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.style("stroke", "black")
.style("fill", "none")
}

You're actually deleting the bubble and redrawing the same.
You need to update your chart.
function update(){
d3.selectAll("circle").remove()
svg.selectAll("dot")
.data(getdata())
.enter().append("circle")
.attr("r", function(d) { return r(d.r); })
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.style("stroke", "black")
.style("fill", "none")
}
I just replaced .data(data) with .data(getdata())

Related

d3js multi-line scatterplot zoom

I am working on a multi-line scatterplot with zoom using d3 v6. I am new to d3 and based on different examples, I could get the zoom function working for the images/points. The problem is that the lines aren't zooming. I looked at many similar questions, but none of those solutions are working for me.
The code I am using:
var margin = {
top: 50,
right: 30,
bottom: 30,
left: 210,
};
var svg = d3.select("svg"),
width = 1410 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
svg
.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
d3.csv("CSV_files/NSW_pathway.csv").then(function (data1) {
var groupData = d3.group(data1, (d) => d.pathway_name);
var xScale = d3.scaleLinear().domain([0, 1]).range([0, width]);
var yScale = d3.scaleLinear().domain([0, 1]).range([height, 0]);
var xAxis = d3.axisBottom(xScale).ticks(0).tickSize(-height);
var yAxis = d3.axisLeft(yScale).ticks(0).tickSize(-width);
var gX = svg
.append("g")
.attr(
"transform",
"translate(" + margin.left + "," + (margin.top + height) + ")"
)
.call(xAxis);
var gY = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(yAxis);
var focus = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "line")
.attr("clip-path", "url(#clip)");
const color = d3
.scaleOrdinal()
.range(["#e41a1c", "#377eb8", "#4daf4a", "#984ea3"]);
var points_g = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("clip-path", "url(#clip)")
.classed("points_g", true);
var label = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "label")
.attr("clip-path", "url(#clip)");
var div = d3
.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
const mouseover = function (event, d) {
div.style("opacity", 1);
};
const mousemove = function (event, d) {
div
.html(function (d1) {
if (d.type != "learner")
return `The resource name is ${d.resource_name}`;
else return `This is ${d.name}`;
})
.style("position", "absolute")
.style("left", event.pageX + 15 + "px")
.style("top", event.pageY + 15 + "px");
};
const mouseleave = function (event, d) {
div.transition().duration(200).style("opacity", 0);
};
var points = points_g.selectAll("point").data(data1);
points = points
.enter()
.append("image")
.attr("xlink:href", function (d) {
if (d.type == "video") return "Images/3.jpg";
else if (d.type == "pdf") return "Images/4.png";
else if (d.type == "none") return "Images/5.png";
})
.attr("x", function (d) {
return xScale(+d.x) - 10;
})
.attr("y", function (d) {
return yScale(+d.y) - 10;
})
.attr("width", 20)
.attr("height", 20)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave);
label
.selectAll(".text")
.data(data1)
.enter()
.append("text")
.text(function (d) {
return d.topic;
})
.attr("x", function (d) {
return xScale(+d.x) + 10;
})
.attr("y", function (d) {
return yScale(+d.y) + 10;
});
focus
.selectAll("line")
.data(groupData)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", function (d) {
return color(d[0]);
})
.attr("stroke-width", 1)
.attr("d", function (d) {
return d3
.line()
.curve(d3.curveMonotoneX)
.x(function (d) {
return xScale(+d.x);
})
.y(function (d) {
return yScale(+d.y);
})(d[1]);
});
var zoom = d3
.zoom()
.scaleExtent([0.5, 20])
.extent([
[0, 0],
[width, height],
])
.on("zoom", zoomed);
svg
.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.lower();
svg.call(zoom).call(zoom.transform, d3.zoomIdentity);
function zoomed({ transform }) {
var new_xScale = transform.rescaleX(xScale);
var new_yScale = transform.rescaleY(yScale);
gX.call(xAxis.scale(new_xScale));
gY.call(yAxis.scale(new_yScale));
points
.data(data1)
.attr("x", function (d) {
return new_xScale(d.x) - 10;
})
.attr("y", function (d) {
return new_yScale(d.y) - 10;
});
label
.selectAll("text")
.data(data1)
.attr("x", function (d) {
return new_xScale(d.x) + 15;
})
.attr("y", function (d) {
return new_yScale(d.y) + 15;
});
focus.selectAll("line").attr("d", function (d) {
return d3
.line()
.curve(d3.curveMonotoneX)
.x(function (d) {
return xScale(+d.x);
})
.y(function (d) {
return yScale(+d.y);
})(d[1]);
});
}
});
A sample of the csv file:
x,y,name,type,topic,resource_name,pathway_name
0,0,start,none,Sponsored Search Markets,Networks Crowd and Markets_NCMch15.pdf,pathwayOne
0,0,start,none,Sponsored Search Markets,Networks Crowd and Markets_NCMch15.pdf,pathwayTwo
0.086511627906977,0.16,horse,pdf,Graphs,Networks Crowd and Markets_NCMch2.pdf,pathwayOne
0.12,0.283768436578171,choice,pdf,Network Centrality,Notes_CGT BASED network CENTRALITY - L2.pdf,pathwayTwo
0.32,0.27217943628424,plex,video,Network Models,Network Analysis_LNch13.pdf,pathwayOne
0.775398773006135,0.33,social,pdf,Clustering,Network Analysis_LNch8.pdf,pathwayTwo
1,1,end,none,Allocation in Networks,Notes_Allocation in networks with DON-L3.pdf,pathwayOne
1,1,end,none,Allocation in Networks,Notes_Allocation in networks with DON-L3.pdf,pathwayTwo
Thank you for your help.
It's not zooming the whole page, it's zooming the whole svg, your large margins extend beyond the charting area. One solution is to add the g element not on your svg but only on your chart area.
But using your code, there are 2 things preventing your lines from zooming.
1: your selection is empty - line is a d3 abstraction that returns a path
function zoomed() {
...
// empty selection
console.log(focus.selectAll('line'))
// try instead
console.log(focus.selectAll('path'))
}
2: Simple mistake - you're using the old scale not the new one
function zoomed() {
...
focus.selectAll('path').attr('d', d => {
return d3.line()
// using old scale
.x(di => xScale(+di.x))
// change to
.x(di => new_xScale(+di.x))
})
}
I don't have a sample of your csv file so this isn't tested, but if you want to zoom the whole chart just add a parent g after your svg and transform that..
...
svg
.append("defs")
.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// NEW - add g
.append('g')
// NEW - adjust scaleExtent to your needs
const zoom = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', updateChart)
svg.call(zoom)
function updateChart(event) {
svg.attr('transform', event.transform)
}
Note that this also adds pan, but if you only want zoom you can use:
let scale = 1
...
function updateChart(event) {
if(event.transform.k === scale) { return }
svg.attr('transform', event.transform)
scale = event.transform.k
}

D3 graph tooltip should show nearest point on hover

I have made a graph using D3 but the problem is that I want its tooltip to appear on the graph as per nearest mouse point over in the graph. I have also seen one example on StackOverflow here on this link - D3: Get nearest value from ordinal axis on mouseover. Which is doing the exact what I want but when I implemented the same code on my graph then it is not working. Please take a look at my code and suggest me changes.
IMPORTANT!: I also want when someone double click on the graph then tooltip x'axis & y'axis coordinated stay there. Your valuable time is highly appreciated. Please Help!!!
<div id='chartdiv'></div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
function getData(){
data1 = [{x:1,y:15},{x:2,y:26},{x:3,y:17},{x:4,y:21},];
return data1};
function drawChart(data) {
var coreheight = 720
var corewidth = 1280
var margin = {top: 10, right: 30, bottom: 100, left: 60}
, width = corewidth - margin.left - margin.right
, height = coreheight - margin.top - margin.bottom;
var xExtent = d3.extent(data, function(d) { return d.x; }),
xRange = xExtent[1] - xExtent[0],
yExtent = d3.extent(data, function(d) { return d.y; }).reverse(),
yRange = yExtent[1] - yExtent[0];
var xScale = d3.scaleLinear().range([50, width]).domain([xExtent[0] - (xRange * .05), xExtent[1] + (xRange * .05)]);;
var yScale = d3.scaleLinear().range([0, height]).domain([yExtent[0] - (yRange * .1), yExtent[1] + (yRange * .05)]);;
var line = d3.line()
.x(function(d, x) { return xScale(d.x); })
.y(function(d, y) { return yScale(d.y); })
.curve(d3.curveMonotoneX);
d3.select('#chartdiv')
.append('svg')
.attr('class','graph')
.style('background-color','#fff')
.attr("viewBox", "0 0 "+ corewidth +" "+ coreheight +"");
var svg = d3.select(".graph")
.append("g")
.attr("class", "dchart")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale).ticks(7))
.attr("transform", "translate(50, 0)")
.attr('font-size','25px');
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale).ticks(7))
.attr('font-size','25px');
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.selectAll(".dot")
.data(data)
.enter()
.append("circle")
.attr("class", "dot")
.attr("cx", function(d) { return xScale(d.x) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 8)
.on("mouseover", mousehover)
.on("mouseout", mousehoverout)
function mousehover(d) {
svg.append("text")
.attr('class','annot')
.attr('x', xScale(d.x) - 20)
.attr('y', yScale(d.y) - 23)
.text(d.x+','+d.y)
.style('font-size','30px')
svg.append('line')
.attr('class','annot')
.style("stroke", "black")
.attr('stroke-width','3')
.attr("x1", xScale(d.x))
.attr("y1", yScale(d.y))
.attr("x2", xScale(d.x))
.attr("y2", height);
}
function mousehoverout() {
d3.selectAll('.annot').remove()
}
}drawChart(getData());
</script>
<style>
.line {fill: none;stroke: darkblue;stroke-width: 3}
.dot {fill: darkblue;stroke-width:0}
</style>
You need to track where the mouse is on the chart, you're currently only checking if the mouse is hovering on a dot.
I've added a couple of event handlers to the entire chart:
.on("mousemove", mousemove)
.on("mouseout", mousehoverout);
One you have already implemented, mousehoverout, and the other, mousemove, which tracks where the mouse is relative to the points.
var lastIndex = -1;
function mousemove()
{
let x = d3.mouse(this)[0];
let closest = data.reduce((best, value, i) =>
{
let absx = Math.abs(xScale(value.x) - x)
if(absx < best.value)
{
return {index: i, value:absx};
}
else
{
return best;
}
}, {index:0, value:Number.MAX_SAFE_INTEGER});
if(lastIndex != closest.index)
{
d3.selectAll('.annot').remove();
lastIndex = closest.index;
}
mousehover(data[closest.index]);
}
Then to add the double click functionality, you can do as you have shown in the w3schools link, but add the handler to the chart:
.on('dblclick', function(){/* your code in here */});
function getData(){
data1 = [{x:1,y:15},{x:2,y:26},{x:3,y:17},{x:4,y:21},];
return data1};
function drawChart(data) {
var coreheight = 720
var corewidth = 1280
var margin = {top: 10, right: 30, bottom: 100, left: 60}
, width = corewidth - margin.left - margin.right
, height = coreheight - margin.top - margin.bottom;
var xExtent = d3.extent(data, function(d) { return d.x; }),
xRange = xExtent[1] - xExtent[0],
yExtent = d3.extent(data, function(d) { return d.y; }).reverse(),
yRange = yExtent[1] - yExtent[0];
var xScale = d3.scaleLinear().range([50, width]).domain([xExtent[0] - (xRange * .05), xExtent[1] + (xRange * .05)]);;
var yScale = d3.scaleLinear().range([0, height]).domain([yExtent[0] - (yRange * .1), yExtent[1] + (yRange * .05)]);;
var line = d3.line()
.x(function(d, x) { return xScale(d.x); })
.y(function(d, y) { return yScale(d.y); })
.curve(d3.curveMonotoneX);
d3.select('#chartdiv')
.append('svg')
.attr('class','graph')
.style('background-color','#fff')
.attr("viewBox", "0 0 "+ corewidth +" "+ coreheight +"")
.on('dblclick', function(){if(lastIndex > -1) { createpeak(data[lastIndex]); } })
.on("mousemove", mousemove)
.on("mouseout", mousehoverout);
var svg = d3.select(".graph")
.append("g")
.attr("class", "dchart")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale).ticks(7))
.attr("transform", "translate(50, 0)")
.attr('font-size','25px');
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale).ticks(7))
.attr('font-size','25px');
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.selectAll(".dot")
.data(data)
.enter()
.append("circle")
.attr("class", "dot")
.attr("cx", function(d) { return xScale(d.x) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 8);
var lastIndex = -1;
function mousemove()
{
let x = d3.mouse(this)[0];
let closest = data.reduce((best, value, i) =>
{
let absx = Math.abs(xScale(value.x) - x)
if(absx < best.value)
{
return {index: i, value:absx};
}
else
{
return best;
}
}, {index:0, value:Number.MAX_SAFE_INTEGER});
d3.selectAll('.annot').remove();
lastIndex = closest.index;
mousehover(data[closest.index]);
}
function mousehover(d) {
svg.append("text")
.attr('class','annot')
.attr('x', xScale(d.x) - 20)
.attr('y', yScale(d.y) - 23)
.text(d.x+','+d.y)
.style('font-size','30px')
svg.append('line')
.attr('class','annot')
.style("stroke", "black")
.attr('stroke-width','3')
.attr("x1", xScale(d.x))
.attr("y1", yScale(d.y))
.attr("x2", xScale(d.x))
.attr("y2", height);
}
var i = 1;
var m = 1;
function createpeak(d) {
console.log('redacted');
}
function dragstarted(d,e){
d3.select(this).raise().classed("active", true);
var current = d3.select(this);
deltaX = current.attr("x") - d3.event.x;
deltaY = current.attr("y") - d3.event.y;
}
function dragged(d,e){
d3.select(this).attr("x",d3.event.x + deltaX)
d3.select(this).attr("y",d3.event.y + deltaY)
for (var i=1; i <= 100; i++){
d3.select('.line'+i).attr("x2", function (d) {
return d3.select('.peak'+i).attr("x") - deltaX
});
d3.select('.line'+i).attr("y2", function (d) {
return d3.select('.peak'+i).attr("y") - deltaY
})}}
function dragended(d,e){}
function mousehoverout() {
}
}drawChart(getData());
.line {fill: none;stroke: darkblue;stroke-width: 3}
.dot {fill: darkblue;stroke-width:0}
<div id='chartdiv'></div>
<script src="https://d3js.org/d3.v5.min.js"></script>

How to make a moving transition of points from a to b

I have a scatterplot and I have two different sets of datapoints I am visualizing from the dataset. I want to animate the path from "red" to "blue" dots and show them like the blue point is moving from the red and getting its position. Is that possible with d3, and if so how can I do this?
The scatterplot I have currently with the plotted points is here.
this is how I draw both sets of datapoints in the scatterplot:
// blue dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.x); } )
.attr("cy", function (d) { return y(d.y); } )
.attr("r", 4.1)
.transition()
.style("fill", "blue")
// red dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.x1); } )
.attr("cy", function (d) { return y(d.y1); } )
.attr("r", 4.1)
.style("fill", "red")
}
Thank you for any kind of help in advance!
Yes it's possible.
Using the property transition and combining with duration in milliseconds. Look below:
https://jsfiddle.net/mathyaku/L5bpaxwv/1/
function drawScatterplot(data, selector) {
// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 30, left: 60 },
width = 700 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select(selector)
.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 + ")");
//Read the data
// Add X axis
var x = d3.scaleLinear()
.domain([0, 1])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 1])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Add red dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.x1); })
.attr("cy", function (d) { return y(d.y1); })
.attr("r", 4.1)
.style("fill", "red")
svg.selectAll("circle")
.transition()
.duration(2000)
.attr("cx", function (d) { return x(d.x); })
.attr("cy", function (d) { return y(d.y); })
.style("fill", "blue")
}
drawScatterplot(data, '#Scatterplot');

D3.js v5 Line chart with circle markers

The lines on my chart are displaying with a weird black filled-in shape instead of an actual line. Any idea what i'm doing wrong? The data is parsed in from a csv. It's a multiline chart where each series is a column in the csv(columns are: date, cat1, cat2, cat3, cat4).
Aside - I got this to work in a different fashion by defining each valueline and appending to the path. But I ran into issues with scaling the axis. I eventually need to have four plots on my html page, each with different axis scales (for example log scale on the y axis). Therefore I'll need y = d3.scaleLog().domain(my domain).range(range) and then in d3.line.y return y(my value).
var margin = {top: 20, right: 20, bottom: 30, left: 50},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var padding =20;
var xScale = d3.scaleTime()
.domain([d3.min(dataset,function (d) { return d.date }),d3.max(dataset,function (d) { return d.date }) ]).range([padding, w - padding * 2])
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset,function (d) { return d.cat1 }) ]).range([h- padding, padding])
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
var svg1 = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var line = d3.line()
.x(function(d) { return xScale(d['date']); })
.y(function(d) { return yScale(d['cat1']); });
var line2 = d3.line()
.x(function(d) { return xScale(d['date']); })
.y(function(d) { return yScale(d['cat2']); });
var line3 = d3.line()
.x(function(d) { return xScale(d['date']); })
.y(function(d) { return yScale(d['cat3']); });
var line4 = d3.line()
.x(function(d) { return xScale(d['date']); })
.y(function(d) { return yScale(d['cat4']); });
var path = svg1.append('path').attr('d', line(dataset));
var path2 = svg1.append('path').attr('d', line2(dataset));
var path3 = svg1.append('path').attr('d', line3(dataset));
var path4 = svg1.append('path').attr('d', line4(dataset));
//draw points
var selectCircle = svg1.selectAll(".circle")
.data(dataset)
selectCircle.enter().append("circle")
.attr("class", "circle")
.attr("r", 10)
.attr("cx", function(d) {
return xScale(d.date)
})
.attr("cy", function(d) {
return yScale(d.cat1)
})
.attr("fill", "#FFC300")
selectCircle.enter().append("circle")
.attr("class", "circle")
.attr("r", 10)
.attr("cx", function(d) {
return xScale(d.date)
})
.attr("cy", function(d) {
return yScale(d.cat2)
})
.attr("fill", "#FF5733")
selectCircle.enter().append("circle")
.attr("class", "circle")
.attr("r", 10)
.attr("cx", function(d) {
return xScale(d.date)
})
.attr("cy", function(d) {
return yScale(d.cat3)
})
.attr("fill", "#C70039")
selectCircle.enter().append("circle")
.attr("class", "circle")
.attr("r", 10)
.attr("cx", function(d) {
return xScale(d.date)
})
.attr("cy", function(d) {
return yScale(d.cat4)
})
.attr("fill", "#900C3F")
svg1.append("g").attr("class", "axis").attr("transform", "translate(0," + (h - padding) + ")").call(xAxis);
//draw Y axis
svg1.append("g").attr("class", "axis").attr("transform", "translate(" + padding + ",0)").call(yAxis);
// add label
svg1.append("text").attr("x", (w/2)).attr("y", h+30).attr("text-anchor", "middle").text("Year");
svg1.append("text").attr("x", padding).attr("y", padding-20).attr("text-anchor", "middle").text("# of Events");
//add title
svg1.append("text").attr("x", (w/2)).attr("y", padding).attr("text-anchor", "middle").text("Events per Year by Category");

how to align y axis label in D3

i am trying to create a stacked bar graph.
however i can't seem to get the alignment right.the graph has two axis.
because of the length of the y axis label it is partially blocked.
i tried solving this by using different CSS styles on the label and on the enclosing div,
but they did not have the desired affect.
i created a jsfidel to explain my case.
http://jsfiddle.net/2khbceut/1/
HTML
<title>Diverging Stacked Bar Chart with D3.js</title>
<body>
<div id="figure" align="center" style="margin-bottom: 50px;"></div>
</body>
javascript
$(document).ready(getTopolegy());
function getTopolegy(){
var data = null;
var links = parseTopology(data);
createChart(links);
}
function parseTopology(data){
var links=[{1:5,2:5,3:10,N:20,link_name: "Link 167772376>>167772375"}];
return links;
}
function jsonNameToId(name){
switch (allocated_priority) {
case "allocated_priority":
return 1;
case "allocated_default":
return 2;
case "spare_capacity":
return 3;
case "total":
return "N";
default:
return 999;
}
}
function createChart(data){
var margin = {top: 50, right: 20, bottom: 10, left: 65},
width = 1000 - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom;
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], .3);
var x = d3.scale.linear()
.rangeRound([0, width]);
var color = d3.scale.ordinal()
.range(["#cccccc", "#92c6db", "#086fad"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var svg = d3.select("#figure").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "d3-plot")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
color.domain(["Allocated Priority %", "Allocated Default %", "Spare Capacity %"]);
// d3.csv("js/raw_data.csv", function(error, data) {
data.forEach(function(d) {
d["Allocated Priority %"] = +d[1]*100/d.N;
d["Allocated Default %"] = +d[2]*100/d.N;
d["Spare Capacity %"] = +d[3]*100/d.N;
var x0 = 0;
var idx = 0;
d.boxes = color.domain().map(function(name) { return {name: name, x0: x0, x1: x0 += +d[name], N: +d.N, n: +d[idx += 1]}; });
});
var min_val = d3.min(data, function(d) {
return d.boxes["0"].x0;
});
var max_val = d3.max(data, function(d) {
return d.boxes["2"].x1;
});
x.domain([min_val, max_val]).nice();
y.domain(data.map(function(d) { return d.link_name; }));
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var vakken = svg.selectAll(".Link")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(0," + y(d.link_name) + ")"; });
var bars = vakken.selectAll("rect")
.data(function(d) { return d.boxes; })
.enter().append("g").attr("class", "subbar");
bars.append("rect")
.attr("height", y.rangeBand())
.attr("x", function(d) { return x(d.x0); })
.attr("width", function(d) { return x(d.x1) - x(d.x0); })
.style("fill", function(d) { return color(d.name); });
bars.append("text")
.attr("x", function(d) { return x(d.x0); })
.attr("y", y.rangeBand()/2)
.attr("dy", "0.5em")
.attr("dx", "0.5em")
.style("font" ,"10px sans-serif")
.style("text-anchor", "begin")
.text(function(d) { return d.n !== 0 && (d.x1-d.x0)>3 ? d.n : "" });
vakken.insert("rect",":first-child")
.attr("height", y.rangeBand())
.attr("x", "1")
.attr("width", width)
.attr("fill-opacity", "0.5")
.style("fill", "#F5F5F5")
.attr("class", function(d,index) { return index%2==0 ? "even" : "uneven"; });
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y2", height);
var startp = svg.append("g").attr("class", "legendbox").attr("id", "mylegendbox");
// this is not nice, we should calculate the bounding box and use that
var legend_tabs = [0, 150, 300];
var legend = startp.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + legend_tabs[i] + ",-45)"; });
legend.append("rect")
.attr("x", 0)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 22)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.style("font" ,"10px sans-serif")
.text(function(d) { return d; });
d3.selectAll(".axis path")
.style("fill", "none")
.style("stroke", "#000")
.style("shape-rendering", "crispEdges")
d3.selectAll(".axis line")
.style("fill", "none")
.style("stroke", "#000")
.style("shape-rendering", "crispEdges")
var movesize = width/2 - startp.node().getBBox().width/2;
d3.selectAll(".legendbox").attr("transform", "translate(" + movesize + ",0)");
// });
}
i will appreciate any insight you have on this matter.

Categories