On Baseball Savant (https://baseballsavant.mlb.com), they have these great visualizations for displaying percentile rankings. Basically, out of the population of MLB athletes, where does a player stand in comparison for a given statistic? In the photograph below, Iâ€™ve snipped a few stats (Exit Velocity, xBA, K%, and Sprint Speed). Weâ€™re going to replicate this visualization using d3 today. (For the record, this is Daniel Vogelbach (MIL) vs. 2020 season data)

First, Iâ€™ll assume you have some familiarity with d3 as well as some familiarity with what *slight* modifications will be necessary between traditional d3 and the code weâ€™re going to write today, which is d3 formatted for Observable (https://observablehq.com). Letâ€™s load in d3:

Next, we need to set up a helper function to get our cx values. Because the width of our canvas is going to be 150 pixels but percentiles are ranged 0-100, we have to do some calculation for the actual x values:

Now, letâ€™s add our data. Weâ€™re going to format our data as a collection of objects that hold information about the statistic label, the value of the statistic (this will be our cx value, so weâ€™re going to utilize the `getX()`

function weâ€™ve just written), and the y-value of where the statistic will be displayed:

Weâ€™re cookinâ€™ with gas, now! Letâ€™s define our SVG:

The first thing weâ€™re going to add to our new `svg`

is the horizontal lines in which each percentile ranking will be displayed. This is pretty simple to do, because the x1 and x2 values will be 0 - 160 (we just want to go straight across our svg which has a width of 170), and the y1 and y2 values will be the same (and theyâ€™re the `cy`

key in our `percentileData`

object):

The horizontal lines are a good start, but they donâ€™t look the same as Baseball Savantâ€™s horizontal lines doâ€¦ yet! Baseball savant has circular decorators on their lines at the 0, 50, and 100th percentile positions. This makes it easy to identify how far off the measure of center a player is. Letâ€™s add these now:

Much better. Now, the fun part. Letâ€™s add our circles that indicate where a player ranks in relation to other players in the MLB. To do this, weâ€™re going to need to do some more math for the label positioning, but weâ€™re also going to need to make use of `d3.interpolateRdBu()`

. The value that goes inside of this function (which just colors the circle) is going to be the inverse of what we *actually* want, so weâ€™re going to subtract our real value from 1 to get the desired color. Note that weâ€™re not actually putting the label on the circle yet, weâ€™re just trying to figure out where the label would be positioned on the line so that we can color it appropriately:

Look at that! Itâ€™s close, but weâ€™re still missing labels. Both for the statistic weâ€™re showing and for the actual percentile ranking number. Letâ€™s do the labels for which statistic weâ€™re showing first:

This is looking really good. The last step (displaying the percentile ranking number) requires the use of another helper function. Because of the font sizing, we need to tweak our x values a bit before slapping them on our svg:

At first it looks like hocus pocus, but you should be able to see why this is an important step. (hint: itâ€™s due to the svg size being 170, percentiles ranging from 0-100, and the fact that the values may be 1 digit long, 2 digits long, or 3 digits long.)

Okay, letâ€™s finally get our text labels up and running:

Tada! The final product looks great, and itâ€™s an easy way to visualize percentile data. I hope youâ€™ve enjoyed this quick walkthrough. The full observable notebook is available here: https://observablehq.com/@jakenherman/visualizing-percentile-data.