Public
Edited
Sep 17, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
// SVG要素を作成し、アスペクト比を維持して表示領域を設定します
const svg = d3

.create("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
// .attr(
// "viewBox",
// "-" +
// adj +
// " -" +
// adj +
// " " +
// (width + adj * 2) +
// " " +
// (height + adj * 2)
// )
.attr("viewBox", "0 0 900 1030")
// .attr("viewBox", "-90 -250 900 1030")
// .style("background", mode === "dark" ? "#2e2e2e" : "#fff");
.style("background-color", "rgb(250, 245, 240)"); // 背景色を設定します;

// グラデーションの開始色、中間色、終了色をカスタムカラーマップから取得
const gradientStartColor = customColorMap(1.0); // 開始色と終了色を逆に
const gradientMidColor = customColorMap(0.6);
const gradientEndColor = customColorMap(0.0); // 開始色と終了色を逆に

// 明るいグラデーションを定義します
const gradient_light = svg
.append("linearGradient")
.attr("id", "gradLight")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "0%")
.attr("y2", "100%");

// グラデーションの開始色を追加します
gradient_light
.append("stop")
.attr("offset", "0%")
.attr("stop-color", gradientStartColor);

// グラデーションの中間色を追加します
gradient_light
.append("stop")
.attr("offset", "60%")
.attr("stop-color", gradientMidColor);

// グラデーションの終了色を追加します
gradient_light
.append("stop")
.attr("offset", "95%")
.attr("stop-color", gradientEndColor);

// 暗いグラデーションを定義します
const gradient_dark = svg
.append("linearGradient")
.attr("id", "gradDark")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "0%")
.attr("y2", "100%");

// グラデーションの開始色を追加します
gradient_dark
.append("stop")
.attr("offset", "0%")
.attr("stop-color", gradientStartColor);

// グラデーションの中間色を追加します
gradient_dark
.append("stop")
.attr("offset", "60%")
.attr("stop-color", gradientMidColor);

// グラデーションの終了色を追加します
gradient_dark
.append("stop")
.attr("offset", "95%")
.attr("stop-color", gradientEndColor);

// // // 明るいグラデーションを定義します
// // const gradient_light = svg
// // .append("linearGradient")
// // .attr("id", "gradLight")
// // .attr("x1", "0%")
// // .attr("y1", "0%")
// // .attr("x2", "0%")
// // .attr("y2", "100%");

// // // グラデーションの開始色を追加します
// // gradient_light
// // .append("stop")
// // .attr("offset", "0%")
// // .attr("stop-color", "#6a915c");

// // // グラデーションの中間色を追加します
// // gradient_light
// // .append("stop")
// // .attr("offset", "60%")
// // .attr("stop-color", "#92ac7d");

// // // グラデーションの終了色を追加します
// // gradient_light
// // .append("stop")
// // .attr("offset", "95%")
// // .attr("stop-color", "#b8c8a0");

// // 暗いグラデーションを定義します
// const gradient_dark = svg
// .append("linearGradient")
// .attr("id", "gradDark")
// .attr("x1", "0%")
// .attr("y1", "0%")
// .attr("x2", "0%")
// .attr("y2", "100%");

// // グラデーションの開始色を追加します
// gradient_dark
// .append("stop")
// .attr("offset", "0%")
// .attr("stop-color", "#b8c8a0");

// // グラデーションの中間色を追加します
// gradient_dark
// .append("stop")
// .attr("offset", "60%")
// .attr("stop-color", "#92ac7d");

// // グラデーションの終了色を追加します
// gradient_dark
// .append("stop")
// .attr("offset", "95%")
// .attr("stop-color", "#6a915c");

// x軸をSVGに追加します
svg.append("g").call(xAxis);

// 新しいY軸を右側に追加するための設定
const yAxisRight = d3
.axisRight(y)
.ticks(5) // 目盛りの数を設定
.tickSize(width); // 目盛り線の長さをグラフ全体の幅に設定

// Y軸を右側に追加
svg
.append("g")
.attr("class", "y-axis-right") // クラスを追加(任意)
.call(yAxisRight)
.attr("transform", `translate(${width},0)`); // 右側に配置

// データの各シリーズに対して要素を追加し、位置を調整します
const group = svg
.append("g")
.selectAll("g")
.data(data.series)
.join("g")
.attr("transform", (d) => `translate(0,${y(d.country) + 1})`)
// .on("mouseover", handleMouseOver) // マウスオーバー時のイベントを追加
// .on("mouseout", handleMouseOut); // マウスアウト時のイベントを追加
.attr("class", (d) => (d.country === "United States" ? "highlighted" : ""));

// 領域を描画します
group
.append("path")
.attr("fill", mode === "dark" ? "url(#gradDark)" : "url(#gradLight)")
.attr("fill-opacity", (d) => (d.country === "United States" ? 1.0 : 0.2))
.attr("d", (d) => area(d.viewss));

