Jesse Martin
Open GraphQL
Published in
5 min readJul 16, 2018

--

I recently wrote a large tutorial for my company, GraphCMS, about creating a project from start to finish. We cover everything from analysing data-types to pulling the data into the client. It’s well worth the read and is split into two parts:

The tutorial: 👉 Link
The visual: 👉 Link

In the process, however, I uncovered some additional power-tips for data visualisations that really let GraphQL shine.

GraphQL for Data-visualisation

For a reference, here’s two of the charts that were created:

An interactive chart that found the cross-section of wines shared between multiple food classes.

So, it wasn’t a design tutorial. But what it did reveal to me is that GraphQL is really well suited for flexible data formatting! The database itself is a series of connected nodes based on the Wine Folly food pairing chart. A cool resource worth checking out in its own right.

The library I chose to use was D3. More or less a given in modern day, data visualisation. But I came across a handful of cases where I really needed the data formatted differently than it had come from the server. There’s a host of solutions to this kind of problem. You can use a library such as Crossfilter which is tailor made for this kind of situation. In my case, because the data set was small and I wanted to perform fewer network requests, I just brute force reformatted the data in Javascript.

But if you have the luxury of, say, 2–3 API requests IN TOTAL (i.e. a perfectly acceptable tolerance IRL) then GraphQL can come to our rescue. According to the spec, we are able to make one very important assumption about the network response. The data will respond exactly as the request was made.

This means making a request like:

// Request 1
{
people {
name
age
height
}
}
// Request 2
{
people {
height
age
name
}
}

would return the same data but in the specific orders requested.

The Basic Ideas

In D3 the order of data is often important. Placing a series of lines across the page is a matter of looping over the data. If you want to nest content inside of those shapes, the most effective way is to have your data structures also nest in a similar matter.

The most common pattern being Loop over 3 items, make a group for each, enter each group and add data for the nested items.

To create the chart above, I did a basic search for all the Food Classes and their contained foods and their related wine pairings. It’s a simple query that looks like this:

{
foodClasses(orderBy: foodCategory_ASC) {
name
foodCategory
foods {
name
}
wineClassPairings(orderBy: slug_ASC) {
name
slug
wines {
name
wineClass {
name
}
}
}
wineClassWFPPs(orderBy: slug_ASC) {
name
slug
wines {
name
wineClass {
name
}
}
}
}
}

Don’t worry about the specifics of our syntax, the gist of what it does should be clear.

A Crash Course in D3

A key concept in D3 are the scale functions. I cover them in the visual part of my tutorial, but the basic idea is that if I tell my function to accept a range of [1..5] and to output a color value between Red and Blue, I would expect 2 to be very “reddish” and 4 to be some kind of purple.

Giving these functions the correct input data is important. The majority of my scales took a “discrete” input, meaning I would give it one of a concrete set of values (as opposed to any floating point between 1 and 5, for example.) This would allow me to give my function the top most Food Class in from my data response and get a value close to 0 for being near the top of my chart, and the last Food Class in my response would give me something near the bottom of my chart. In my case, my discrete array of values mapped to something like [0..1200].

How GraphQL Helps

But how do I get a reduced set of values of wine classes? My data response has many duplicates, and if this were a larger data set, it could be 10’s of thousands — not something I want to do on the client!

Well, in GraphQL. We can simply ask for this exact subset of data!

{
wineClasses {
name
}
}

Another issue came up with the Food Category labels on the left. This took a little bit of D3 hackery, but the basic concept was to loop over each Food Category, get the subset of related Food Classes, and, as described above, use the Food Class scale function on the first subset Food Class and the last Food Class to get the positions of where my shape should start and stop. Cool! Sounds like a logical idea, doesn’t it! The only problem is, my data is not structured for that! Not even close!

This allows us to bring in a really powerful concept in GraphQL called Aliases.

Aliases for the Win!

Aliases allow us to map our response to a new key:value pair. It can be completely arbitrary and it gives us great flexibility. An example of this query would then look like this:

query getFoodPairing() {
Vegetables: foodClasses (
where:{
foodCategory: Vegetables
}) {
name
}
Dairy: foodClasses(
where: {
foodCategory: Dairy
}) {
name
}
Meat: foodClasses(
where: {
foodCategory: Meat
}) {
name
}
...
}

In fact, we could simply append a generic helper request on our original data request to get an alias of our formatted data like this:

...
wineClasses(orderBy:slug_ASC) {
name
}
foodCategories: foodClasses {
foodCategory
}

And so, by simply changing our request structure we are able to get the data, both the content and SHAPE as needed from the server.

As you can see, the flexibility in which we are able to request our data and change it’s shape depending on any arbitrary reason is a powerful paradigm for data exploration and the layout out of our designs. The syntax I used is part of the opinionated stack behind GraphCMS but writing your own resolvers and directives can create even more powerful abilities.

I hope you found this quick read interesting and I invite you to play with the data yourself! The API can be found at https://api-euwest.graphcms.com/v1/cjj75a4cx05hv01gg1zjttejo/master

Check out GraphCMS if you want the best of both worlds! A powerful, API driven CMS with a completely open API for the developers and a thoughtful UI for content creators and those less comfortable in the terminal.

Thanks for reading!

--

--