Today, I signed the contract for an apartment in Utrecht. Yay!
Often people ask me: “Why do you move to Utrecht?”
There are so many factors. I like the vibe of the city; I have many friends there; It’s close to Amsterdam; It’s the center of the Netherlands and it has the biggest train station in this country. Haha, then I downloaded my train travel records since I moved to the Netherlands and made a bar chart.
The fact is that I have been to Utrecht a lot. I live near Amsterdam Zuid, so 80 trips were just coming back home. The second most visited station is Utrecht Centraal. If you count all the stations in Utrecht, I have been to this city 37+4+1 = 42 times. If the exposure effect theory with people also applies to cities, I guess I fall in love with this city because I have seen it too frequently.

Okay, let’s talk about how to create this bar chart now. 🙂
scaleBand
There are two methods to create a bar chart. One is “d3.bin( )” if we have numerical data and need to group them into bins first. Another method is “d3.scaleBand( )” if we have categorical data. Here the train station is a categorical value, and frequency is a numerical value, which will use the “d3.scaleLinear( )” as we used before.
const yScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.range([0, chartHeight])
.round(true)
.padding(0.25)
Create Bars
Each bar in the bar chart is actually a rectangle. We will need to define four parameters to draw the rectangle: x, y, width, and height. x & y are the starting coordinate of a rectangle,
const bar = chart.append("g")
.attr("fill","#FFC917")
.selectAll("rect")
.data(dataset)
.join("rect")
.attr("class", yAccessor)
.attr("x", xScale(0))
.attr("y", (d, i) => yScale(i))
.attr("width",
d => xScale(xAccessor(d)) - xScale(0))
.attr("height", yScale.bandwidth())

Adding Text
I didn’t create a y-axis or x-axis for this bar chart. I simply used the text. I created two sets of text. One is for the train station name, which is anchored with “end” and shifted to the left a little bit. Another set is the frequency of the visits, which is placed on the right of the bar. Since it’s placed right of the bar, I put the “text-anchor” as “start” and shifted to the right 4px to avoid overlapping with the right edge of the bars.
chart.append("g")
.attr("text-anchor", "end")
.attr("font-family", "sans-serif")
.attr("font-size", 16)
.attr('font-weight', 600)
.selectAll("text")
.data(dataset)
.join("text")
.attr("x", d => xScale(0))
.attr("y", (d, i) => yScale(i) + yScale.bandwidth() / 2)
.attr("dy", "0.35em")
.attr("dx", -4)
.attr("fill", "#003082")
.text(d => yAccessor(d))
chart.append("g")
.attr("text-anchor", "start")
.attr("font-family", "sans-serif")
.attr("font-size", 16)
.attr('font-weight', 600)
.selectAll("text")
.data(dataset)
.join("text")
.attr("x", d => xScale(xAccessor(d)))
.attr("y", (d, i) => yScale(i) + yScale.bandwidth() / 2)
.attr("dy", "0.35em")
.attr("dx", +4)
.attr("fill", "#003082")
.text(d => xAccessor(d))
I modified the code from Observable Horizontal Bar Chart. My codes are here.