Public
Edited
Jan 12, 2023
Insert cell
Insert cell
// make a timeline by date
// --> make this a beeswarm chart!
// stacked timelines of date finished each book (dk what to do about re-reads yet)
// add a data column and make a timeline of settings!!
// add a genre column and color books by genre! (and y value by genre for "shelves"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{ const width = 800;
const height = 200;
const marginLeft = 20;
const marginRight = 0;
const marginBottom = 0;
const marginTop = 0;
const smallFont = 12;
const medFont = 14;
const bigFont = 20;
const lightGray = "#999";
const medGray = "#777";
const darkGray = "#444";
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width*1.3, height*1.1])

const xScale = d3
.scaleTime()
.domain([Date.now() - 900 * 365.24 * 24 * 60 * 60 * 1000, Date.now()])
.range([0, width-marginRight]);
const yScale = d3
.scaleLinear()
.domain([10,0])
.range([0, height]);
const xAxis = d3.axisBottom(xScale); //.tickFormat(d3.timeFormat('%Y'));
svg
.append("g")
.attr("class", "axis x-axis")
.attr("transform", `translate(${marginLeft},${height})`)
.call(xAxis)
.append("text")
.attr("class", "axis-label")
.attr("x", "45%")
.attr("dy", "3em")
.text(`text`)
.attr("font-size", medFont)
.attr("fill", "none");
const yAxis = d3.axisLeft(yScale);
svg
.append("g")
.attr("class", "axis y-axis")
.attr("transform", `translate(${marginLeft},${0})`)
.call(yAxis)
.append("text")
.attr("class", "axis-label")
.attr("y", "50%")
.attr("dx", "-3em")
.attr("writing-mode", "vertical-rl")
.text(" ")
.attr("font-size", medFont)
.attr("fill", medGray)

// create circle for each key (word instance)
const rect =
svg.selectAll("rect")
.data(typed_data)
.join("rect")
.attr("x", (d) => xScale(d.setting_start_year) + marginLeft) // + jitter() (not great for squares but could work for circles
.attr("y", (d) => yScale(d.f_nf_num)) // would be cool to do this by genre
.attr("width", (d) => xScale(d.setting_end_year - d.setting_start_year)) //xScale(d.setting_duration)) //(d) => xScale(d.setting_date_end - d.setting_date_start +1)) //(d) => d.setting_duration) date.setFullYear(date.getFullYear() + years)
.attr("height", 20)
//.attr("cy", yScale(5))
//.attr("cx", (d) => xScale(d.original_publication_year))
// .attr("r", 2)
.attr("fill", lightGray)
.attr("opacity", .15)
.attr("stroke", "black")

svg.on("click", function() { // only mouseenter is needed -- change on next mouseenter
d3.selectAll('rect')
.attr("opacity", 0.15)
.attr("stroke", "black")
})

const tooltip1 = svg
.append("g");
svg
.selectAll("rect")
.on("mouseover", function(d) {
//console.log('this', this)
// tooltip
tooltip1.call(callout, `${d.title}, ${d.author}
set c. ${d.setting_start_year}-${d.setting_end_year}`)
tooltip1.attr("transform",
`translate(${xScale(1550)}, ${yScale(3)})`)
.transition()
.duration(500)
.attr("fill-opacity", 0.8)
})
return svg.node();
}

Insert cell
Insert cell
Insert cell
Insert cell
typed_data = d3.csvParse(await FileAttachment("goodreads_library_export-read@10.csv").text(), ({Title, Author, AuthorLF, AdditionalAuthors, MyRating, AverageRating, Publisher, Binding, NumberofPages, YearPublished, original_publication_year, setting_date_start, setting_date_end, setting_duration, setting_error_years, fiction_or_non, f_nf_num, genre, DateRead, DateAdded, ExclusiveShelf, ReadCount}) =>
({title: Title,
author: Author,
author_LF: AuthorLF,
additional_auth: AdditionalAuthors,
my_rating: +MyRating,
avg_rating: +AverageRating,
publisher: Publisher,
binding: Binding,
num_pages: +NumberofPages,
year_published: new Date(YearPublished).getFullYear(),
orig_publication_year: new Date(original_publication_year).getFullYear(),
setting_start_year: new Date(setting_date_start).getFullYear(),
setting_end_year: new Date(setting_date_end).getFullYear(),
setting_duration: +setting_duration,
setting_error_years: +setting_error_years,
fiction_or_non: fiction_or_non,
f_nf_num: f_nf_num,
genre: genre.split(', '),
date_read: new Date(DateRead),
date_added: new Date(DateAdded),
exclusive_shelf: ExclusiveShelf,
read_count: +ReadCount
}))
Insert cell
Insert cell
import {slider} from "@jashkenas/inputs"
Insert cell
Insert cell
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