The Heiss Family’s 2025 books
  • Overview
  • See all books
    • Andrew’s books
    • Nancy’s books
    • Rachel’s books
    • Miriam’s books
    • Benjamin’s books
    • Zoë’s books
    • Alexander’s books
The Heiss Family’s 2025 books

all_people = ["alexander", "andrew", "benjamin", "miriam", "nancy", "rachel", "zoe"]

schema_loading = all_people
  .reduce((obj, person) => {
    obj[person] = {
      name: [person],
      count: [html`<i class="fa fa-clock fa-spin"></i>`],
      most_recent: {
        title: [html` <i class="fa-solid fa-ellipsis fa-fade"></i>`],
        author: [html` <i class="fa-solid fa-ellipsis fa-fade"></i>`],
        date: [html` <i class="fa-solid fa-ellipsis fa-fade"></i>`]
      },
      data: {
        timestamp_local: null,
        total: null
      }
    };
    return obj;
  }, {});

schema_404 = all_people
  .reduce((obj, person) => {
    obj[person] = {
      name: [person],
      count: [html`<span class="fa-stack"><i class="fa-solid fa-cloud fa-stack-1x"></i><i class="fa-solid fa-slash fa-stack-1x" style="color:#FF4136"></i></span>`],
      most_recent: {
        title: [html` <i class="fa-solid fa-triangle-exclamation"></i>`],
        author: [html` <i class="fa-solid fa-triangle-exclamation"></i>`],
        date: [html` <i class="fa-solid fa-triangle-exclamation"></i>`]
      },
      data: {
        timestamp_local: null,
        total: null
      }
    };
    return obj;
  }, {});

schema_error = all_people
  .reduce((obj, person) => {
    obj[person] = {
      name: [person],
      count: [html`<i class="fa-solid fa-bomb"></i>`],
      most_recent: {
        title: [html` <i class="fa-solid fa-bomb"></i>`],
        author: [html` <i class="fa-solid fa-bomb"></i>`],
        date: [html` <i class="fa-solid fa-bomb"></i>`]
      },
      data: {
        timestamp_local: null,
        total: null
      }
    };
    return obj;
  }, {});
d3 = require("d3")

books = {
  // Provide an empty array with placeholder values until the data loads
  yield schema_loading
  // yield undefined
  
  yield fetch("https://api.andrewheiss.com/books?person=all&start_date=2025-01-01&end_date=2025-12-31")
    .then(response => {
      if (!response.ok) {
        throw new Error('Network error');
      }
      return response.json();
    })
    .then(people => {
      for (let person in people) {
        people[person].data = people[person].data.map(d => ({
          ...d,
          timestamp_local: new Date(d.timestamp_local_as_utc)
        }));
      }
      return people;
    })
    .catch(error => {
      if (error.message === 'Network error') {
        console.error('Error with the API call:', error);
        return schema_404;
      } else {
        console.error('Some general error:', error);
        return schema_error;
      }
    });
}
Alexander’s books

Write down a book

Last read: , on

Alexander’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.alexander.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#1D6996",
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})
Zoë’s books

Write down a book

Last read: , on

Zoë’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.zoe.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#5F4690",
          size: 5,
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})
Benjamin’s books

Write down a book

Last read: , on

Benjamin’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.benjamin.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#0F8554",
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})
Miriam’s books

Write down a book

Last read: , on

Miriam’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.miriam.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#CC503E",
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})
Rachel’s books

Write down a book

Last read: , on

Rachel’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.rachel.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#38A6A5",
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})
Nancy’s books

Write down a book

Last read: , on

Nancy’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.nancy.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#94346E",
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})
Andrew’s books

Write down a book

Last read: , on

Andrew’s total books

Plot.plot({
  style: {
    fontSize: "14px",
    fontFamily: "Libre Franklin",
  },
  marginBottom: 0,
  marginLeft: 0,
  y: {
    label: "Books read",
    grid: false,
  },
  x: {
    label: "Month",
    domain: [new Date("2025-01-01"), new Date("2025-12-31")]
  },
  marks: [
    Plot.axisX({label: null, ticks: null}),
    Plot.axisY({label: null, ticks: null}),

    Plot.rectY(books.andrew.data, 
      Plot.binX(
        {y: "count"},  // Reducing function
        {
          x: "timestamp_local", 
          y: "total", 
          fill: "#E17C05",
          interval: d3.utcMonth,
          inset: 2,
          tip: {
            format: {
              x1: (d) => d3.utcFormat("%B")(d),
              x2: false,
              y: true
            }
          }
        }
      )
    )
  ]
})