From Data Analyst to Data Storyteller in 3 Steps | by Max Hilsdorf | Towards Data Science

Why you need to learn this
It is widely known that various forms of data preparation make up more than 80% of a data scientists job. This is a valuable piece of information given that new people getting into the field seem to think it is all about expensive computers and complex deep learning models. You might be able to impress your coworkers in the data team with those things, but your managers and customers generally don’t care much about technical details. However, it is crucial to get your work noticed and understood correctly by exactly these people. This is why you need to learn data visualization!
To some, data visualization is just bothering with annoying stakeholders. This is an unproductive way of thinking, and it is also wrong! Think about it this way instead:
If you can’t visualize your results, you don’t know your results.
Everyone and their grandmother can create some one-liner scatterplot and call it data visualization. It takes a passionate and skilled data scientist, however, to transform basic visualizations into a story, that your managers and customers will not only understand, but be excited about and inspired by. In this article, I am going to help you take your skillset to the next level! All it takes is to follow a simple three step procedure that you can apply to every single one of your visualizations. Your managers, customers and future employers will be thankful for your effort to read this story!
What does a bad visualization look like?
Try to imagine some of your first matplotlib visualizations. Chances are, they might look like Figure 1. What I tried to do here is visualize the popularity of various musical genres in different age groups.
This lineplot is produced by the following code:
fig, ax = plt.subplots(figsize =(10,6))# Loop through the genresfor i, g in enumerate(genres):  # Define x and y x = np.arange(7) y = music_pref_2019[g]  # Plot lines ax.plot(x, y, label = g)  # X axis ax.set_xticks(x) ax.set_xticklabels([“14–19”, “20–29”, “30–39”, “40–49”, “50–59”, “60–69”, “70+”]) ax.legend()plt.show()
There’s a lot of things wrong with this plot. We are going to improve it in these three steps:
Add InformationReduce InformationEmphasize Information
Add Information
Reduce Information
Emphasize Information
The signal/noise ratio describes the amount of valuable information compared to the amount of unnecessary information. In any creative product (articles, visualizations, musical compositions), we should aim to maximize this ratio.
We can improve the signal/noise ratio by adding useful information, but also by removing useless information. In an ideal visualization, all of the important information arepresent and emphasized while everything that does not add any real value is removed.
Let’s brainstorm what the plot in Figure 1 is missing. Here are the observations I made. We need to add:
a titleaxis labelsticks and ticklabels for the y-axisa way to read single values for different age groups directly from the lines
a title
axis labels
ticks and ticklabels for the y-axis
a way to read single values for different age groups directly from the lines
We can do this by including the following lines of code to our full visualization code:
# 1ax.set_title("Popularity of Different Genres by Age Groups")# 2ax.set_xlabel("Age")ax.set_ylabel("Amount of people with preference (%)")# 3ax.set_ylim(0,1)ax.set_yticklabels(int(i*100) for i in ax.get_yticks()) # Turns the # decimals into percent values# 4ax.scatter(x, y) # adds points at every tick of x
On top of this, I selected different colors for our lines. The matplotlib standard colors are hard to deal with for colorblind people (like myself). Therefore, I have used only colors from the tableau colorblind palette in the plot below.
We can clearly see an improvement from Figure 1 to Figure 2 in terms of the amount of information given! Through adding relevant information, we have improved our signal/noise ratio. We need to protect the relevant information at all costs! It would be easy to just leave it at that since everything we need is included in the visualization in some form. However, this is where the magic can happen. Step 2 and 3 are going to keep all the relevant information, but use certain techniques to make the whole chart more clear and easier to read.
Reducing information doesn’t always mean actually deleting information like labels, legends or ticks. Sometimes, it just means reducing the extent to which the information is an obstacle to the reader. Here are some ideas on what to do with this plot:
We can:
remove ticksremove spinesremove the big legend and write the labels on each line directlyleave only 4 ticks on the y axisremove the x and y labels and indicate them on the last tick directly
remove ticks
remove spines
remove the big legend and write the labels on each line directly
leave only 4 ticks on the y axis
remove the x and y labels and indicate them on the last tick directly
# 1ax.tick_params(bottom = False, top = False,                  left = False, right = False)# 2for key, spine in ax.spines.items():    spine.set_visible(False)# 3ax.text(0,.875, "Rock/Pop", rotation = -1.5)ax.text(0,.144, "Classical", rotation = 16)ax.text(0,.395, "Hardrock/Metal", rotation = 4.5)ax.text(0,.679, "Hip Hop/Rap", rotation = -31)ax.text(0,.592, "Techno/House", rotation = -15)# 4ax.set_yticks([0,0.25,0.5,0.75,1])# 5ax.set_xticklabels(["14-19", "20-29", "30-39", "40-49", "50-59", "60-69", "70+ years"])ax.set_yticklabels([0, 25, 50, 75, "100%"])
Now that we have added all the relevant information and removed everything that is not, we can still optimize our visualization. Maybe there is something we can do to emphasize certain aspects. Here is a couple of ideas for this specific plot:
Change font, fontsize, and weight of the titleEmphasize the continuous quality of the data
Change font, fontsize, and weight of the title
Emphasize the continuous quality of the data
To change the title font, we can create a font_dict and call it in the ax.set_title() function.
title_font= {"family" : "Cambria",             "size" : 16,             "color" : "black",             "weight" : "roman"}# LATER IN THE CODEax.set_title("Popularity of Different Genres by Age Groups", fontdict = title_font)
To emphasize the continuous quality of the data, we need to get rid of the category label and use the mean age instead. For classed variables, we don’t know what the mean age of participants in any age category was. We can use the rounded mean of the possible ages in the category, however. Our mean age m for any category c would be:
m = int(c_start + c_end)
Now, we can use these mean ages as your y axis labels:
ax.set_xticklabels(["17", "25", "35", "45", "55", "65", "70+ years"])
To further emphasize the continuous features of our data, we can decrease the dot sizes and transparencies while increasing line sizes:
ax.scatter(x, y, c = cb_colors[i], label = mapping_dict[g], marker = ".", linewidth = 3, alpha = 0.8)ax.plot(x,y, c = cb_colors[i], linestyle = "-", linewidth = 2.5, alpha = 0.8) # lowering alpha is also good here, as it gives more attention to the annotations and labels
I have also increased the annotation sizes to 12pt.
This will give us our final output (Figure 4).
Here, we can clearly see that the lines start to make sense. While this is not exactly what the data tells us (it’s categorical after all), our mean ages allow us to tell an actual story. With this visualization, we can predict how preferences change with age, not only compare how they are different between ages. The dots still allow us to target a specific age and see the exact values for it, while also revealing that the connections between dots are linear predictions, not actual data.
We could also go the other route and emphasize the categorical features of our data. Figure 5 is an example of that approach.
Here, I emphasized the points and added a grid in the background. I also kept the original category labels.
In this article, I showed you how you can use a three-step formula to improve your matplotlib visualizations. One key thing to take home from this post is that the magic lies not within the information you add, but within the information you remove or transform. Look at Figure 1 and compare it to our final results. Then check your own recent visualizations and see if you can make use of the three-step formula to make them even better!
Thanks for reading!