Public
Edited
Jul 19, 2023
Insert cell
Insert cell
{
const plt1 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true, domain: cities, range: colorScheme },
marks: [
Plot.frame(),
Plot.dot(allData, {
x: "分数",
y: "本段人数",
fill: "city",
opacity: 0.5,
tip: true
}),
Plot.line(allData, {
x: "分数",
y: "本段人数",
stroke: "city",
opacity: 0.8
})
]
});

const plt2 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true, domain: cities, range: colorScheme },
marks: [
Plot.frame(),
Plot.line(scoreTable, {
x: "score",
y: "accumulateRatio",
stroke: "black",
strokeWidth: 10,
opacity: 0.2,
tip: true
}),
Plot.line(allData, {
x: "分数",
y: "accumulateRatioInCity",
stroke: "city",
strokeWidth: 2,
opacity: 0.8,
tip: true
})
]
});

const plt3 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true },
marks: [
Plot.frame(),
Plot.dot(scoreTable, {
x: "score",
y: "haidianRatio",
fill: "green",
opacity: 0.5,
tip: true
}),
Plot.dot(scoreTable, {
x: "score",
y: "top4Ratio",
fill: "red",
opacity: 0.5,
tip: true
})
]
});

const plt4 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true, domain: cities, range: colorScheme },
marks: [
Plot.frame(),
Plot.line(allData, {
x: "分数",
y: "ratioInCity",
stroke: "city",
opacity: 0.4,
tip: true
})
]
});

return htl.html`
<div>
${plt1}
${plt2}
${plt3}
${plt4}
</div>
`;
}
Insert cell
Insert cell
{
const plts = cities.map((city, cityIdx) => {
const data = rawData.filter((d) => d.city === city),
color = colorScheme[cityIdx % 10],
mean =
d3.sum(data, (d) => d.本段人数 * d.分数) /
d3.sum(data, (d) => d.本段人数),
max = data[d3.maxIndex(data, (d) => d.本段人数)].分数;

const plt = Plot.plot({
width: width / 2,
height: width / 5,
x: { nice: true, reverse: true },
y: { nice: true, domain: sameYDomain ? [0, 250] : undefined },
color: {
nice: true,
legend: true
},
grid: true,
marks: [
Plot.frame({ stroke: "#3333" }),
Plot.dot(data, {
x: "分数",
y: "本段人数",
fill: color,
opacity: 0.8,
tip: true
}),
Plot.ruleX([mean]),
Plot.ruleX([max]),
Plot.text(
[
{ x: mean, y: 10, t: "mean" + mean.toFixed(2) },
{ x: max, y: 20, t: "max" + max.toFixed(2) }
],
{
x: "x",
y: "y",
text: "t"
}
)
]
});

return htl.html`
<div>
<h2 style="color: ${color}">
${city} ${max.toFixed(2)} | ${mean.toFixed(2)}
</h2>
${plt}
</div>
`;
});

return htl.html`

<div style='display: flex; flex-flow: wrap'>
${plts}
</div>
`;
}
Insert cell
colorScheme = d3.schemeTableau10.concat(d3.schemeTableau10.map((d) => d + "50"))
Insert cell
{
const plt1 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true, scheme: "Blues", range: [0.1, 0.9] },
marks: [
Plot.frame(),
Plot.dot(scoreTable, { x: "score", y: "num", fill: "std", opacity: 0.5 })
]
});

const plt2 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true, scheme: "Blues", range: [0.1, 0.9] },
marks: [
Plot.frame(),
Plot.dot(scoreTable, {
x: "score",
y: "num",
fill: "stdRatio",
opacity: 0.5
})
]
});

const plt3 = Plot.plot({
grid: true,
x: { nice: true, reverse: true },
y: { nice: true },
color: { nice: true, legend: true, scheme: "Blues", range: [0.1, 0.9] },
marks: [
Plot.frame(),
Plot.dot(scoreTable, {
x: "score",
y: "num",
fill: "x2Factor",
opacity: 0.5,
tip: true
}),
Plot.dot(
scoreTable.filter((d) => d.x2Factor > 28.87), // 28.87 is p<0.05 in degree of freedom = 18
{
x: "score",
y: "num",
stroke: "red",
r: 4,
opacity: 0.5,
tip: true
}
)
]
});

return htl.html`
${plt1}
${plt2}
${plt3}
`;
}
Insert cell
scoreTable
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
scoreTable = {
const scores = [...new Set(allData.map((d) => d.分数))].sort().reverse(),
table = scores.map((score) => {
return {
score,
num: d3.sum(
allData.filter((d) => d.分数 === score),
(d) => d.本段人数
)
};
}),
variance = d3.variance(allData, (d) => d.ratioInCity),
degreeOfFreedom = cities.length - 1;

table.map((d, i) => {
const select = allData.filter((e) => e.分数 === d.score);

Object.assign(d, {
accumulate: d3.sum(table.slice(0, i + 1), (e) => e.num),
accumulateRatio:
d3.sum(table.slice(0, i + 1), (e) => e.num) /
d3.sum(table, (d) => d.num),
std: Math.sqrt(d3.variance(select, (e) => e.本段人数)),
stdRatio: Math.sqrt(d3.variance(select, (e) => e.ratioInCity)),
x2Factor:
(d3.variance(select, (e) => e.ratioInCity) / variance) *
degreeOfFreedom,
haidianRatio:
allData.find((e) => (e.city === "海淀区") & (e.分数 === d.score))
.本段人数 / d.num,
top4Ratio:
d3.sum(
allData.filter(
(e) =>
(["东城区", "海淀区", "朝阳区", "西城区"].indexOf(e.city) > -1) &
(e.分数 === d.score)
),
(d) => d.本段人数
) / d.num
});
});

return table;
}
Insert cell
allData
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
allData = {
const data = rawData.map((d) => Object.assign({}, d));

cities.map((city) => {
const select = data.filter((d) => d.city === city),
total = d3.sum(select, (d) => d.本段人数);

select.map((row) => {
Object.assign(row, { ratioInCity: row.本段人数 / total });
});

select.map((row, i) => {
Object.assign(row, {
accumulateRatioInCity: d3.sum(
select.slice(0, i + 1),
(d) => d.ratioInCity
)
});
});
});

return data;
}
Insert cell
Insert cell
table.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
d3 = require("d3")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more