// 線を描画します
group
.append("path")
.attr("fill", "none")
.attr("stroke", (d) =>
d.country === "United States" ? "white" : "rgb(250, 245, 240)"
)
.attr("stroke-width", 2.5)
.attr("stroke-opacity", (d) => (d.country === "United States" ? 0.0 : 0.1))
.attr("d", (d) => line(d.viewss));

// // 領域を描画します
// group
// .append("path")
// .attr("fill", mode === "dark" ? "url(#gradDark)" : "url(#gradLight)")
// .attr("fill-opacity", 0.7)
// .attr("d", (d) => area(d.viewss));

// // 線を描画します
// group
// .append("path")
// .attr("fill", "none")
// // .attr("stroke", mode === "dark" ? "#f2e8d2" : "#544208")
// .attr("stroke", "white")
// .attr("stroke-width", 2.5) // 線の太さを設定します
// .attr("stroke-opacity", 0.5) // 線の透明度を設定します
// .attr("d", (d) => line(d.viewss));
// y軸をSVGに追加します
svg
.append("g")
.call(yAxis)
.selectAll("text")
.attr("text-anchor", "end")
.attr("transform", "translate(85, -15)")
.style("font-size", "22px")
.style("font-weight", "bold")
// .style("stroke", "rgb(250, 245, 240)") // ストロークの色を指定します
.style("stroke", "white") // ストロークの色を指定します
.style("opacity", 1.0) // ストロークの透明度を指定します
.style("stroke-width", "0.3px"); // ストロークの太さを指定します

// SVG要素を返します
return svg.node();
}
Insert cell

// handleMouseOver関数: マウスオーバー時にハイライトする処理
function handleMouseOver(event, d) {
// 選択されたシリーズのパスをハイライト
d3.select(this)
.select("path")
.attr("fill-opacity", 1.0) // ハイライト時の不透明度
.attr("stroke-opacity", 1.0); // ハイライト時の不透明度
}

Insert cell
// handleMouseOut関数: マウスアウト時にハイライトを解除する処理
function handleMouseOut(event, d) {
// 選択されたシリーズのパスのハイライトを解除
d3.select(this)
.select("path")
.attr("fill-opacity", 0.7) // 元の不透明度に戻す
.attr("stroke-opacity", 0.5); // 元の不透明度に戻す
}
Insert cell
230917_YouTubeMC_Lamp@2.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
mode = Generators.observe(notify => {
const query = matchMedia("(prefers-color-scheme: dark)");
const changed = () => notify(query.matches ? "dark" : "light");
changed();
query.addListener(changed);
return () => query.removeListener(changed);
})
Insert cell
adj = 50
Insert cell
overlap = 8
Insert cell
width = 900
Insert cell
height = 1030
Insert cell
margin = ({ top: 300, right: 20, bottom: 30, left: 110 })
Insert cell
x = d3.scaleTime()
.domain(d3.extent(data.dates))
.range([margin.left, width - margin.right])
Insert cell
y = d3.scalePoint()
.domain(data.series.map(d => d.country))
.range([margin.top, height - margin.bottom])
Insert cell
z = d3
.scaleLinear()
.domain([0, d3.max(data.series, (d) => d3.max(d.viewss))])
.nice()
.range([0, -overlap * y.step()])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.style("color", mode==="dark"?"#f2e8d2":"#544208")
.call(d3.axisBottom(x)
.ticks(width / 80)
.tickSizeOuter(0))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.style("color", mode==="dark"?"#f2e8d2":"#544208")
.call(d3.axisLeft(y).tickSize(0).tickPadding(4))
.call(g => g.select(".domain").remove())
Insert cell
area = d3
.area()
.curve(d3.curveCatmullRom.alpha(0.5))
.defined((d) => !isNaN(d))
.x((d, i) => x(data.dates[i]))
.y0(0)
.y1((d) => z(d))
Insert cell
line = area.lineY1()
Insert cell
data = {
const data = d3.csvParse(
await FileAttachment("230917_YouTubeMC_Lamp@2.csv").text(),
d3.autoType
);
const dates = Array.from(d3.group(data, (d) => +d.date).keys()).sort(
d3.ascending
);

// 最初の10ヶ国を抽出します
const top10Countries = Array.from(
d3.groups(data, (d) => d.country),
([country]) => country
).slice(0, 20);

return {
dates: dates.map((d) => new Date(d)),
series: d3
.groups(data, (d) => d.country)
.filter(([country]) => top10Countries.includes(country)) // 最初の10ヶ国だけをフィルタリング
.map(([country, viewss]) => {
const views = new Map(viewss.map((d) => [+d.date, d.views]));
return { country, viewss: dates.map((d) => views.get(d)) };
})
};
}
Insert cell
d3 = require("d3@5", "d3-array@2")
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