Published
Edited
Jul 10, 2022
Insert cell
Insert cell
Insert cell
/*
viewof select_hist_grouping = select({
title: "選択したbarの グループ化",
options:["発売年月","レーベル","著者"],
value: "発売年月",
description: "(何に使っているのか忘れた[使ってない??])"
});*/
Insert cell
Insert cell
by_label_obj["電撃ポストカード文庫"];//ページ数全てNaNのもの
Insert cell
Insert cell
Insert cell
Insert cell
{
// 作者スパイク統計
// 何かでソートしないと、予期せぬ(無意味な)発見をしてしまうかも...
const _authors = Object.keys(by_author_obj);
const _data = Object.values(by_author_obj)
.map((d,i) =>{
//y位置を確認しやすいように、各データにindexを加える
d.map(_d =>{
_d.id = i;
return _d;
});
return d;
});
const per_height = 12;// 各行の高さ
const div = d3.create("div");
const svg = div.append("svg").attr("viewBox", [0, 0, width, per_height * (_authors.length + 2)]).attr("id", "spike-svg");
// x・y 位置用
// (別セルの大元データで 発売年月の始めと終わりを見る)
const st_year = data[data.length - 1]["発売年月"]["年"];
const ed_year = data[0]["発売年月"]["年"];
const per_x = 12;//年毎の間距離
const yearX = d3.scaleLinear()
.domain([st_year, ed_year + 1])
.range([0, per_x * (ed_year - st_year + 1)]);
const dayX = d3.scaleLinear()
.domain([1, 12])
.range([0, per_x - 1]);
const posX = function(_d){
const YM = _d["発売年月"];
return yearX(YM["年"]) + dayX(YM["月"]);
}
const posY = d3.scaleLinear()
.domain([0, _data.length])//1つ分多めにとる
.range([0, _data.length * per_height]);
// 作者毎の列
const spike_row = svg.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.selectAll("g")
.data(_data)
.enter()
.append("g")
.attr("class", (_,i) => "spike-row-" + i);
// 各スパイク
const spikes = spike_row.selectAll("line")
.data(d => d)
.enter()
.append("line")
.attr("x1", d => posX(d))
.attr("x2", d => posX(d))
.attr("y1", d => posY(d.id) + 0.5)//隙間を作成
.attr("y2", d => posY(d.id+1) - 0.5)
.attr("stroke", "#8E354A")//蘇芳(スオウ)
.attr("opacity", 0.4)//重なりがわかるように
.attr("stroke-width", 1);
// 作者名(これを先に作成しないと, デフォルトtop == svgのtop にならない)[微妙にずれる]
d3.select("#spike-div-container").remove();//既にある場合は消去
// bodyに入れないと 位置取りが面倒
d3.select("body").append("div")
.attr("id", "spike-div-container")
.style("display", "none")
.selectAll("div")
.data(_authors)
.enter()
.append("div")
.attr("class", "author-spike-div")
.style("margin", 1 + "px")//下の高さを二倍減らさなくていいのは不思議?
.style("height", (per_height - 1)+ "px") //各スパイク位置に一致するようにする
.text(d => d.length < 10? d: d.slice(0, 10) + "...");//はみ出す部分は削除
// あるスパイクに触れた場合に表示する(上の処理と同様に)
d3.select("spike-div-overtip").remove();
d3.select("body").append("div")
.attr("id", "spike-div-overtip")
.style("display", "none");
// 三年毎に表示される
function tickFormat(d){
if(d % 3 !== 0) return;
return d;
}
// 年の表示
const year_ticks = svg.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3
.axisBottom(yearX)
.ticks(ed_year - st_year + 1)
.tickFormat(tickFormat)
.tickSizeOuter(0)
);
// tickの書き方を真似して、x軸名を加えた
year_ticks.append("g")
.attr("transform", "translate(-25,0)")
.attr("opacity", 1)
.append("text")
.attr("fill", "currentColor")
.attr("y", 9)
.attr("dy", "0.71em")
.text("出版年月");
/* 表示されてない年は 突き出した棒を小さくする*/
year_ticks.selectAll(".tick")
.each( function(year,i,nodes){
const _tick = d3.select(nodes[i]);
//console.log(year, nodes[i], _tick, _tick.select("text").datum());
if(_tick.select("text").datum() % 3 !== 0){
_tick.select("line").attr("y2", 3.5);//デフォルトは6
}
});
// ticksは translateで x位置を決めて、 textなどはそれぞれ個別にyを指定する
console.log(year_ticks)
// 何もないところを触れた場合(それ以外も同時に調べる[d3 ver5より可能])
svg.on("mousemove", function(){
// 個人名の非表示
d3.select("#spike-div-overtip").style("display", "none");
const y = d3.event.offsetY;
year_ticks.attr("transform", `translate(${margin.left}, ${y + 10})`);
// div移動
const div_x = d3.event.offsetX < width/2? d3.event.offsetX + 30: d3.event.offsetX - 130;
const div_y = d3.event.target.getBoundingClientRect().top;
const names = d3.select("#spike-div-container")
.style("display", null)
.style("left", div_x + "px");
// svgの上を移動している場合のみ top位置を利用
if(d3.event.target.tagName === "svg") names.style("top", div_y + "px");
// 他の場合は、あるspikeの情報のみを表示
else{
// 全ての名前を非表示
names.style("display", "none");
// 触れているspikeについての表示
const parent = d3.event.target.parentNode;
const parent_class = parent.className.baseVal;
// spike以外なら無視
if(parent_class.indexOf("spike-row") !== -1){
const st_num_index = 1+parent_class.lastIndexOf("-")
const author_index = parseInt(parent_class.slice(st_num_index, parent_class.length), 10);
d3.select("#spike-div-overtip")
.style("display", null)
.style("left", div_x+ "px")
.style("top", (d3.event.pageY - 60) + "px")
.html("<div>" + _authors[author_index] + "</div>" +
'<div class="pub-num-spike-div-overtip">出版数: ' + _data[author_index].length + "</div>");
/*
console.log(parent, d3.select("#spike-div-overtip"), y, _authors[author_index], _data[author_index])
*/
}
}
});
return div.node()
}
Insert cell
Object.entries(by_label_obj).filter(d => d[0] ==="ルルル文庫スペシャル")
Insert cell
Insert cell
Insert cell
height = 500;
Insert cell
margin = ({top:30,
bottom: 30,
left: 50,
right: 10});
Insert cell
Insert cell
Insert cell
mutable select_hist_data = [];
Insert cell
Insert cell
by_illuster_obj = makeDataObj(data, "イラスト");//イラストライター? がいない[空文字] が多い
Insert cell
{
const keys = Object.keys(by_author_obj);
const last = keys.length-1;
return last
return [keys[last], by_author_obj[keys[last]]];
}
Insert cell
by_author_obj = makeDataObj(data, "著者");//一部 訳, 原案などの情報も同時に入る
//(因みに、『整理番号の一番最後数字』= 作家の出版作品番号 == 1 は処女作)
//例外もある(最後が大文字英語 => これはA~Z で AAになっている?)
// 更なる例外 :『青空に虹が』(著:富島健夫) => 別レーベルより?
Insert cell
by_title_obj = makeDataObj(data, "タイトル");//上下 や (2) II などで名前が一致しない
Insert cell
by_label_obj = makeDataObj(data, "レーベル");//レーベル毎に分類
Insert cell
data[data.length -1]
Insert cell
data = {
let data = [];
const ar_2019 = await FileAttachment("2019@1.tsv").text();
data = data.concat(parseTsv(ar_2019));
const ar_2018 = await FileAttachment("2018@1.tsv").text();
data = data.concat(parseTsv(ar_2018));
const ar_2017 = await FileAttachment("2017@1.tsv").text();
data = data.concat(parseTsv(ar_2017));
const ar_2016 = await FileAttachment("2016@1.tsv").text();
data = data.concat(parseTsv(ar_2016));
const ar_2015 = await FileAttachment("2015@1.tsv").text();
data = data.concat(parseTsv(ar_2015));
const ar_2014 = await FileAttachment("2014@1.tsv").text();
data = data.concat(parseTsv(ar_2014));
const ar_2013 = await FileAttachment("2013@1.tsv").text();
data = data.concat(parseTsv(ar_2013));
const ar_2012 = await FileAttachment("2012@1.tsv").text();
data = data.concat(parseTsv(ar_2012));
const ar_2011 = await FileAttachment("2011@1.tsv").text();
data = data.concat(parseTsv(ar_2011));
const ar_2010 = await FileAttachment("2010@1.tsv").text();
data = data.concat(parseTsv(ar_2010));
const ar_2009 = await FileAttachment("2009@1.tsv").text();
data = data.concat(parseTsv(ar_2009));
const ar_2008 = await FileAttachment("2008@1.tsv").text();
data = data.concat(parseTsv(ar_2008));
const ar_2007 = await FileAttachment("2007@1.tsv").text();
data = data.concat(parseTsv(ar_2007));
const ar_2006 = await FileAttachment("2006@1.tsv").text();
data = data.concat(parseTsv(ar_2006));
const ar_2005 = await FileAttachment("2005@1.tsv").text();
data = data.concat(parseTsv(ar_2005));
const ar_2004 = await FileAttachment("2004@1.tsv").text();
data = data.concat(parseTsv(ar_2004));
const ar_2003 = await FileAttachment("2003@1.tsv").text();
data = data.concat(parseTsv(ar_2003));
const ar_2002 = await FileAttachment("2002@1.tsv").text();
data = data.concat(parseTsv(ar_2002));
const ar_2001 = await FileAttachment("2001@1.tsv").text();
data = data.concat(parseTsv(ar_2001));
const ar_2000 = await FileAttachment("2000@1.tsv").text();
data = data.concat(parseTsv(ar_2000));
const ar_1999 = await FileAttachment("1999@1.tsv").text();
data = data.concat(parseTsv(ar_1999));
const ar_1998 = await FileAttachment("1998@1.tsv").text();
data = data.concat(parseTsv(ar_1998));
const ar_1997 = await FileAttachment("1997@1.tsv").text();
data = data.concat(parseTsv(ar_1997));
const ar_1996 = await FileAttachment("1996@1.tsv").text();
data = data.concat(parseTsv(ar_1996));
const ar_1995 = await FileAttachment("1995@1.tsv").text();
data = data.concat(parseTsv(ar_1995));
const ar_1994 = await FileAttachment("1994@1.tsv").text();
data = data.concat(parseTsv(ar_1994));
const ar_1993 = await FileAttachment("1993@1.tsv").text();
data = data.concat(parseTsv(ar_1993));
const ar_1992 = await FileAttachment("1992@1.tsv").text();
data = data.concat(parseTsv(ar_1992));
const ar_1991 = await FileAttachment("1991@1.tsv").text();
data = data.concat(parseTsv(ar_1991));
const ar_1990 = await FileAttachment("1990@1.tsv").text();
data = data.concat(parseTsv(ar_1990));
const ar_1989 = await FileAttachment("1989@1.tsv").text();
data = data.concat(parseTsv(ar_1989));
const ar_1988 = await FileAttachment("1988@1.tsv").text();
data = data.concat(parseTsv(ar_1988));
const ar_1987 = await FileAttachment("1987@1.tsv").text();
data = data.concat(parseTsv(ar_1987));
const ar_1986 = await FileAttachment("1986@1.tsv").text();
data = data.concat(parseTsv(ar_1986));
const ar_1985 = await FileAttachment("1985@1.tsv").text();
data = data.concat(parseTsv(ar_1985));
const ar_1984 = await FileAttachment("1984@1.tsv").text();
data = data.concat(parseTsv(ar_1984));
const ar_1983 = await FileAttachment("1983@1.tsv").text();
data = data.concat(parseTsv(ar_1983));
const ar_1982 = await FileAttachment("1982@1.tsv").text();
data = data.concat(parseTsv(ar_1982));
const ar_1981 = await FileAttachment("1981@1.tsv").text();
data = data.concat(parseTsv(ar_1981));
const ar_1980 = await FileAttachment("1980@1.tsv").text();
data = data.concat( parseTsv(ar_1980));
const ar_1979 = await FileAttachment("1979@1.tsv").text();
data = data.concat( parseTsv(ar_1979));
const ar_1978 = await FileAttachment("1978@1.tsv").text();
data = data.concat( parseTsv(ar_1978));
const ar_1977 = await FileAttachment("1977@1.tsv").text();
data = data.concat( parseTsv(ar_1977));
const ar_1976 = await FileAttachment("1976@2.tsv").text();
data = data.concat( parseTsv(ar_1976));
const ar_1975 = await FileAttachment("1975@1.tsv").text();
data = data.concat( parseTsv(ar_1975));
return data;
}
Insert cell
Insert cell
Insert cell
parseTsv = function(txt){
//tsvのconcatミス? により出てくる column名の列を削除
return d3.tsvParse(txt).filter(d => d["発売年月"] !== "発売年月")
.map(d =>{
//返される値は列エラーがあり、tsvFormatで数字変換を上手く行えなかった
// よって、ここで数字 年月を変更する
//年月変更
const date_obj = ({"年":1,"月":1});
[date_obj["年"], date_obj["月"] ] = parseDate(d["発売年月"]);
d["発売年月"] = date_obj;
//通巻番号 変更
d["通巻番号"] = parseInt(d["通巻番号"], 10);
//ページ数変更
d["ページ数"] = parseInt(d["ページ数"], 10);
return d;
});
}
Insert cell
parseDate = function(str){
// 197601 の文字を => 1976 と 1 の数字にする
const y = str.substr(0,4);
const m = str.substr(4);
return [parseInt(y, 10), parseInt(m, 10)];//[年, 月]を10進数字にして返す
}
Insert cell
makeDataObj = function(array, d_lab, findFunc= (d_,lab_)=> d_[lab_] ){
//findLabDataはラベルに一致するデータを返す
//データをlabel毎のkeyで分類し、obj化
const by_label_obj = {};
array.forEach(d =>{
const label = findFunc(d, d_lab);//関数に一致するデータを返す
if(by_label_obj[label] === undefined) by_label_obj[label] = [d];//配列生成
else by_label_obj[label].push(d);
});
return by_label_obj;
}
Insert cell
findTitleData = function(d, d_lab){
}
Insert cell
Insert cell
Insert cell
makeX = function(min_val,max_val){
return d3.scaleLinear()
.domain([min_val,max_val])
.range([margin.left, width - margin.right]);
}
Insert cell
makeY = function(min_val, max_val){
return d3.scaleLinear()
.domain([min_val, max_val])
.range([height - margin.bottom, margin.top]);
}
Insert cell
histogram = function(label, x_,num_bar=30){
return d3.histogram()
.value(d => d[label])//各データの使用する値
.domain(x_.domain() )//x軸のドメイン
.thresholds(x_.ticks(num_bar));//ticksは、xのdomainをnum_bar数分 分割した数を入れた配列を生成?
}
Insert cell
md`***
### css宣言`
Insert cell
html`<style>

#spike-div-container{
position: absolute;
font-size: 8.45px;
width: 100px;
}

.author-spike-div{
background-color: rgba(0, 0, 0, 0.4);
color: #fff;
}


#spike-div-overtip{
position: absolute;
padding: 0 2px;
background-color: rgba(0,0,0,0.4);
color: #fff;
font-size: 14px;
}


.pub-num-spike-div-overtip{
padding:0 0.5em 0 1em;/*左右隙間(右が少し多めの隙間)*/
font-size: 12px;/* 元のfont-sizeより少し小さめ */
}
</style>
`
Insert cell
Insert cell
d3 = require("d3@5");
Insert cell
import {select} from "@jashkenas/inputs"
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