Public
Edited
Aug 28, 2024
Fork of Simple D3
Insert cell
Insert cell
parseData = (data) => {
return data.replaceAll('-', ',').split('\n').map(line => line.split(',').map(e => parseInt(e)))
}
Insert cell
questions = [
{
question: `You can obtain one of these before you depart for a long adventure.

Which of them would you want?

冒険に出発するあなたに、力をひとつ授けよう。何がほしい?`,
answers: [
'An almighty sword / 強い敵を倒す剣',
'The power of natural energies / 自然の力を操る魔力',
'The power to protect and heal / 仲間を守り癒す力',
'Super speed / 誰も追いつけないスピード'
]
},
{
question: `What do you cherish the most?

あなたにとって最も大切なものは?`,
answers: [
'Peace / 平和',
'Excitement / 刺激',
'Friendship / 友情',
'Power / 力'
]
},
{
question: `Which of these do you think could be your alias?

あなたに二つ名をつけるなら?`,
answers: [
'Shadow Sword / 影の剣',
'Dragon Killer / ドラゴン殺し',
'Steel-made Samurai / 鋼鉄の侍',
'Poison Lily / 毒ユリ姫'
]
},
{
question: `A kingdom in desperate need of protection is asking you for your help to fight off dangerous enemies!

滅亡の危機に瀕した王国に、危険な敵との戦いを頼まれた!`,
answers: [
"It'll be okay because I'm here! / もう大丈夫、私が来た!",
"What's in it for me? / 見返りは?",
'Me? Are you sure about that? / じ、自分ですか!?',
'But I refuse, DAGA KOTOWARU! / だが断る'
]
},
{
question: `Something is waiting for you at the last stage of a long and challenging dungeon. What is it?

苦労しながら進んだダンジョンの最終階に、何かが待ち受けていた。それは何?`,
answers: [
'A box full of treasure! / 金銀財宝',
'An invitation to a new land / 新しい冒険へ導く手紙',
'The Final Boss! / 史上最悪の敵',
'YAGOO'
]
}
]
Insert cell
data = [
{
name: "ame",
answers: `1-1-1-3-2
1-1-2-3-2
1-1-3-3-2
1-1-4-3-2
1-2-1-3-2
1-2-2-3-2
1-2-3-3-1
1-2-3-3-2
1-2-3-3-4
1-2-4-3-2
1-3-1-3-2
1-3-2-3-2
1-3-2-3-4
1-3-3-3-2
1-3-4-3-2
1-4-2-3-1
1-4-2-3-2
1-4-2-3-4
1-4-3-3-2
1-4-4-3-2
2-1-4-3-1
2-1-4-3-2
2-2-1-3-2
2-2-2-3-2
2-2-3-3-2
2-3-1-3-2
2-3-2-3-2
2-4-1-3-2
2-4-2-3-2
2-4-3-3-3
3-1-2-3-2
3-1-3-3-2
3-2-2-3-2
3-2-3-3-2
3-2-4-3-2
3-3-2-3-2
3-3-4-3-2
3-4-1-3-2
3-4-2-3-2
3-4-3-3-2
3-4-4-3-2
4-1-2-3-2
4-1-3-3-2
4-2-1-3-2
4-3-1-3-2
4-3-2-3-2
4-3-2-3-4
4-3-4-3-2
4-4-2-3-2
4-4-2-4-2
4-4-3-3-2
4-4-3-4-2
4-4-4-3-2`
},
{
name: "gura",
answers: `1-1-2-4-1
1-1-2-4-2
1-1-2-4-3
1-1-2-4-4
1-2-1-4-1
1-2-1-4-2
1-2-2-4-1
1-2-2-4-2
1-2-2-4-3
1-2-2-4-4
1-2-3-4-2
1-2-3-4-4
1-2-4-4-2
1-2-4-4-4
1-3-2-4-2
1-3-2-4-4
1-4-2-4-2
2-1-1-4-4
2-1-2-4-2
2-1-2-4-3
2-2-1-4-3
2-2-2-1-2
2-2-2-4-1
2-2-2-4-2
2-2-2-4-3
2-2-2-4-4
2-2-3-4-2
2-2-3-4-3
2-2-3-4-4
2-2-4-4-2
2-3-2-4-4
2-4-2-4-2
2-4-2-4-3
3-1-2-4-1
3-1-2-4-2
3-1-2-4-4
3-2-1-4-2
3-2-2-4-1
3-2-2-4-2
3-2-2-4-3
3-2-2-4-4
3-2-3-4-1
3-2-3-4-2
3-2-4-4-2
3-2-4-4-3
3-2-4-4-4
3-3-2-4-4
3-4-2-4-2
4-1-2-4-2
4-1-2-4-3
4-2-2-4-2
4-2-2-4-3
4-2-2-4-4
4-3-2-4-2`
},
{
name: 'Fauna',
answers: `1-1-1-2-4
1-1-1-3-4
1-1-2-2-4
1-1-2-3-4
1-1-3-3-4
1-1-4-1-4
1-1-4-2-3
1-1-4-3-1
1-1-4-4-2
1-1-4-4-4
1-3-4-1-4
1-3-4-4-4
2-1-1-1-1
2-1-1-1-4
2-1-1-2-1
2-1-1-4-2
2-1-1-4-3
2-1-2-1-1
2-1-2-1-4
2-1-2-2-1
2-1-2-2-2
2-1-2-2-4
2-1-2-3-2
2-1-2-3-4
2-1-2-4-4
2-1-3-1-4
2-1-3-3-2
2-1-3-3-3
2-1-3-3-4
2-1-3-4-2
2-1-4-1-3
2-1-4-1-4
2-1-4-2-2
2-1-4-2-3
2-1-4-2-4
2-1-4-3-3
2-1-4-3-4
2-1-4-4-3
2-1-4-4-4
2-2-1-3-4
2-2-3-2-4
2-2-4-2-3
2-2-4-3-2
2-3-4-3-2
2-3-4-4-2
2-3-4-4-4
2-4-2-3-4
2-4-4-1-2
2-4-4-1-3
2-4-4-2-3
2-4-4-2-4
2-4-4-3-2
2-4-4-4-3
3-2-4-1-4
3-3-4-1-4`
},
{
name: 'Fuwawa',
answers: `1-1-3-1-2
2-1-1-1-2
2-1-1-1-3
2-1-2-1-2
2-1-3-1-2
2-1-4-1-2
3-1-1-1-2
3-1-1-1-3
3-1-1-1-4
3-1-2-1-2
3-1-2-1-4
3-1-3-1-2
3-1-3-1-4
3-1-4-1-1
3-1-4-1-2
3-1-4-1-3
3-1-4-4-2
3-2-2-1-2
3-4-2-1-2
4-1-1-1-1
4-1-1-1-2
4-1-1-1-3
4-1-1-1-4
4-1-1-2-4
4-1-2-1-2
4-1-2-1-3
4-1-2-3-4
4-1-3-1-1
4-1-3-1-2
4-1-3-1-3
4-1-3-1-4
4-1-4-1-1
4-1-4-1-2
4-1-4-1-3
4-1-4-1-4
4-1-4-2-2
4-1-4-3-1
4-2-1-1-3
4-2-1-1-4
4-2-2-1-2
4-2-2-1-3
4-2-3-1-2
4-3-1-1-3
4-3-1-1-4
4-3-2-1-2
4-3-3-1-2
4-3-4-1-2
4-4-1-1-1
4-4-1-1-3
4-4-2-1-4
4-4-3-1-2
4-4-3-1-4
4-4-4-1-2`
},
{
name: 'Mococo',
answers: `1-1-2-2-2
1-1-3-2-2
1-1-4-2-1
1-1-4-2-2
1-1-4-2-4
1-2-1-2-4
1-2-3-2-2
1-2-4-2-2
1-2-4-2-3
1-2-4-2-4
1-3-1-2-2
1-3-1-2-4
1-3-2-2-2
1-3-3-2-1
1-3-3-2-2
1-3-4-1-2
1-3-4-2-2
1-3-4-2-3
1-3-4-2-4
1-3-4-4-2
1-4-1-1-2
1-4-1-2-1
1-4-1-2-2
1-4-1-2-3
1-4-2-2-1
1-4-2-2-2
1-4-2-2-3
1-4-2-2-4
1-4-3-2-1
1-4-3-2-2
1-4-3-2-4
1-4-3-4-2
1-4-4-1-2
1-4-4-2-1
1-4-4-2-2
1-4-4-2-3
1-4-4-2-4
1-4-4-4-2
2-4-1-2-2
2-4-2-2-2
2-4-3-2-2
2-4-4-2-2
3-2-4-2-2
3-3-4-2-2
3-4-2-2-2
3-4-4-1-2
3-4-4-2-2
4-3-4-2-2
4-4-2-2-3
4-4-2-2-4
4-4-3-2-2
4-4-4-2-1
4-4-4-2-2
4-4-4-2-3`
}
].map(talent => {
const parsedData = parseData(talent.answers);
return {
...talent,
answers: parsedData,
answerTimes: parsedData.reduce((acc, current) => {
current.forEach((e, i) => acc[i][e-1] = acc[i][e-1] + 1);
return acc;
}, Array.from({ length: 5 }, () => Array(4).fill(0)))
};
})
Insert cell
chart = {
const width = 800;
const height = 400;

const margin = {top: 50, right:50, left: 50, bottom: 50}
// Create SVG container
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto;");
const x = d3.scaleLinear()
// 5 questions
.domain([1,5])
.range([margin['left'], width - margin['right']]);

const y = d3.scaleLinear()
// 4 Answers per question
.domain([4,1])
.range([height - margin['bottom'], margin['top']]);

svg.selectAll("axes")
.data(questions).enter()
.append("g")
// I translate this element to its right position on the x axis
.attr("transform", (d, i) => { return "translate(" + x(i+1) + ")"; })
// And I build the axis with the call function
.each(function(d) {
d3.select(this).call(
d3.axisLeft()
.scale(y)
.tickValues(y.ticks().filter(tick => Number.isInteger(tick)))
);
})
// Add axis title
.append("text")
.style("text-anchor", "middle")
.attr("y", 0)
.text(function(d) { return d; })
.style("fill", "black")

const filter = ["ame", "gura"];
const colours = {
"ame": "#fcba03",
"gura": "#57b0ff",
"Fauna": "#43c465",
"Fuwawa": "#88e3f7",
"Mococo": "#f788d2",
}
const path = (d) => {
return d3.line()(d.map((p, i) => { return [x(i+1), y(p)]}))
}

const drawPaths = (name, data, colour) => {
svg.selectAll(`${name}-path`)
.data(data)
.join("path")
.attr("d", path)
.style("fill", "none")
.style("stroke", colour)
.style("opacity", 0.5);
}

// data.forEach((e) => drawPaths(e.name, e.answers, colours[e.name]));

const drawCircles = (data, colour) => {
data.forEach((questionAnswers, i) => {
svg
.selectAll(`${name}-q${i}-answer-circles`)
.data(questionAnswers)
.join("circle")
.attr("cx", x(i+1))
.attr("cy", (d, j) => {
console.log(i, j, d)
return y(j+1);
})
.attr("r", d => d)
.attr("fill", colour);
});
}

data.filter(e => filter.includes(e.name))
.forEach((e) => drawCircles(e.answerTimes, colours[e.name]));
return svg.node();
}
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