Aligment Labels Under Grouped Bar Chart - javascript

I'm relatively new to D3 and trying to add labels to a grouped bar chart.. So for the following picture which is an example, I would like to align label properly under grouped bar chart.
Code
Currently I am using the following code to create grouped bar chart
renderChart(data) {
d3.select("#group-bar-chart").select("svg").remove();
const width = document.querySelector("#group-bar-chart").clientWidth * 0.9,
height = 500,
margin = { top: 50, left: 40, bottom: 60, right: 40 },
chartWidth = width - (margin.left + margin.right),
chartHeight = height - (margin.top + margin.bottom),
colors = ["#22a348", "#e63c20", "#367af0"];
const svg = d3.select("#group-bar-chart").append("svg");
const chartLayer = svg.append("g").classed("chartLayer", true)
const xScale = d3.scaleBand();
const xScale1 = d3.scaleBand().padding(0.05);
const xInScale = d3.scaleBand();
const yScale = d3.scaleLinear()
const color = d3.scaleOrdinal().range(colors);
const keys = Object.keys(data[0]).filter(k => k !== 'objId' && k !== 'label');
main(data);
function main(data) {
const nested = d3.nest()
.rollup(function (d) {
const { 'label': omit, ...res } = d[0];
return res;
})
.key(function (d) { return d.label })
.entries(data)
nested.forEach(function (d) {
d.val = keys.map(function (key) {
return { key: key, value: d.value[key] }
})
})
setSize(nested)
drawChart(nested)
}
function setSize(nested) {
svg.attr("width", width).attr("height", height)
chartLayer
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr("transform", "translate(" + [margin.left, margin.top] + ")")
xScale.domain(nested.map(function (d) { return d.key }))
.range([0, chartWidth]).paddingInner(0.3)
xInScale.domain(keys).range([0, xScale.bandwidth()])
const yMax = d3.max(nested.map(function (d) {
const values = keys.map(function (key) {
return d.value[key]
})
return d3.max(values)
}))
yScale.domain([0, yMax]).range([chartHeight, 0])
}
function drawChart(nested) {
xScale1.domain(nested.map(d => { return d.key; })).rangeRound([0, chartWidth]);
const t = d3.transition()
.duration(1000)
.ease(d3.easeLinear)
const barGroup = chartLayer.selectAll(".bar-group")
.data(nested)
const newBarGroup = barGroup.enter()
.append("g")
.attr("class", "bar-group");
barGroup.merge(newBarGroup)
.attr("transform", function (d) { return "translate(" + [xScale(d.key), 0] + ")"; });
const bar = newBarGroup.selectAll(".bar")
.data(function (d) { return d.val })
const newBar = bar.enter().append("rect").attr("class", "bar")
bar.merge(newBar)
.attr("width", xInScale.bandwidth())
.attr("height", 0)
.attr("fill", function (d) { return color(d.key); })
.attr("transform", function (d) { return "translate(" + [xInScale(d.key), chartHeight] + ")" })
bar.merge(newBar).transition(t)
.attr("height", function (d) { return chartHeight - yScale(d.value); })
.attr("transform", function (d) { return "translate(" + [xInScale(d.key), yScale(d.value)] + ")" })
chartLayer.append("g")
.attr("class", "axis")
.style('transform', 'translate(0px, 420px)')
.style('text-anchor', 'middle')
.call(d3.axisTop(xScale1));
}
function wrap(text, width) {
text.each(function () {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
}
What I am looking for is look like image bellow.

Related

bubbleplot is not plotting d3js

I am trying to make buuble plot according to geo location.All my datas come from local .csv file. First i plotted only with one datasets and it worked fine.Now i have inserted two more datasets and everything is messed up. The code doesnt plot naything at all. I think it could be because i am not using any staements and writing the same code below the previous one.If you could give me some suggestions ,it would be quite helpful.
csv data :link
function createBubbleChart(error, countries, continentNames) {
var airports = countries.map(function(country) { return +country.airports; }), population = countries.map(function(country) { return +country.population; }),median_age = countries.map(function(country) { return +country.median_age; });
var meanairports = d3.mean(airports),meanpopulation = d3.mean(population),meanmedian_age = d3.mean(median_age),
airportsExtent = d3.extent(airports),populationExtent = d3.extent(population),median_ageExtent = d3.extent(median_age),
airportsScaleX,populationScaleX,median_ageScaleX,
airportsScaleY,populationScaleY,median_ageScaleY;
/* var airports = countries.map(function(country){ return +country.airports; });
var meanairports = d3.mean(airports),
airportsExtent = d3.extent(airports),
airportsScaleX,
airportsScaleY;*/
var continents = d3.set(countries.map(function(country) { return country.ContinentCode; }));
var continentColorScale = d3.scaleOrdinal(d3.schemeCategory10)
.domain(continents.values());
var width = 1200,
height = 800;
var svg,
circles,
circleSize = { min: 10, max: 80 };
var circleRadiusScale = d3.scaleSqrt()
.domain(airportsExtent)
.domain(populationExtent)
.domain(median_ageExtent)
.range([circleSize.min, circleSize.max]);
var forces,
forceSimulation;
createSVG();
toggleContinentKey(!flagFill());
createCirclesairports();
createCirclespopulation();
createCirclesmedian_age();
createForces();
createForceSimulation();
addFlagDefinitions();
addFillListenerairports();
addFillListenerpopulation();
addFillListenermedian_age();
addGroupingListeners();
function createSVG() {
svg = d3.select("#bubble-chart")
.append("svg")
.attr("width", width)
.attr("height", height);
}
function toggleContinentKey(showContinentKey) {
var keyElementWidth = 150,
keyElementHeight = 30;
var onScreenYOffset = keyElementHeight*1.5,
offScreenYOffset = 100;
if (d3.select(".continent-key").empty()) {
createContinentKey();
}
var continentKey = d3.select(".continent-key");
if (showContinentKey) {
translateContinentKey("translate(0," + (height - onScreenYOffset) + ")");
} else {
translateContinentKey("translate(0," + (height + offScreenYOffset) + ")");
}
function createContinentKey() {
var keyWidth = keyElementWidth * continents.values().length;
var continentKeyScale = d3.scaleBand()
.domain(continents.values())
.range([(width - keyWidth) / 2, (width + keyWidth) / 2]);
svg.append("g")
.attr("class", "continent-key")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.selectAll("g")
.data(continents.values())
.enter()
.append("g")
.attr("class", "continent-key-element");
d3.selectAll("g.continent-key-element")
.append("rect")
.attr("width", keyElementWidth)
.attr("height", keyElementHeight)
.attr("x", function(d) { return continentKeyScale(d); })
.attr("fill", function(d) { return continentColorScale(d); });
d3.selectAll("g.continent-key-element")
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) { return continentKeyScale(d) + keyElementWidth/2; })
.text(function(d) { return continentNames[d]; });
// The text BBox has non-zero values only after rendering
d3.selectAll("g.continent-key-element text")
.attr("y", function(d) {
var textHeight = this.getBBox().height;
// The BBox.height property includes some extra height we need to remove
var unneededTextHeight = 4;
return ((keyElementHeight + textHeight) / 2) - unneededTextHeight;
});
}
function translateContinentKey(translation) {
continentKey
.transition()
.duration(500)
.attr("transform", translation);
}
}
function flagFill() {
return isChecked("#flags");
}
function isChecked(elementID) {
return d3.select(elementID).property("checked");
}
/* function createCircles(){
createCirclesairport();
}*/
/* function createCircles() {
var formatairports = d3.format(","),formatpopulation = d3.format(","),formatmedian_age = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.airports),(d.population),(d.median_age); })
.on("mouseover", function(d) {
updateCountryInfo(d);
})
.on("mouseout", function(d) {
updateCountryInfo();
});
updateCircles();
function updateCountryInfo(country) {
var info = "";
if (country) {
info = [country.CountryName, formatairports(country.airports),formatpopulation(country.population),formatmedian_age(country.median_age)].join(": ");
}
d3.select("#country-info").html(info);
}
}*/
/* function updateCirclesairport(){
updateCircles();
}*/
function createCirclesairports() {
var formatairports = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.airports); })
.on("mouseover", function(d) {
updateCountryInfoairports(d);
})
.on("mouseout", function(d) {
updateCountryInfoairports();
});
updateCirclesairports();
function updateCountryInfoairports(country) {
var info = "";
if (country) {
info = [country.CountryName, formatairports(country.airports)].join(": ");
}
d3.select("#country-info").html(info);
}
}
function updateCirclesairports() {
circles
.attr("fill", function(d) {
return flagFill() ? "url(#" + d.CountryCode + ")" : continentColorScale(d.ContinentCode);
});
}
function createCirclespopulation() {
var formatpopulation = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.population); })
.on("mouseover", function(d) {
updateCountryInfopopulation(d);
})
.on("mouseout", function(d) {
updateCountryInfopopulation();
});
updateCirclespopulation();
function updateCountryInfopopulation(populationcountry) {
var info = "";
if (country) {
info = [country.CountryName, formatpopulation(country.population)].join(": ");
}
d3.select("#country-info").html(info);
}
}
function updateCirclespopulation() {
circles
.attr("fill", function(d) {
return flagFill() ? "url(#" + d.CountryCode + ")" : continentColorScale(d.ContinentCode);
});
}
function createCirclesmedian_age() {
var formatmedian_age = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.median_age); })
.on("mouseover", function(d) {
updateCountryInfomedian_age(d);
})
.on("mouseout", function(d) {
updateCountryInfomedian_age();
});
updateCirclesmedian_age();
function updateCountryInfomedian_age(country) {
var info = "";
if (country) {
info = [country.CountryName, formatmedian_age(country.median_age)].join(": ");
}
d3.select("#country-info").html(info);
}
}
function updateCirclesmedian_age() {
circles
.attr("fill", function(d) {
return flagFill() ? "url(#" + d.CountryCode + ")" : continentColorScale(d.ContinentCode);
});
}
/*function createForces(){
createForcesairport();
}
*/
function createForces() {
var forceStrength = 0.05;
forces = {
combine: createCombineForces(),
countryCenters: createCountryCenterForces(),
continent: createContinentForces(),
airports: createairportsForces(),
population: createpopulationForces(),
median_age: createmedian_ageForces(),
};
function createCombineForces() {
return {
x: d3.forceX(width / 2).strength(forceStrength),
y: d3.forceY(height / 2).strength(forceStrength)
};
}
function createCountryCenterForces() {
var projectionStretchY = 0.25,
projectionMargin = circleSize.max,
projection = d3.geoEquirectangular()
.scale((width / 2 - projectionMargin) / Math.PI)
.translate([width / 2, height * (1 - projectionStretchY) / 2]);
return {
x: d3.forceX(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[0];
}).strength(forceStrength),
y: d3.forceY(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[1] * (1 + projectionStretchY);
}).strength(forceStrength)
};
}
function createContinentForces() {
return {
x: d3.forceX(continentForceX).strength(forceStrength),
y: d3.forceY(continentForceY).strength(forceStrength)
};
function continentForceX(d) {
if (d.ContinentCode === "EU") {
return left(width);
} else if (d.ContinentCode === "AF") {
return left(width);
} else if (d.ContinentCode === "AS") {
return right(width);
} else if (d.ContinentCode === "NA" || d.ContinentCode === "SA") {
return right(width);
}
return center(width);
}
function continentForceY(d) {
if (d.ContinentCode === "EU") {
return top(height);
} else if (d.ContinentCode === "AF") {
return bottom(height);
} else if (d.ContinentCode === "AS") {
return top(height);
} else if (d.ContinentCode === "NA" || d.ContinentCode === "SA") {
return bottom(height);
}
return center(height);
}
function left(dimension) { return dimension / 4; }
function center(dimension) { return dimension / 2; }
function right(dimension) { return dimension / 4 * 3; }
function top(dimension) { return dimension / 4; }
function bottom(dimension) { return dimension / 4 * 3; }
}
function createairportsForces() {
var projectionStretchY = 0.25,
projectionMargin = circleSize.max,
projection = d3.geoEquirectangular()
.scale((width / 2 - projectionMargin) / Math.PI)
.translate([width / 2, height * (1 - projectionStretchY) / 2]);
var scaledairportsMargin = circleSize.max;
airportsScaleX = d3.scaleBand()
/*.domain(continentNamesDomain)*/
.range([scaledairportsMargin, width - scaledairportsMargin*2]);
airportsScaleY = d3.scaleLog()
.domain(airportsExtent)
.range([height - scaledairportsMargin, scaledairportsMargin*2]);
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var centerCirclesInScaleBandOffset = airportsScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[0];
}).strength(forceStrength),
y: d3.forceY(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[1] * (1 + projectionStretchY);
}).strength(forceStrength),
x: d3.forceX(function(d) {
return airportsScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return airportsScaleY(d.airports);
}).strength(forceStrength),
};
/*
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var scaledairportsMargin = circleSize.max;
airportsScaleX = d3.scaleBand()
.domain(continentNamesDomain)
.range([scaledairportsMargin, width - scaledairportsMargin*2]);
airportsScaleY = d3.scaleLog()
.domain(airportsExtent)
.range([height - scaledairportsMargin, scaledairportsMargin*2]);
var centerCirclesInScaleBandOffset = airportsScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return airportsScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return airportsScaleY(d.airports);
}).strength(forceStrength)
};*/
}
function createpopulationForces() {
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var scaledpopulationMargin = circleSize.max;
populationScaleX = d3.scaleBand()
.domain(continentNamesDomain)
.range([scaledpopulationMargin, width - scaledpopulationMargin*2]);
populationScaleY = d3.scaleLog()
.domain(populationExtent)
.range([height - scaledpopulationMargin, scaledpopulationMargin*2]);
var centerCirclesInScaleBandOffset = populationScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return populationScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return populationScaleY(d.population);
}).strength(forceStrength)
};
}
function createmedian_ageForces() {
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var scaledmedian_ageMargin = circleSize.max;
median_ageScaleX = d3.scaleBand()
.domain(continentNamesDomain)
.range([scaledmedian_ageMargin, width - scaledmedian_ageMargin*2]);
median_ageScaleY = d3.scaleLog()
.domain(median_ageExtent)
.range([height - scaledmedian_ageMargin, scaledmedian_ageMargin*2]);
var centerCirclesInScaleBandOffset = median_ageScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return median_ageScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return median_ageScaleY(d.median_age);
}).strength(forceStrength)
};
}
}
function createForceSimulation() {
forceSimulation = d3.forceSimulation()
.force("x", forces.combine.x)
.force("y", forces.combine.y)
.force("collide", d3.forceCollide(forceCollideairports))
.force("collide", d3.forceCollide(forceCollidepopulation))
.force("collide", d3.forceCollide(forceCollidemedian_age));
forceSimulation.nodes(countries)
.on("tick", function() {
circles
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
}
function forceCollideairports(d) {
return countryCenterGrouping() || airportsGrouping() ? 0 : circleRadiusScale(d.airports) + 1 ;
}
function forceCollidepopulation(d) {
return countryCenterGrouping() || populationGrouping() ? 0 : circleRadiusScale(d.population) + 1 ;
}
function forceCollidemedian_age(d) {
return countryCenterGrouping() || median_ageGrouping() ? 0 : circleRadiusScale(d.median_age) + 1 ;
}
function countryCenterGrouping() {
return isChecked("#country-centers");
}
function airportsGrouping() {
return isChecked("#airports");
}
function populationGrouping() {
return isChecked("#population");
}
function median_ageGrouping() {
return isChecked("#median_age");
}
function addFlagDefinitions() {
var defs = svg.append("defs");
defs.selectAll(".flag")
.data(countries)
.enter()
.append("pattern")
.attr("id", function(d) { return d.CountryCode; })
.attr("class", "flag")
.attr("width", "100%")
.attr("height", "100%")
.attr("patternContentUnits", "objectBoundingBox")
.append("image")
.attr("width", 1)
.attr("height", 1)
// xMidYMid: center the image in the circle
// slice: scale the image to fill the circle
.attr("preserveAspectRatio", "xMidYMid slice")
.attr("xlink:href", function(d) {
return "flags/" + d.CountryCode + ".svg";
});
}
/* function addFillListener(){
addFillListenerairport();
}
*/
function addFillListenerairports() {
d3.selectAll('input[name="fill"]')
.on("change", function() {
toggleContinentKey(!flagFill() && !airportsGrouping());
updateCirclesairports();
});
}
function addFillListenerpopulation() {
d3.selectAll('input[name="fill"]')
.on("change", function() {
toggleContinentKey(!flagFill() && !populationGrouping() );
updateCirclespopulation();
});
}
function addFillListenermedian_age() {
d3.selectAll('input[name="fill"]')
.on("change", function() {
toggleContinentKey(!flagFill() && !median_ageGrouping());
updateCirclesmedian_age();
});
}
function addGroupingListeners() {
addListener("#combine", forces.combine);
addListener("#country-centers", forces.countryCenters);
addListener("#continents", forces.continent);
addListener("#airports", forces.airports);
addListener("#population", forces.population);
addListener("#median_age", forces.median_age);
function addListener(selector, forces) {
d3.select(selector).on("click", function() {
updateForces(forces);
toggleContinentKey(!flagFill() && !airportsGrouping() && !populationGrouping() && !median_ageGrouping());
toggleairportsAxes(airportsGrouping()),
togglepopulationAxes(populationGrouping()),
togglemedian_ageAxes(median_ageGrouping());
});
}
function updateForces(forces) {
forceSimulation
.force("x", forces.x)
.force("y", forces.y)
.force("collide", d3.forceCollide(forceCollideairports))
.force("collide", d3.forceCollide(forceCollidepopulation))
.force("collide", d3.forceCollide(forceCollidemedian_age))
.alphaTarget(0.5)
.restart();
}
function toggleairportsAxes(showAxes) {
var onScreenXOffset = 40,
offScreenXOffset = -40;
var onScreenYOffset = 40,
offScreenYOffset = 100;
if (d3.select(".x-axis").empty()) {
createAxes();
}
var xAxis = d3.select(".x-axis"),
yAxis = d3.select(".y-axis");
if (showAxes) {
translateAxis(xAxis, "translate(0," + (height - onScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + onScreenXOffset + ",0)");
} else {
translateAxis(xAxis, "translate(0," + (height + offScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + offScreenXOffset + ",0)");
}
function createAxes() {
var numberOfTicks = 10,
tickFormat = ".0s";
var xAxis = d3.axisBottom(airportsScaleX)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.call(xAxis)
.selectAll(".tick text")
.attr("font-size", "16px");
var yAxis = d3.axisLeft(airportsScaleY)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + offScreenXOffset + ",0)")
.call(yAxis);
}
function translateAxis(axis, translation) {
axis
.transition()
.duration(500)
.attr("transform", translation);
}
}
function togglepopulationAxes(showAxes) {
var onScreenXOffset = 40,
offScreenXOffset = -40;
var onScreenYOffset = 40,
offScreenYOffset = 100;
if (d3.select(".x-axis").empty()) {
createAxes();
}
var xAxis = d3.select(".x-axis"),
yAxis = d3.select(".y-axis");
if (showAxes) {
translateAxis(xAxis, "translate(0," + (height - onScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + onScreenXOffset + ",0)");
} else {
translateAxis(xAxis, "translate(0," + (height + offScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + offScreenXOffset + ",0)");
}
function createAxes() {
var numberOfTicks = 10,
tickFormat = ".0s";
var xAxis = d3.axisBottom(populationScaleX)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.call(xAxis)
.selectAll(".tick text")
.attr("font-size", "16px");
var yAxis = d3.axisLeft(populationScaleY)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + offScreenXOffset + ",0)")
.call(yAxis);
}
function translateAxis(axis, translation) {
axis
.transition()
.duration(500)
.attr("transform", translation);
}
}
function togglemedian_ageAxes(showAxes) {
var onScreenXOffset = 40,
offScreenXOffset = -40;
var onScreenYOffset = 40,
offScreenYOffset = 100;
if (d3.select(".x-axis").empty()) {
createAxes();
}
var xAxis = d3.select(".x-axis"),
yAxis = d3.select(".y-axis");
if (showAxes) {
translateAxis(xAxis, "translate(0," + (height - onScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + onScreenXOffset + ",0)");
} else {
translateAxis(xAxis, "translate(0," + (height + offScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + offScreenXOffset + ",0)");
}
function createAxes() {
var numberOfTicks = 10,
tickFormat = ".0s";
var xAxis = d3.axisBottom(median_ageScaleX)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.call(xAxis)
.selectAll(".tick text")
.attr("font-size", "16px");
var yAxis = d3.axisLeft(median_ageScaleY)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + offScreenXOffset + ",0)")
.call(yAxis);
}
function translateAxis(axis, translation) {
axis
.transition()
.duration(500)
.attr("transform", translation);
}
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="style.css" rel="stylesheet">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-queue.v3.min.js"></script>
<script src="scriptpopulation.js"></script>
<title>D3 Country Bubble Chart</title>
</head>
<body>
<div id="controls">
<span>
<label><input id="country-centers" type="radio" name="grouping" value="country-centers-">Country Centers</label>
<label><input id="population" type="radio" name="grouping" value="population">population</label>
<label><input id="airports" type="radio" name="grouping" value="airports">Airportss</label>
<label><input id="median_age" type="radio" name="grouping" value="median_age">smedian_age</label>
</span>
<span>
<label><input id="colors" type="radio" name="fill" value="colors" checked>Colors</label>
<label><input id="flags" type="radio" name="fill" value="flags">Flags</label>
</span>
</div>
<div id="country-info"></div>
<div id="bubble-chart"></div>
<script>
d3.queue()
.defer(d3.csv, "countries.csv")
.defer(d3.json, "continent-names.json")
.await(createBubbleChart);
</script>
</body>
</html>
strong text

D3 stacked segment chart, sort by totals

I have been trying to create a stacked segment chart for the past few days and between all the trigonometry and key stacking it has truly been a nightmare for me to apply what seems to be the most basic of tweaks. Currently my segment chart has data that is sorted in descending order based on Active equity. I want to change this to have the data sorted by total.
const csvData = `State,Active equity,Passive equity,Fixed income,Mixed assets
BlackRock,1,17,0,0
Fidelity,13,2,0,0
SSgA,12,0,0,0
Hang Seng,11,0,0,0
UBS,9,0,0,1
Schroders,6,0,2,1
JP Morgan,5,2,0,1
Value Partners,1,0,6,0
First State,5,0,0,0
Invesco,4,1,0,0
HSBC,1,1,1,1
DBS,0,2,1,0
BOCI,1,1,1,0
CSOP,0,2,1,0
Principal,1,1,0,0
Allianz,2,1,0,0
Yuanta,0,2,1,0
Manulife,1,0,1,0
Aberdeen,2,0,0,0
Mirae,1,1,0,0
,0,0,0,0`;
//const data = d3.csvParse(csvData, d3.autoType);
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(250,250)");
var x = d3.scaleBand()
.range([0, 2 * Math.PI])
.align(0);
var y = d3.scaleRadial()
.range([innerRadius, outerRadius]);
var z = d3.scaleOrdinal()
.range(["#003366", "#4f81b9", "#95b3d7", "#f6d18b"]);
d3.csv("csvData", function(d, i, columns) {
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
}, function(error, data) {
if (error) throw error;
weave(data, function(a, b) { return b[data.columns[6]] - a[data.columns[6]]; });
x.domain(data.map(function(d) { return d.State; }));
y.domain([0, d3.max(data, function(d) { return d.total; })*1.3]);
z.domain(data.columns.slice(1));
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc2")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius+2)
.startAngle(function(d) { return x(d.data.State); })
.endAngle(function(d) { return x(d.data.State) + x.bandwidth()*.90; })
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class','bg-arc2')
.attr('fill','none')
.attr('stroke-width','4px')
.attr('stroke','#003366');
graphGroup.append('circle')
.attr('cx',0)
.attr('cy',0)
.attr('r',200)
.style('fill','#d9d9d9');
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(function(d) { return x(d.data.State); })
.endAngle(function(d) { return x(d.data.State) + x.bandwidth()*.95; })
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class','bg-arc')
.attr('fill','#fff');
graphGroup.append('circle')
.attr('cx',0)
.attr('cy',0)
.attr('r',innerRadius)
.style('fill','#fff');
var stackedData = d3.stack().keys(data.columns.slice(1))(data);
var stackedData2 = stackedData.sort(function(a,b) { return d3.descending(a[0].data.total, b[0].data.total)});
console.log(stackedData[0][0].data.total)
console.log(stackedData2);
graphGroup.append("g")
.selectAll("g")
.data(stackedData)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("path")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(function(d) { return y(d[0]); })
.outerRadius(function(d) { return y(d[1]); })
.startAngle(function(d) { return x(d.data.State); })
.endAngle(function(d) { return x(d.data.State) + x.bandwidth()*.95; })
.padAngle(0.04)
.padRadius(innerRadius));
var label = graphGroup.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "rotate(" + ((x(d.State) + x.bandwidth() / 2) * 180 / Math.PI - 90) + ")translate(" + (outerRadius+25) + ",0)"; });
label.append("text")
.attr("transform", function(d) { return (x(d.State) + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI) < Math.PI ? "rotate(90)translate(0,16)" : "rotate(-90)translate(0,-9)"; })
.text(function(d) { return d.State; });
var yAxis = graphGroup.append("g")
.attr("text-anchor", "end");
var yTick = yAxis
.selectAll("g")
.data(y.ticks(10).slice(1))
.enter().append("g");
});
function weave(array, compare) {
var i = -1, j, n = array.sort(compare).length, weave = new Array(n);
while (++i < n) weave[i] = array[(j = i << 1) >= n ? (n - i << 1) - 1 : j];
while (--n >= 0) array[n] = weave[n];
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://gist.githubusercontent.com/mbostock/3686329aa6e1f5938df8eef12ec353fe/raw/1ab722df937c3ac86cac8292e34cfc7279b017f8/d3-scale-radial.js"></script>
Relevant code here:
var stackedData = d3.stack().keys(data.columns.slice(1))(data);
var stackedData2 = stackedData.sort(function(a,b) { return d3.descending(a[0].data.total, b[0].data.total)});
console.log(stackedData[0][0].data.total)
console.log(stackedData2);
I checked via the console log to make sure I was slicing at the correct place, which I was, as confirmed by console.log(stackedData[0][0].data.total) which returned the correct value of 18.
However I can't apply the sort as desired. The data is still sorted by Active equity and not total.
Question
The default sort for stacked radial charts seems to be whatever the first variable is. In my case, it's Active equity. With that in mind, based off my progress above, what is keeping me from applying the descending order sort by data.total as opposed to the default?
Your question is not clear: are you talking about sorting the segments within each slice, or are you talking about sorting the slices themselves?
For the first case, there is an method named order, that you can use with the stack generator (the link goes to v5 docs, which are a bit different from v4). However, because you said "I want to change [the order] to have the data sorted by total", it seems to me that you're talking about sorting the slices. If that is correct, two observations: it's not sorted by Active equity, right now it's just the order of the objects in the original data array.
For sorting by total you just need to change that array:
data.sort(function(a, b) {
return b.total - a.total;
});
Also, get rid of the weave function.
Here is the result:
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("d3-scale")) :
typeof define === "function" && define.amd ? define(["exports", "d3-scale"], factory) :
(factory(global.d3 = global.d3 || {}, global.d3));
}(this, function(exports, d3Scale) {
'use strict';
function square(x) {
return x * x;
}
function radial() {
var linear = d3Scale.scaleLinear();
function scale(x) {
return Math.sqrt(linear(x));
}
scale.domain = function(_) {
return arguments.length ? (linear.domain(_), scale) : linear.domain();
};
scale.nice = function(count) {
return (linear.nice(count), scale);
};
scale.range = function(_) {
return arguments.length ? (linear.range(_.map(square)), scale) : linear.range().map(Math.sqrt);
};
scale.ticks = linear.ticks;
scale.tickFormat = linear.tickFormat;
return scale;
}
exports.scaleRadial = radial;
Object.defineProperty(exports, '__esModule', {
value: true
});
}));
const csvData = `State,Active equity,Passive equity,Fixed income,Mixed assets
BlackRock,1,17,0,0
Fidelity,13,2,0,0
SSgA,12,0,0,0
Hang Seng,11,0,0,0
UBS,9,0,0,1
Schroders,6,0,2,1
JP Morgan,5,2,0,1
Value Partners,1,0,6,0
First State,5,0,0,0
Invesco,4,1,0,0
HSBC,1,1,1,1
DBS,0,2,1,0
BOCI,1,1,1,0
CSOP,0,2,1,0
Principal,1,1,0,0
Allianz,2,1,0,0
Yuanta,0,2,1,0
Manulife,1,0,1,0
Aberdeen,2,0,0,0
Mirae,1,1,0,0
,0,0,0,0`;
const data = d3.csvParse(csvData, function(d, i, columns) {
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
});
data.sort(function(a, b) {
return b.total - a.total;
});
var margins = {
top: 20,
bottom: 300,
left: 30,
right: 100
};
var height = 600;
var width = 900;
var totalWidth = width + margins.left + margins.right;
var totalHeight = height + margins.top + margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(250,250)");
var x = d3.scaleBand()
.range([0, 2 * Math.PI])
.align(0);
var y = d3.scaleRadial()
.range([innerRadius, outerRadius]);
var z = d3.scaleOrdinal()
.range(["#003366", "#4f81b9", "#95b3d7", "#f6d18b"]);
x.domain(data.map(function(d) {
return d.State;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
}) * 1.3]);
z.domain(data.columns.slice(1));
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc2")
.data(function(d) {
return d;
})
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius + 2)
.startAngle(function(d) {
return x(d.data.State);
})
.endAngle(function(d) {
return x(d.data.State) + x.bandwidth() * .90;
})
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class', 'bg-arc2')
.attr('fill', 'none')
.attr('stroke-width', '4px')
.attr('stroke', '#003366');
graphGroup.append('circle')
.attr('cx', 0)
.attr('cy', 0)
.attr('r', 200)
.style('fill', '#d9d9d9');
graphGroup.append('g')
.selectAll('g')
.data(d3.stack().keys(data.columns.slice(1))(data))
.enter().append("g")
.selectAll(".bg-arc")
.data(function(d) {
return d;
})
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(function(d) {
return x(d.data.State);
})
.endAngle(function(d) {
return x(d.data.State) + x.bandwidth() * .95;
})
.padAngle(0.1)
.padRadius(innerRadius))
.attr('class', 'bg-arc')
.attr('fill', '#fff');
graphGroup.append('circle')
.attr('cx', 0)
.attr('cy', 0)
.attr('r', innerRadius)
.style('fill', '#fff');
var stackedData = d3.stack()
.keys(data.columns.slice(1))
(data);
graphGroup.append("g")
.selectAll("g")
.data(stackedData)
.enter().append("g")
.attr("fill", function(d) {
return z(d.key);
})
.selectAll("path")
.data(function(d) {
return d;
})
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(function(d) {
return y(d[0]);
})
.outerRadius(function(d) {
return y(d[1]);
})
.startAngle(function(d) {
return x(d.data.State);
})
.endAngle(function(d) {
return x(d.data.State) + x.bandwidth() * .95;
})
.padAngle(0.04)
.padRadius(innerRadius));
var label = graphGroup.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "rotate(" + ((x(d.State) + x.bandwidth() / 2) * 180 / Math.PI - 90) + ")translate(" + (outerRadius + 25) + ",0)";
});
label.append("text")
.attr("transform", function(d) {
return (x(d.State) + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI) < Math.PI ? "rotate(90)translate(0,16)" : "rotate(-90)translate(0,-9)";
})
.text(function(d) {
return d.State;
});
var yAxis = graphGroup.append("g")
.attr("text-anchor", "end");
var yTick = yAxis
.selectAll("g")
.data(y.ticks(10).slice(1))
.enter().append("g");
function weave(array, compare) {
var i = -1,
j, n = array.sort(compare).length,
weave = new Array(n);
while (++i < n) weave[i] = array[(j = i << 1) >= n ? (n - i << 1) - 1 : j];
while (--n >= 0) array[n] = weave[n];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

How to pass data from Vue js method scope to external JS file?

This my component code of vue js
<template>
<div class="grapha">
<div id="chart2"></div>
</div>
</template>
<script>
// var apiURL = 'https://jsonplaceholder.typicode.com/users';
var apiURL = 'http://localhost:3000/db';
export default {
name: 'grapha',
data () {
return {
users:[]
}
},
methods: {
fetchData: function () {
var self = this;
$.get( apiURL, function( data ) {
self.users = data;
});
}
},
created: function (){
this.fetchData();
}
}
</script>
Here is my d3 combo chart code , here is a variable named Data takes values and shows it on graph.
Now, I want to get data from self.users (vue js component) to pass it on data variable ( external function ). Could you suggest me what would be the possible way to do that ?
function getTextWidth(text, fontSize, fontName) {
c = document.createElement("canvas");
ctx = c.getContext("2d");
ctx.font = fontSize + ' ' + fontName;
return ctx.measureText(text).width;
}
function DataSegregator(array, on) {
var SegData;
OrdinalPositionHolder = {
valueOf: function () {
thisObject = this;
keys = Object.keys(thisObject);
keys.splice(keys.indexOf("valueOf"), 1);
keys.splice(keys.indexOf("keys"), 1);
return keys.length == 0 ? -1 : d3.max(keys, function (d) { return thisObject[d] })
}
, keys: function () {
keys = Object.keys(thisObject);
keys.splice(keys.indexOf("valueOf"), 1);
keys.splice(keys.indexOf("keys"), 1);
return keys;
}
}
array[0].map(function (d) { return d[on] }).forEach(function (b) {
value = OrdinalPositionHolder.valueOf();
OrdinalPositionHolder[b] = OrdinalPositionHolder > -1 ? ++value : 0;
})
SegData = OrdinalPositionHolder.keys().map(function () {
return [];
});
array.forEach(function (d) {
d.forEach(function (b) {
SegData[OrdinalPositionHolder[b[on]]].push(b);
})
});
return SegData;
}
Data = self.users.comboChart;
var margin = { top: 20, right: 30, bottom: 60, left: 40 },
width = 800 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var textWidthHolder = 0;
/// Adding Date in LineCategory
Data.forEach(function (d) {
d.LineCategory.forEach(function (b) {
b.Date = d.Date;
})
});
var Categories = new Array();
// Extension method declaration
// Categories.pro;
var Data;
var ageNames;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var XLine = d3.scale.ordinal()
.rangeRoundPoints([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var YLine = d3.scale.linear().range([height, 0])
.domain([0, d3.max(Data, function (d) { return d3.max(d.LineCategory, function (b) { return b.Value }) })]);
var color = d3.scale.ordinal()
.range(["#6aae6a", "#639ce4", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var line = d3.svg.line().x(function (d) {
return x0(d.Date) + x0.rangeBand() / 2;
}).y(function (d) { return YLine(d.Value) });
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
// var yAxis = d3.svg.axis()
// .scale(y)
// .orient("left")
// .tickFormat(d3.format(".2s"));
// var YLeftAxis = d3.svg.axis().scale(YLine).orient("right").tickFormat(d3.format(".2s"));
var svg = d3.select("#chart2").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 + ")");
// Bar Data categories
Data.forEach(function (d) {
d.Categories.forEach(function (b) {
if (Categories.findIndex(function (c) { return c.Name===b.Name}) == -1) {
b.Type = "bar";
// console.log(JSON.stringify(b))
Categories.push(b)
}
})
});
// Line Data categories
Data.forEach(function (d) {
d.LineCategory.forEach(function (b) {
if (Categories.findIndex(function (c) { return c.Name === b.Name }) == -1) {
b.Type = "line";
// console.log(JSON.stringify(b))
Categories.push(b)
}
})
});
// Processing Line data
lineData = DataSegregator(Data.map(function (d) { return d.LineCategory }), "Name");
// Line Coloring
LineColor = d3.scale.ordinal();
LineColor.domain(Categories.filter(function (d) { return d.Type == "line" }).map(function (d) { return d.Name }));
LineColor.range(["#333471", "#386a07", "#7f8ed4", "#671919", "#0b172b"])
x0.domain(Data.map(function (d) { return d.Date; }));
XLine.domain(Data.map(function (d) { return d.Date; }));
x1.domain(Categories.filter(function (d) { return d.Type == "bar" }).map(function (d) { return d.Name})).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(Data, function (d) { return d3.max(d.Categories, function (d) { return d.Value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var state = svg.selectAll(".state")
.data(Data)
.enter().append("g")
.attr("class", "state")
.attr("transform", function (d) { return "translate(" + x0(d.Date) + ",0)"; });
state.selectAll("rect")
.data(function (d) { return d.Categories; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function (d) { return x1(d.Name); })
.attr("y", function (d) { return y(d.Value); })
//.attr("height", function (d) { return height - y(d.Value); })
.style("fill", function (d) { return color(d.Name); })
.transition().delay(500).attrTween("height", function (d) {
var i = d3.interpolate(0, height - y(d.Value));
return function (t)
{
return i(t);
}
});
// drawaing lines
svg.selectAll(".lines").data(lineData).enter().append("g").attr("class", "line")
.each(function (d) {
Name=d[0].Name
d3.select(this).append("path").attr("d", function (b) { return line(b) }).style({ "stroke-width": "3px", "fill": "none" }).style("stroke", LineColor(Name)).transition().duration(1500);
})
// Legends
var LegendHolder = svg.append("g").attr("class", "legendHolder");
var legend = LegendHolder.selectAll(".legend")
.data(Categories.map(function (d) { return {"Name":d.Name,"Type":d.Type}}))
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) { return "translate(0," +( height+ margin.bottom/2 )+ ")"; })
.each(function (d,i) {
// Legend Symbols
d3.select(this).append("rect")
.attr("width", function () { return 18 })
.attr("x", function (b) {
left = (i+1) * 15 + i * 18 + i * 5 + textWidthHolder;
return left;
})
.attr("y", function (b) { return b.Type == 'bar'?0:7})
.attr("height", function (b) { return b.Type== 'bar'? 18:5 })
.style("fill", function (b) { return b.Type == 'bar' ? color(d.Name) : LineColor(d.Name) });
// Legend Text
d3.select(this).append("text")
.attr("x", function (b) {
left = (i+1) * 15 + (i+1) * 18 + (i + 1) * 5 + textWidthHolder;
return left;
})
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(d.Name);
textWidthHolder += getTextWidth(d.Name, "10px", "calibri");
});
// Legend Placing (center)
d3.select(".legendHolder").attr("transform", function (d) {
thisWidth = d3.select(this).node().getBBox().width;
return "translate(" + ((width) / 2 - thisWidth / 2) + ",0)";
})
// round the rectangle corners
svg.selectAll('rect').attr('rx', 5).attr('ry', 5);
You can achieve by using Using Javascript's custom event feature
We need to register an event, globally with document as follows
Registering Event
document.addEventListener("updateUser", function(e) {
console.info("Event is: ", e);
console.info("Custom data is: ", e.detail);
// Place your logic to operate with new data
})
The above snippet needs to be placed in your d3 script.
Emitting the custom event
var myEvent = new CustomEvent("updateUser", {
detail: data // Your data from vuejs part
});
// Trigger it!
document.dispatchEvent(myEvent);

How do you rotate the x and y axis in D3 bar chart

I am trying to figure out how to have a horizontal bar chart instead of a vertical. I have watched a video to try to explain how to do this, as well as looked at forums and other D3 codes, but I still can't figure it out. Here is my code below.
<script>
var data = [
{
skill:"FBSO",
TEAM:57,
OPP:50
},
{
skill:"SO",
TEAM:73,
OPP:61
},
{
skill:"ModSO",
TEAM:69,
OPP:57
},
{
skill:"ErndSO",
TEAM:67,
OPP:52
},
{
skill:"FBPS",
TEAM:35,
OPP:25
},
{
skill:"PS",
TEAM:43,
OPP:29
}
];
var margin = {
top: 20,
right: 20,
bottom: 40,
left: 60
},
width = 450 - margin.left - margin.right,
height = 315 - margin.top - margin.bottom,
that = this;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .3);
var x2 = d3.scale.ordinal().rangeRoundBands([0, width], .3);
var y = d3.scale.linear().rangeRound([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var xAxis2 = d3.svg.axis().scale(x).orient("top");
var yAxis = d3.svg.axis().scale(x).orient("left");
var yAxis2 = d3.svg.axis().scale(x).orient("right");
// var yAxis = d3.svg.axis().scale(y).orient("left").tickFormat(d3.format(".0%"));
var svg = d3.select(".viz-portfolio-delinquent-status").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 + ")");
color.domain(d3.keys(data[0]).filter(function (key) {
return key !== "interest_rate";
}));
data.forEach(function (d) {
var y0 = 0;
d.rates = color.domain().map(function (name) {
// console.log();
// ;
return {
name: name,
y0: y0,
y1: y0 += +d[name],
amount: d[name]
};
});
d.rates.forEach(function (d) {
d.y0 /= y0;
d.y1 /= y0;
});
// console.log(data);
});
data.sort(function (a, b) {
return b.rates[0].y1 - a.rates[0].y1;
});
x.domain(data.map(function (d) {
return d.interest_rate;
}));
svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis);
svg.append('g').attr('class', 'x axis').attr('transform', 'translate(0,'+ height/375 +')').call(xAxis2);
svg.append("g").attr("class", "x axis").attr("transform", "translate(" + width + ",0)").call(yAxis2);
svg.append('g').attr('class', 'y axis').attr('transform', 'translate('+ height/375 +',0)').call(yAxis);
// svg.append("g").attr("class", "y axis").call(yAxis);
var interest_rate = svg.selectAll(".interest-rate").data(data).enter().append("g").attr("class", "interest-rate").attr("transform", function (d) {
// conosole.log(d)
return "translate(" + x(d.interest_rate) + ",0)";
});
interest_rate.selectAll("rect")
.data(function (d) {
return d.rates;
})
.enter()
.append("rect")
.attr("width", x.rangeBand())
.attr("y", function (d) {
return y(d.y1);
})
.attr("height", function (d) {
// console.log(d)
return y(d.y0) - y(d.y1);
})
.style("fill", function (d) {
return color(d.name);
})
.on('mouseover', function (d) {
var total_amt;
total_amt = d.amount;
// console.log('----');
// d3.select(".chart-tip").style('opacity', '1').html('Amount: <strong>$' + that.numberWithCommas(total_amt.toFixed(2)) + '</strong>');
}).on('mouseout', function () {
d3.select(".chart-tip").style('opacity', '0');
});
I am sure it isn't too difficult, I just can't figure which x's and y's I need to change. Thanks!
So I figured it out somewhat. I rotated the svg that my plot was on so that it visually showed the x axis as the y axis, and vice versa.
svg {
transform: rotate(90deg);
}
This will make things difficult, as far as adding text on top of the bar chart, and it will make your height act as width, but it is a decent temporary fix.

How to make y-scale dynamic in d3 bar chart?

I'm facing difficulty to manage the Y-Scale in d3 bar chart.
I want to make y-scale dynamic according the data but don't want to exceed the points [ticks] more then 4 in positive and 4 in negative and 1 zero line [total 9]. Right now in my fiddle the values of ticks is keep changing according the data. Sometime its plot 2 ticks or sometime 4.
Here is my fiddle
var data = [["Since Mar 10, 2015",6], ["1 year",2], ["3 year",-10], ["Since Mar 10, 2010",1]];
d3.select("#example")
.datum(data)
.call(columnChart()
.width(320)
.height(240)
.x(function(d, i) { return d[0]; })
.y(function(d, i) { return d[1]; }));
function columnChart() {
var margin = {top: 30, right: 10, bottom: 50, left: 50},
width = 20,
height = 20,
xRoundBands = 0.6,
xValue = function(d) { return d[0]; },
yValue = function(d) { return d[1]; },
xScale = d3.scale.ordinal(),
yScale = d3.scale.linear(),
yAxis = d3.svg.axis().scale(yScale).orient("left"),
xAxis = d3.svg.axis().scale(xScale);
var isNegative = false;
function chart(selection) {
selection.each(function(data) {
// Convert data to standard representation greedily;
// this is needed for nondeterministic accessors.
for(var i=0; i< data.length; i++){
if(data[i][1] < 0){
isNegative = true;
}
}
data = data.map(function(d, i) {
return [xValue.call(data, d, i), yValue.call(data, d, i)];
});
// Update the x-scale.
xScale
.domain(data.map(function(d) { return d[0];} ))
.rangeRoundBands([0, width - margin.left - margin.right], xRoundBands);
var min = d3.min(data, function(d) { return d[1]; });
var max = d3.max(data, function(d) { return d[1]; });
// alert(min);
yScale.domain([d3.min(data, function(d) { return d[1]; }), d3.max(data, function(d) { return d[1]; })])
.range([height - margin.top - margin.bottom, 0])
.nice();
// All Positive
if(min > 0) {
yScale.domain([0, max]);
} else if(max < 0) {
yScale.domain([min, 0]);
}
// Select the svg element, if it exists.
var svg = d3.select(this).selectAll("svg").data([data]);
// Otherwise, create the skeletal chart.
var gEnter = svg.enter().append("svg").append("g");
gEnter.append("g").attr("class", "y axis");
gEnter.append("g").attr("class", "x axis");
gEnter.append("g").attr("class", "x axis zero");
// Update the outer dimensions.
svg .attr("width", width)
.attr("height", height);
// Update the inner dimensions.
var g = svg.select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Update the y-axis.
g.select(".y.axis")
.call(yAxis.tickSize(0).ticks(5))
.selectAll("g")
.selectAll("text")
.text(function(d){
return d+"%";
});
g.append("g")
.selectAll("line.line")
.data(yScale.ticks(5))
.enter()
.append("line")
.attr(
{
"class":"line grid tick",
"x1" : 0,
"x2" : ( width - 60 ),
"y1" : function(d){ return yScale(d);},
"y2" : function(d){ return yScale(d);},
});
gEnter.append("g").attr("class", "bars");
// Update the bars.
var bar = g.select(".bars")
.selectAll(".bar")
.data(data);
bar.enter().append("rect");
bar.exit().remove();
bar .attr("class", function(d, i) { return d[1] < 0 ? "bar negative" : "bar positive"; })
.attr("x", function(d) { return X(d); })
.attr("y", function(d, i) { return d[1] < 0 ? Y0() : Y(d); })
.attr("width", xScale.rangeBand())
.attr("height", function(d, i) { return Math.abs( Y(d) - Y0() ); });
// x axis at the bottom of the chart
if( isNegative === true ){
var xScaleHeight = height - margin.top - margin.bottom+12;
}else{
var xScaleHeight = height - margin.top - margin.bottom;
}
g.select(".x.axis")
.attr("transform", "translate(0," + ( xScaleHeight ) + ")")
.call(xAxis.orient("bottom"))
.selectAll("text")
.call(wrap, xScale.rangeBand());
// zero line
g.select(".x.axis.zero")
.attr("transform", "translate(0," + Y0() + ")")
.attr("class", "zero axis")
.call(xAxis.tickFormat("").tickSize(0));
// Update the text in bars.
var bar1 = svg.select(".bars").selectAll("text").data(data);
bar1 .data(data)
.enter()
.append("text")
.attr("class", "text")
.text(function(d) { return d[1]+"%"; })
.attr("x", function(d) { return X(d); })
.attr("y", function(d, i) { return d[1] < 0 ? Math.abs(Y(d)+10) : Y(d)-2; });
});
}
// Custom function for text wrap
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > 55) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
// The x-accessor for the path generator; xScale ∘ xValue.
function X(d) {
return xScale(d[0]);
}
function Y0() {
return yScale(0);
}
// The x-accessor for the path generator; yScale ∘ yValue.
function Y(d) {
return yScale(d[1]);
}
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.x = function(_) {
if (!arguments.length) return xValue;
xValue = _;
return chart;
};
chart.y = function(_) {
if (!arguments.length) return yValue;
yValue = _;
return chart;
};
return chart;
}
Thanks in advance :)

Categories