Chartbuilder’s many friends and the value of open source
It’s been eight months since we open-sourced Chartbuilder, our tool for quickly making good-looking charts. In releasing the project to the public, we hoped it might promote visual journalism and that new contributors would help make Chartbuilder better.
We’re happy to report success toward both goals.
Since we released it to the public, Chartbuilder has been used to make thousands of charts for at least a dozen media organizations, including NPR, the Wall Street Journal, the New Yorker, CNBC, the Press-Enterprise, and New Hampshire Public Radio. Just last week, ESPN’s FiveThirtyEight joined the Chartbuilder club.
Isn’t that beautiful? Chartbuilder’s proliferation gives us renewed confidence in our commitment to open-source journalism. We hope it also inspires others to implement the tool and contribute back to the project on GitHub. Chartbuilder needs your help. It still has plenty of bugs and room for improvement.
In the coming weeks, we will be rolling out a new version of Chartbuilder that Quartz reporters have been using. It resolves some of the strange behaviors that have persisted for some time.
If you want to check it out before then, see this branch on GitHub. Or as always, use the current version online here and submit any bugs you come across here.
If you want to join us making tools like this and reporting through code: we’re hiring.
How we found the center of international air travel
While I was making “29 of the world’s largest bike-sharing programs in one map,” my colleague Ritchie sent along a New Yorker article from March about Neil Freeman, the man who created “Subway systems at the same scale" that inspired the bike map.
In the article, Freeman brought the New Yorker’s Jason Fagone to the geographic center of New York City’s road intersections.
It was a unfamiliar concept to grasp, but Fagone described it like this:
if the city was a giant cookie tray and you put a tiny weight on every intersection, the tray would balance on this point.
We like writing about air travel at Quartz, so I thought I’d try creating a similar map, at a global scale, with airports. Then, to make the results more meaningful than “this is the center-most airport,” I decided to weight every airport by the number of routes that came out of it.
When calculated for the entire world, it would show the average midpoint of every airline route. When calculated for a country, it could show the average destination.
I wasn’t entirely sure of the proper math to do this, so I just tried to replicate the cookie tray analogy: For every country, take the destinations of every departing route and average the latitudes and longitudes of every destination.
This was the result
All the calculated center’s of gravity were clustered in the Atlantic Ocean: clearly wrong.
The limits of the cookie sheet method was revealed. Cookie sheets are flat and have a cartesian coordinate system, but planets are round and have a polar coordinate system.
Before submitting myself to the mind-bending geometry that is three-dimensional trigonometry, I searched the internet to see if someone else has tried to accomplish the same.
I found this question on the GIS Sack Exchange—”Computing an averaged latitude and longitude coordinates"—and converted the code to Python, which is what I was using to parse and combine the three databases from OpenFlights.
"""Convert a tuple of lat,long to x,y,z"""
latD,longD = t
latR = math.radians(latD)
longR = math.radians(longD)
"""Convert a tuple of x,y,z to lat,long"""
x,y,z = t
r = math.hypot(x,y)
if r == 0:
if z > 0:
elif z< 0:
#use numpy to allow for easy vector and matrix math
xyz = numpy.asarray([0.0,0.0,0.0])
total = 0
for p in points:
weight = p["weight"]
total += weight
xyz += numpy.asarray(toCartesian((p["lat"],p["long"])))*weight
avgXYZ = xyz/total
avgLat, avgLong = toSpherical(avgXYZ)
New code written, I tested out another map:
That pink dot is supposed to be the center of gravity for the flights from Saudi Arabia shown… It’s not.
Looking for some help, I posted my code to the GIS Stack Exchange, tweeted it, and retweeted it.
Turns out I had a bug in my code (not shown above), but when I went and tried the data again, I still had issues.
A math nerd friend chatted me. We talked it over. He asked if I had tested it. Turns out I hadn’t…I’m an idiot.
I ran some tests on the averaging code I wrote and made some test maps. (The pink dot is the calculated center)
Turns out that was all working, it was my input data that was wrong. So I rewrote my parser and tried again:
If you’re wondering, I was using Tilemill to make these maps from the CSV files my Python script exported. To create the flight paths and lines connecting the center of gravities to the country I put a geojson blob in the CSV.
That method allowed me to make a map of all of the international routes:
Unfortunately, Tilemill draws the lines connecting points after the map data is projected. This means that the paths shown are not actually the shortest distance between the two points.
The only way to accomplish this was to write some more code that would convert two endpoints into a series of points along the great circle that runs through it. I found the formula here, converted it to Python and created a way to loop through it.
There were typos and bugs:
But I figured out the code eventually:
lat1 = math.radians(start)
lon1 = math.radians(start)
lat2 = math.radians(end)
lon2 = math.radians(end)
A = math.sin((1-f)*d)/math.sin(d)
B = math.sin(f*d)/math.sin(d)
x = A * math.cos(lat1) * math.cos(lon1) + B * math.cos(lat2) * math.cos(lon2)
y = A * math.cos(lat1) * math.sin(lon1) + B * math.cos(lat2) * math.sin(lon2)
z = A * math.sin(lat1) + B * math.sin(lat2)
# 3963 is the radius of the earth
num_points = float(round(greatCircDistance(start,start,end,end)/(3963/2)*15))
if num_points < 4:
#make sure there are at least 4 points on the path
num_points = 4
pnts = *int(num_points+1)
dist = arcD(start,start,end,end)
for i in range(int(num_points+1)):
pt = greatCircPoint(start,end,dist,(i/num_points))
pnts[i] = pt
The exported maps from Tilemill looked something like this:
and after the final touches in Illustrator:
See the rest of the maps and read “The average destination of international flights from every country in the world" and "The center of the international airline industry is in the middle of rural Poland" on Quartz.
Get your hands on the same flight data we used from Openflights.
Plotting some dots
Like every news organization and their sisters this week, Quartz felt compelled to acknowledge the (delayed) launch of the New York City bike sharing program.
As is always the case here at Quartz we try to keep our content globally relevant. While the New York system is large, it’s really late to implementing this type of policy compared to other cities around the world. There are already more than 500 municipalities with similar systems.
To say the least, I was skeptical that we should be covering this story.
But then like a super hero in comes Roberto with a instant message, “here’s a website with all of the information you’d ever want about a whole bunch of bike sharing systems http://bikes.oobrien.com/”
The site had geolocation data for 85 cities.
I saw it and immediately knew what I was going to do , then sketched something highly detailed to sell everyone on it:
The top was what I drew then, the bottom came later. I tried to find links to the subway maps I had seen displayed in similar ways, but I couldn’t find them at the time. “Trust me, It’ll be great,” I said.
(I found those links later, here, and here)
I collected the geo data from bikes.oobrien.com using a python script, opened it up in tilemill and exported a really big pdf map that looked like this:
An hour of Illustrator selecting grouping and resizing later and we had this:
Then some more fiddling, versioning, and alt-dragging:
some copy writing, and editing, and hand wringing over a Headline and kicker later, we published (sans kicker).
Read the story on Quartz: 29 of the world’s largest bike-sharing programs in one map
 It turns out that Oliver O’brien had made a similar map last year