MIC drop! Representing antibiotic susceptibility as a stylized heatmap with R's ggplot2


Hey folks,

We had a lot of fun last week with my first workshop on the theory of data visualization! If this is something that you’d be interested in participating in let me know. At this point, I don’t have anything scheduled. So, if you have suggestions for days or times, please let me know


This week I have a fun figure to share with you from a paper recently published in Nature Microbiology, titled, “Candida auris skin tropism and antifungal resistance are mediated by carbonic anhydrase Nce103”. Figure 2a caught my eye

If you’re a microbiologist, you might notice that it resembles a microtitre plate that are often used for performing antibiotic susceptibility testing in solution. For the uninitiated, imagine you have a 96-well plate. Each column has a different step in a dilution series of antibiotic added to growth media. In this case there are 2-fold dilutions of Amphotericin B applied across the columns. All columns of a given row are inoculated with a different strain of bacteria. After incubating the plate you can score the dilution where bacteria stop growing. This is the “minimum inhibitory concentration” or “MIC”. You can see an example of this as performed on agar in panel e of this figure. The method used by these authors allowed them to score the amount of growth relative to the column with no antibiotic added. As I mentioned, if your eyes look like mine, you can see this looks like a microtitre plate. How would we make this in R?

Well, if your eyes look like mine, this panel resembles a heatmap. Instead of having rectangular tiles, this panel has circles that are filled according to the relative growth level. As an added wrinkle, this experiment incubated the assay at three different CO2 levels making for three facets across the panel.

Thankfully, the authors made their data available as a Microsoft XLSX workbook. If you open tab “F2A”, you’ll see the data for this figure. The data frame is already “tidy” with columns for the strain, amount of antibiotic, CO2 concentration, and relative growth. As we’ve seen in recent videos, we can read these workbook pages in to R using the read_excel() function from the {readxl} package.

From here I think it is relatively straightforward to create the basic figure. On the x-axis we map the concentration of the antibiotic. On the y-axis we map the strain. We would then map the relative growth to the fill color. We can use geom_point() to draw the plot. I’d use my favorite plotting symbolTM, 21, which will allow us to have one color for the fill and one for the border. A more challenging step is denoting the MIC for each strain. This is denoted by a red border to the circle and the “MIC” text in the middle of the circle. I’d map whether the concentration was the MIC to the color of the circle with the MIC getting a red color and everything else getting black. To insert the “MIC” in the circle, I’d use geom_text(). Not too bad, eh?

I feel like another unique element of the figure are the text elements. First, consider the legend. The title is rotated. I think this can be done using the theme() function with the legend.title argument. This argument will take the element_text() function, which has an angle argument that we can set to 90. Next, the x-axis text has the dilutions at a 45 degree angle. Here again, we can set the angle argument for element_text() when assigned to the axis.text.x argument of theme(). We will likely have to fiddle with the hjust and vjust arguments in element_text() to get things to look right. The y-axis has a mix of italicization and Greek letters in the text. We will likely have to set the order of the strains using factor() and can also change the labels of the strains to incorporate unicode and markdown to add the delta characters and italicization where needed. Finally, the facet strips and x-axis title will also need some markdown to add sub and super script characters. All of this markdown can be rendered using the {ggtext} package’s element_markdown() function in place of the element_text() function.

Finally, I’d be chickening out if I didn’t mention the vertical lines between the three facets. I feel like we’ve done something like this in the past using annotate() with geom = "vline" and the layout argument that new to {ggplot2} v.4.0. I think this should work 🤓

What do you think? Can you pull this off on your own? Give it a try! I’ll be recreating it along with some tweaks to make it better (IMHO) next Wednesday during a livestream on YouTube. Also, stay tuned for Monday when I’ll release a critique of this plot discussing what I like or don’t like.

Workshops

I'm pleased to be able to offer you one of three recent workshops! With each you'll get access to 18 hours of video content, my code, and other materials. Click the buttons below to learn more

In case you missed it…

Here is a livestream that I published this week that relate to previous content from these newsletters. Enjoy!

video previewvideo preview

Finally, if you would like to support the Riffomonas project financially, please consider becoming a patron through Patreon! There are multiple tiers and fun gifts for each. By no means do I expect people to become patrons, but if you need to be asked, there you go :)

I’ll talk to you more next week!

Pat

Riffomonas Professional Development

Read more from Riffomonas Professional Development

Hey folks, If you missed it, on Wednesday I did a livestream where I made a stacked barplot and pronounced it good. No, I wasn’t drinking anything! But it’s a reminder to think about the question before finding the best data visualization strategy. I think this highlights the value of the constructive approach I’ve been trying to take to critiquing data visualizations. The first steps are to establish the question and figure out the question. If you aren’t a “regular”, I think you’re really...

Hey folks, As I mentioned last week, I’m exploring the possibility of holding live, in person, workshops again like I did before the pandemic. If this is something that interests you, please let me know. My thought would be to hold them at an affordable hotel near the Detroit airport (DTW). But, if you would like to host me to teach a workshop, I would be open to that as well. This week, I want to call your attention to a plot that I would not encourage you to make. This comes form “Targeted...

Hey folks! I’m hoping to host two workshops in March and April. The first would be a Zoom-based workshop on the principles of data visualization (I taught a version of this last month). This would be a code-free workshop and would run for about 3 hours. I don’t have a date yet. If you are interested, please reply to this email and let me know if there is a date and time in March that would work best for you. The second would be an in person 3 day workshop taught near the Detroit airport. I...