[英]D3 Grouped Bar Chart From Arrays
我真的在使用 D3 時遇到了問題,需要一些幫助,將我現有的條形圖更改為分組條形圖 條形圖正在工具提示中使用,目前看起來像:
每種顏色代表一個行業部門(粉紅色 = 零售,藍綠色 = 雜貨......等)。 我需要更改條形圖,以便將每個行業的百分比變化與該行業的世界平均百分比變化進行比較。
目前正在從一組數據創建條形圖。 我還有一個包含世界百分比值的數組。
所以想象一下:
countryData = [10,-20,-30,-63,-23,20],worldData = [23,-40,-23,-42,-23,40]
其中指數 0 = 零售業,指數 1 = 雜貨業等。
我需要 plot 將每個部門與世界平均水平進行比較的分組條形圖(以紅色顯示世界平均水平)。 這有點難以解釋,所以我為您畫了它(......請原諒偽劣的圖)。
請問有人可以幫我更改現有的工具提示嗎? 這是當前代碼。 如果要模擬數據值的變化。 如果你想廢棄我現有的代碼,那很好。
.on('mouseover', ({ properties }) => {
// get county data
const mobilityData = covid.data[properties[key]] || {};
const {
retailAverage,
groceryAverage,
parksAverage,
transitAverage,
workplaceAverage,
residentialAverage,
} = getAverage(covid1);
let avgArray = [retailAverage, groceryAverage, parksAverage, transitAverage, workplaceAverage, retailAverage];
let categoriesNames = ["Retail", "Grocery", "Parks", "Transit", "Workplaces", "Residential"];
// create tooltip
div = d3.select('body')
.append('div')
.attr('class', 'tooltip')
.style('opacity', 0);
div.html(properties[key]);
div.transition()
.duration(200)
.style('opacity', 0.9);
// calculate bar graph data for tooltip
const barData = [];
Object.keys(mobilityData).forEach((industry) => {
const stringMinusPercentage = mobilityData[industry].slice(0, -1);
barData.push(+stringMinusPercentage); // changing it to an integer value, from string
});
//combine the two lists for the combined bar graph
var combinedList = [];
for(var i = 0; i < barData.length; i++) {
const stringMinusPercentage2 = +(avgArray[i].slice(0, -1));
const object = {category: categoriesNames[i], country: barData[i], world: stringMinusPercentage2}
combinedList.push(object); //Push object into list
}
console.log(combinedList);
// barData = barData.sort(function (a, b) { return a - b; });
// sort into ascending ^ keeping this in case we need it later
const height2 = 220;
const width2 = 250;
const margin = {
left: 50, right: 10, top: 20, bottom: 15,
};
// create bar chart svg
const svgA = div.append('svg')
.attr('height', height2)
.attr('width', width2)
.style('border', '1px solid')
.append('g')
// apply the margins:
.attr('transform', `translate(${[`${margin.left},${margin.top}`]})`);
const barWidth = 30; // Width of the bars
// plot area is height - vertical margins.
const chartHeight = height2 - margin.top - margin.left;
// set the scale:
const yScale = d3.scaleLinear()
.domain([-100, 100])
.range([chartHeight, 0]);
// draw some rectangles:
svgA
.selectAll('rect')
.data(barData)
.enter()
.append('rect')
.attr('x', (d, i) => i * barWidth)
.attr('y', (d) => {
if (d < 0) {
return yScale(0); // if the value is under zero, the top of the bar is at yScale(0);
}
return yScale(d); // otherwise the rectangle top is above yScale(0) at yScale(d);
})
.attr('height', (d) => Math.abs(yScale(0) - yScale(d))) // the height of the rectangle is the difference between the scale value and yScale(0);
.attr('width', barWidth)
.style('fill', (d, i) => colours[i % 6]) // colour the bars depending on index
.style('stroke', 'black')
.style('stroke-width', '1px');
// Labelling the Y axis
const yAxis = d3.axisLeft(yScale);
svgA.append('text')
.attr('class', 'y label')
.attr('text-anchor', 'end')
.attr('x', -15)
.attr('y', -25)
.attr('dy', '-.75em')
.attr('transform', 'rotate(-90)')
.text('Percentage Change (%)');
svgA.append('g')
.call(yAxis);
})
.on('mouseout', () => {
div.style('opacity', 0);
div.remove();
})
.on('mousemove', () => div
.style('top', `${d3.event.pageY - 140}px`)
.style('left', `${d3.event.pageX + 15}px`));
svg.append('g')
.attr('transform', 'translate(25,25)')
.call(colorLegend, {
colorScale,
circleRadius: 10,
spacing: 30,
textOffset: 20,
});
};
drawMap(svg1, geoJson1, geoPath1, covid1, key1, 'impact1');
drawMap(svg2, geoJson2, geoPath2, covid2, key2, 'impact2');
};
簡而言之,我建議您對 x 軸使用兩個波段刻度。 我附上了一個顯示解決方案的代碼片段。 享受;)
//Assuming the following data final format var finalData = [ { "groupKey": "Retail", "sectorValue": 70, "worldValue": 60 }, { "groupKey": "Grocery", "sectorValue": 90, "worldValue": 90 }, { "groupKey": "other", "sectorValue": -20, "worldValue": 30 } ]; var colorRange = d3.scaleOrdinal().range(["#00BCD4", "#FFC400", "#ECEFF1"]); var subGroupKeys = ["sectorValue", "worldValue"]; var svg = d3.select("svg"); var margin = {top: 20, right: 20, bottom: 30, left: 40}; var width = +svg.attr("width") - margin.left - margin.right; var height = +svg.attr("height") - margin.top - margin.bottom; var container = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // The scale spacing the groups, your "sectors": var x0 = d3.scaleBand().domain(finalData.map(d => d.groupKey)).rangeRound([0, width]).paddingInner(0.1); // The scale for spacing each group's bar, your "sector bar": var x1 = d3.scaleBand().domain(subGroupKeys).rangeRound([0, x0.bandwidth()]).padding(0.05); var yScale = d3.scaleLinear().domain([-100, 100]).rangeRound([height, 0]); //and then you will need to append both, groups and bars var groups = container.append('g').selectAll('g').data(finalData, d => d.groupKey).join("g").attr("transform", (d) => "translate(" + x0(d.groupKey) + ",0)"); //define groups bars, one per sub group var bars = groups.selectAll("rect").data(d => subGroupKeys.map(key => ({ key, value: d[key], groupKey: d.groupKey })), (d) => "" + d.groupKey + "_" + d.key).join("rect").attr("fill", d => colorRange(d.key)).attr("x", d => x1(d.key)).attr("width", (d) => x1.bandwidth()).attr('y', (d) => Math.min(yScale(0), yScale(d.value))).attr('height', (d) => Math.abs(yScale(0) - yScale(d.value))); //append x axis container.append("g").attr("class", "axis").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x0)); //append y axis container.append("g").attr("class", "y axis").call(d3.axisLeft(yScale)).append("text").attr("x", 2).attr("y", yScale(yScale.ticks().pop()) + 0.5).attr("dy", "0.32em").attr("fill", "#000").attr("font-weight", "bold").attr("text-anchor", "start").text("Values");
<script src="https://d3js.org/d3.v7.min.js"></script> <svg width="600" height="400"></svg>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.