我正在尝试完成一些条形图的较小倍数系列,但为了使它们正确呈现,我想念最后的细节。现在的问题是,它无法呈现条形图所期望的所有值,并且我无法确定代码存在的问题。
这是我的csv文件:
media_outlet,positive,negative,balanced,informational,total
La Opinión,149,296,142,101,688
Wall Street Journal,137,118,125,79,459
Univision,226,484,225,159,1094
San Diego Union Tribune,60,24,18,17,119
Fox News,73,102,58,60,293
Washington Post,52,97,56,50,255
CNN,127,160,102,88,477
USA Today,32,23,14,22,91
The Daily Beast,9,50,13,10,82
Bloomberg,251,183,158,119,711
Fusion,48,86,54,49,237
NPR,20,30,12,14,76
Dallas Morning News,40,34,24,31,129
TIME,26,30,17,17,90
Forbes,97,56,72,37,262
Christian Science Monitor,19,15,21,7,62
NBC News,23,34,19,22,98
Huffington Post,232,344,219,85,880
New York TImes,90,129,74,62,355
Houston Chronicle,40,32,31,24,127
Los Angeles Times,66,75,45,45,231
San Antonio Express News,28,22,14,16,80
Arizona Daily Star,32,15,6,8,61
Vice News,17,169,44,12,242
这是我正在编写的用于渲染较小倍数的代码:
d3.csv('../data/media_tendency.csv')
.then(function(data) {
data.forEach(function(d) {
d.positive = +d.positive;
d.negative = +d.negative;
d.balanced = +d.balanced;
d.informational = +d.informational;
d.total = +d.total;
});
//console.log(data);
outlets(data);
})
.catch(function(error) {
console.log(error);
});
function outlets(newsData) {
//console.log(newsData);
const data = newsData.sort(function(a, b) {
if (a.total < b.total) {
return 1;
} else {
return -1;
}
});
//console.log(data);
const groups = d3
.nest()
.key(function(d) {
return d.media_outlet;
})
.entries(data);
console.log(groups);
const colors = ['#5cdacc', '#ff1d34', '#ffc750', '#ff8c50'];
const margin = { top: 40, right: 50, bottom: 40, left: 50 };
const width = 310 - margin.left - margin.right;
const height = 150 - margin.top - margin.bottom;
const svgs = d3
.select('#outlets-viz')
.selectAll('svg')
.data(groups)
.enter()
.append('svg')
.attr('class', 'media-svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
const tValues = ['P', 'N', 'B', 'I'];
const color = d3
.scaleOrdinal()
.domain(tValues)
.range(['#5cdacc', '#ff1d34', '#ffc750', '#ff8c50']);
const x = d3
.scalePoint()
.domain(tValues)
.range([0, width]);
svgs
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.attr('class', 'domain')
.call(d3.axisBottom(x));
const max = d3.max(data, function(d) {
return +d.total;
});
console.log(max);
const y = d3
.scaleLinear()
.domain([0, max])
.range([height, 0]);
const bars = svgs
.selectAll('.bars')
.data(function(d) {
console.log(d.values);
return d.values;
})
.enter()
.append('rect')
.attr('class', 'bars')
.attr('width', 10)
.attr('x', function(d, i) {
return i * 5;
})
.attr('height', function(d, i) {
return height - y(+d.total);
})
.attr('y', function(d) {
return y(+d.total);
})
.style('fill', function(d, i) {
return color(d.key);
});
}
控制台没有返回任何错误,我能够看到绘制了一个条,我认为这是取得积极成果的条。
任何帮助将不胜感激!我一直在d3块中寻找一些答案,但是自几个月前开始编写代码以来,我一直无法解决这些问题。
谢谢您的帮助:)!
答案 0 :(得分:1)
我会花更多时间来预先组织我的数据,以使其在传递给d3
时更加简单,就像这样:
// loop data once and organize
let max = -1e9;
data = data.map(function(d) {
let m = Math.max(d.positive, d.negative, d.balanced, d.informational);
if (m > max) max = m; // find max of data
return {
key: d.media_outlet,
values: [{
key: 'positive',
value: +d.positive
}, {
key: 'negative',
value: +d.negative
}, {
key: 'balanced',
value: +d.balanced
}, {
key: 'informational',
value: +d.informational
}]
};
});
这将成为非常直截了当的d3
子选择,以绘制线条:
const bars = svgs
.selectAll('.bars')
.data(function(d) {
return d.values;
})
.enter()
.append('rect')
.attr('class', 'bars')
.attr('width', 10)
.attr('x', function(d, i) {
return x(d.key) - 5;
})
.attr('height', function(d, i) {
return height - y(d.value);
})
.attr('y', function(d) {
return y(d.value);
})
.style('fill', function(d, i) {
return color(d.key);
});
完整的运行代码:
let newsData = [{
"media_outlet": "La Opinión",
"positive": "149",
"negative": "296",
"balanced": "142",
"informational": "101",
"total": "688"
}, {
"media_outlet": "Wall Street Journal",
"positive": "137",
"negative": "118",
"balanced": "125",
"informational": "79",
"total": "459"
}, {
"media_outlet": "Univision",
"positive": "226",
"negative": "484",
"balanced": "225",
"informational": "159",
"total": "1094"
}, {
"media_outlet": "San Diego Union Tribune",
"positive": "60",
"negative": "24",
"balanced": "18",
"informational": "17",
"total": "119"
}, {
"media_outlet": "Fox News",
"positive": "73",
"negative": "102",
"balanced": "58",
"informational": "60",
"total": "293"
}, {
"media_outlet": "Washington Post",
"positive": "52",
"negative": "97",
"balanced": "56",
"informational": "50",
"total": "255"
}, {
"media_outlet": "CNN",
"positive": "127",
"negative": "160",
"balanced": "102",
"informational": "88",
"total": "477"
}, {
"media_outlet": "USA Today",
"positive": "32",
"negative": "23",
"balanced": "14",
"informational": "22",
"total": "91"
}, {
"media_outlet": "The Daily Beast",
"positive": "9",
"negative": "50",
"balanced": "13",
"informational": "10",
"total": "82"
}, {
"media_outlet": "Bloomberg",
"positive": "251",
"negative": "183",
"balanced": "158",
"informational": "119",
"total": "711"
}, {
"media_outlet": "Fusion",
"positive": "48",
"negative": "86",
"balanced": "54",
"informational": "49",
"total": "237"
}, {
"media_outlet": "NPR",
"positive": "20",
"negative": "30",
"balanced": "12",
"informational": "14",
"total": "76"
}, {
"media_outlet": "Dallas Morning News",
"positive": "40",
"negative": "34",
"balanced": "24",
"informational": "31",
"total": "129"
}, {
"media_outlet": "TIME",
"positive": "26",
"negative": "30",
"balanced": "17",
"informational": "17",
"total": "90"
}, {
"media_outlet": "Forbes",
"positive": "97",
"negative": "56",
"balanced": "72",
"informational": "37",
"total": "262"
}, {
"media_outlet": "Christian Science Monitor",
"positive": "19",
"negative": "15",
"balanced": "21",
"informational": "7",
"total": "62"
}, {
"media_outlet": "NBC News",
"positive": "23",
"negative": "34",
"balanced": "19",
"informational": "22",
"total": "98"
}, {
"media_outlet": "Huffington Post",
"positive": "232",
"negative": "344",
"balanced": "219",
"informational": "85",
"total": "880"
}, {
"media_outlet": "New York TImes",
"positive": "90",
"negative": "129",
"balanced": "74",
"informational": "62",
"total": "355"
}, {
"media_outlet": "Houston Chronicle",
"positive": "40",
"negative": "32",
"balanced": "31",
"informational": "24",
"total": "127"
}, {
"media_outlet": "Los Angeles Times",
"positive": "66",
"negative": "75",
"balanced": "45",
"informational": "45",
"total": "231"
}, {
"media_outlet": "San Antonio Express News",
"positive": "28",
"negative": "22",
"balanced": "14",
"informational": "16",
"total": "80"
}, {
"media_outlet": "Arizona Daily Star",
"positive": "32",
"negative": "15",
"balanced": "6",
"informational": "8",
"total": "61"
}, {
"media_outlet": "Vice News",
"positive": "17",
"negative": "169",
"balanced": "44",
"informational": "12",
"total": "242 "
}];
let data = newsData.sort(function(a, b) {
if (+a.total < +b.total) {
return 1;
} else {
return -1;
}
});
let max = -1e9;
data = data.map(function(d) {
let m = Math.max(d.positive, d.negative, d.balanced, d.informational);
if (m > max) max = m;
return {
key: d.media_outlet,
values: [{
key: 'positive',
value: +d.positive
}, {
key: 'negative',
value: +d.negative
}, {
key: 'balanced',
value: +d.balanced
}, {
key: 'informational',
value: +d.informational
}]
};
});
const tValues = ['positive', 'negative', 'balanced', 'informational'];
const colors = ['#5cdacc', '#ff1d34', '#ffc750', '#ff8c50'];
const margin = {
top: 20,
right: 50,
bottom: 20,
left: 50
};
const width = 310 - margin.left - margin.right;
const height = 150 - margin.top - margin.bottom;
const svgs = d3
.select('#outlets-viz')
.selectAll('svg')
.data(data)
.enter()
.append('svg')
.attr('class', 'media-svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
const color = d3
.scaleOrdinal()
.domain(tValues)
.range(['#5cdacc', '#ff1d34', '#ffc750', '#ff8c50']);
const x = d3
.scalePoint()
.domain(tValues)
.range([0, width]);
svgs
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.attr('class', 'domain')
.call(d3.axisBottom(x).tickFormat(
t => t[0].toUpperCase()
));
const y = d3
.scaleLinear()
.domain([0, max])
.range([height, 0]);
const bars = svgs
.selectAll('.bars')
.data(function(d) {
return d.values;
})
.enter()
.append('rect')
.attr('class', 'bars')
.attr('width', 10)
.attr('x', function(d, i) {
return x(d.key) - 5;
})
.attr('height', function(d, i) {
return height - y(d.value);
})
.attr('y', function(d) {
return y(d.value);
})
.style('fill', function(d, i) {
return color(d.key);
});
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v5.min.js"></script>
<div id="outlets-viz"></div>