Submind YouTube summaries
Thumbnail for Two methods of creating a jitter dodged slope plot in R with ggplot2 (CC429)

Two methods of creating a jitter dodged slope plot in R with ggplot2 (CC429)

Watch on YouTube

Video summary

This video tutorial focuses on refactoring a specific panel from a scientific figure published in *Nature Microbiology* to better visualize Shannon diversity data derived from paired mouse samples. The original publication presented fecal microbiome data collected before and after four different experimental perturbations, including controls, antibiotics alone, carboxymethylcellulose (ACR) alone, and their combination. A key critique of the original visualization was that it failed to reflect the paired nature of the experiment, where the same eight mice were sampled at two time points for each treatment group. To address this, the presenter demonstrates how to restructure messy Excel data into a tidy format using R's `readxl` and `tidyr` packages, ensuring that "before" and "after" measurements are properly aligned by replicate ID before plotting. The core of the tutorial involves creating two distinct methods for generating slope plots with jittered dodged points in ggplot2 to highlight changes over time within each treatment group. The first method employs a manual approach where the presenter programmatically calculates custom x-axis coordinates. By converting categorical variables into numeric indices, he applies specific dodge offsets and random jitter values using `runif` functions before plotting. This technique allows for precise control over point placement so that lines can be drawn connecting the "before" cloud to the "after" cloud within each treatment group, effectively visualizing individual animal trajectories while maintaining statistical rigor through paired t-tests or Wilcoxon tests. The second method utilizes faceting as an alternative strategy to achieve a similar visual result without manually calculating jitter coordinates for every point. In this approach, each of the four treatment groups is placed in its own facet using `facet_wrap`, which simplifies the process of connecting points with lines by grouping data based on replicate IDs rather than relying solely on position aesthetics that often fail when combined with random jittering. The presenter refines both plots extensively to match the original publication's dimensions and style, adjusting axis limits, font sizes, legend positions, and color schemes (using white for pre-treatment and dodger blue for post-treatment) to ensure clarity and aesthetic consistency. Ultimately, the video concludes that while both manual coordinate manipulation and faceting offer valid pathways to creating high-quality slope plots in R, each has its own trade-offs regarding flexibility versus ease of implementation. The presenter emphasizes that regardless of the chosen method, visualizing paired data by connecting pre- and post-treatment points provides a much clearer interpretation of experimental trends than unpaired scatterplots. By implementing these improvements, the refactored figures not only correct the original authors' visualization choices but also enable more powerful statistical comparisons to determine if changes in diversity are significant across different treatment groups, showcasing R's versatility in data visualization workflows.
Read the full video transcript
Hey folks, welcome back for another episode of code club. In this episode, I will be refactoring panel D from this set of panels in a figure published recently in the journal Nature Microbiology. This panel describes Shannon index Shannon diversity data for the microbiome of mice that underwent an experimental protocol where the investigators were able to obtain fecal samples from the mice before and after a experimental pertabbation. There are four different pertibbations. control where the mice weren't perturbed. Um ACR where the mice received a carbos, ABx where the mice received antibiotics and then ABX plus ACR which is the combination of antibiotics and a carbos. Again, they obtain the samples before undergoing one of these four treatments and then after these treatments. And so the before we're on day 21 of the protocol and the after we're on day 28. And when I look at panel D, as I did in a critique video that I posted a few days ago, I'll put a link to that critique video up here so you can go check out what I talked about in there. I mostly talked about panel F, but towards the end I also talked about panel D and some of the other panels. The gist of that critique is that the authors really did themselves a disservice by not visualizing the data in a manner that reflected the experimental design. Again, the same eight mice were sampled before and after the experimental protocol. At a minimum, the same mice should have been put next to each other. So, these eight control mice here on the left are the same as these eight control mice here in the saturated blue. And the same for the purple and the purple and the yellow and the orange and the pink and the red. Right? Put them next to each other to make them easier to see. But because the same mice were sampled across the the same treatment group, draw a line, right? And so now if you draw a line between the eight mice, it's easier for your audience to see the overall trend, the overall change. When you do a paired analysis like this, you're looking at the change. Not just the difference, but the change. And that difference is subtle, but it's important. And so what I'm going to do is I'm going to take two different approaches today to generating a slope plot version of this panel D. Again, this figure came from a paper published a few weeks ago in Nature Microbiology titled a carbos redirects gut microbiome utilization of dietary carbohydrates to suppress anoflaxis in mice. What that means, don't worry about it. As always, if you've watched my other videos where I do these types of critiques and refactorings and recreation videos, I always use plots where they provide the source data. Over here in R, I've already written the download file function statement to download that Excel workbook as the file figure 3xlsx. If you want to get any of the code that I am generating today, by all means do so. Down below in the description for today's episode, you'll find a link where you can get this code. Also down there is a link to the paper so you can go back and look at the paper, look up the figures, do your own critiques, try to recreate the data, recreate the visuals on your own. Uh that would be awesome. I love hearing how people are doing the same process that I'm doing on their own and then coming to see how I did it, right? That's just so beautiful and that's really just keeps me going doing these types of videos. So by all means, let me know how that works out for you. Also down there you will find a link to a sign up where you can sign up for a 30 minute slot in my calendar to let me know how I might be able to help you on your own data visualization journey. I'm happy to do coaching and consultations with individuals or research groups to help them design better figures and then implement those designs using R. All right, let's go ahead and load our libraries and download our Excel workbook that I'm again I'm saving as figure 3 XLSX. The data I'm interested in is in tab fig 3D. This is not tidy by any means. It's basically one row of data where they have before and after and then they have the four treatment groups. Within each treatment group, again, they have eight mice. They don't indicate the mouse number or the replicate number. I'm going to assume that this 5.074 value is paired with the control in the after this 5.5177 value. So I'm going to assume the first column corresponds to the first column before and after and second through 8th as well. All right. So we have a little bit of work to do to get this all read in. And so what I will do is I'm going to read in C5 to BN5. So before I forget, let's do C5 to BN5. So we'll do read Excel and we're going to do fig 3 XLS X. We're going to do sheet equals fig 3D. And if we do just that, we see we get a lot of ugliness and unhappiness and parsing from read Excel. So what I can do then is take this range and add that as an argument. I can do range equals that within quotes. Now what I get is a table with zero rows and 64 columns with these different variables. That's not what I want. I want to be able to add in column names. So I'll do call names, but I'm going to have to create my own column names. Okay. So, I'm going to call that variable call names. Not very original, I know, but hey, you got to come up with something. Naming things is hard. So, we'll do call names. Uh, let me hold on to that for a minute because we're going to want the replicates, we're going to want the treatment, and we're going to want the time, right? And so, uh, the replicates is going to be we'll do rep one to 8, and we're going to repeat eight times, right? And so if I run this, I should get 1 to 8 eight times as I do. And then for treatment, we're again going to do a rep on the vector CT RL AC ab. Then I'm going to repeat each eight times. So I do I get control eight times, but I also want to take this vector and I want to duplicate it. So I think what I can then do is times equals 2. And so that should take that set of 32 and duplicate it. And sure enough, I now have these eight controls. And then I also have these eight controls. Right? And so it's duplicating it to make it 64 units long. And then the time I'll do another rep where I will do before and after. And we'll do each 32 times. So now if I look at time, I've got 32 befores and 32 afters. Then I can pull all that together. Call names with paste. I'll do time treatment and replicates. And I'm going to do a separate by an underscore. And I'm going to go ahead and make sure I've got everything loaded. Now when I look at call names, I've got these column names. And now when I run read Excel, what I find is that I have my column names with my values. And this is not tidy. And I would like to get it to be tidy. So to get it tidy, I'm going to add a column that I'll call index. And I'll say one, right? And so we don't see it. It's at the very end, but trust me, it's there. If you want to see it, we could do before equals everything. And so now what you see is we've got that index column, right? We need that value for pivot longer because what I'll do in pivot longer, I'm going to take all of the columns except for the index column, right? And so that then allows me to pivot the table longer to get it to be tidy. So now I have a column index, name, and value. But I'd like to give it, I don't know, more informative name. So we'll do names 2 equals I'll I'll do call name and put that in quotes and values to equals Shannon. And so now we have index, call name, and Shannon. I would like to pull apart that call name column. So we'll do separate wider delim and we'll do calls call name delim equals the underscore and then we'll do names and we're going to do time treatment and replicate. And so now what you'll see is that we've got time treatment replicate and Shannon going to go ahead and put this on a separate line so it doesn't scroll off the side of the screen. And then let's go ahead and do a select. And I'm going to drop the index column. Okay. And so now we have time treatment replicate and Shannon. And we are good to go to go into making our plot. I'm going to go ahead and save this as D for data because I'm going to use that data frame to make the same slope plot by two different methods. Let's go ahead and take our D and we'll put that into ggplot. on the AES on the X axis we're going to put the treatment on the Y we're going to put Shannon and then I'm going to do color by time and let's stay there for a moment and we'll then do geome point and I've also got a gg save statement here that will save my version of the figure to the same size same aspect ratio as the original and so there we go it's not much to look at at this point but we're getting there let's go ahead and think about how we can dodge our points to have the before on the left and the after on the right. And so we could try that with geome point doing position equals position dodge. And we need to give it a width. So we'll do width equals 0.3. So it's a little bit hard to see in this case, but we got a little bit of a dodge. You can see over here clearly the red for after is to the left of the teal for the before. So that's the opposite order of what we really want. Let's go ahead for now and up this width to 0.5 so we can get a better sense of that dodging. That looks good. But again, I want the before to come before the after on the left, not the right. So, let's go ahead and fix that. And so, what we could do, and this is something I think I want to do in D, is to go ahead and modify the time column. So in here I'll do mutate time equals factor on time and we'll do levels equals and then we'll do before and after. And so now we can see that we have the before to the left and the after on the right already. I mean hopefully you can see where we're going here and that we are doing a much more direct comparison of the data, right? Like this is the control and you can see those right next to each other. there's really no difference. And that over here, like this antibiotics, there's a huge drop, right? And there's a pretty comparable drop for the antibiotics plus the ACR and a smaller drop for the ACR. Uh, interestingly, when they looked at the ACR, this red to this kind of pink, they gave a p value of 61. So, not a significant difference. So, we'll come back to that and do our statistical analysis to see if these changes are significant or not. But I think at least from this perspective, I'm wondering why this was not significant. That that really surprises me. So anyway, um we'll get there. So let's go ahead and remove that legend. Uh we might bring it back later, but for now, let's go ahead and hide it. We'll do false. And that gives us more space left to right. One concern that yes, we've dodged things, but there's eight points here, and those might be hard to see, right? So what we might like to do instead would be jitter dodge. So we'll do jitter dodge. And then here we don't need the width argument. And so now what we can see is that we've got jittering to the points. And and that looks pretty nice. One thing that um when I've got jittered points like this, I like to have kind of a black border so that I can see where the points are. And so maybe what we'll do instead of color will be fill. And then in gome point we'll do shape equals 21. My favorite shape. And we can see then that that gives us a black border and a colored fill. So what I would like to do next is to draw the line connecting the two clouds of points on the left and right for each of the treatment groups. To do that, what I would do would be like gome line, right? But if I do GM line, I get a unfortunate result where I'm basically connecting the points within the color. It's not what I want, right? I want it to go across the colors. And so, um, what we might think about would be like, uh, position position jitter dodge. And that also is weird, right? that's basically connecting all the points within the group. Um, and that's again not what we want. There's other things we might try with kind of defining the grouping of the data and things like that, but ultimately those aren't going to work. The first approach that I'm going to take to connecting the points within a treatment group is I'm going to basically do my own jittering and dodging. Okay. So to do that, I'm going to create a variable jitter. And let's say the jitter for now is 0.1. Our dodge, let's make that 0.3. What I'm going to do within D is I'm going to create a column that I'll call X. So really what jitter dodge is doing is it's adding a value plus or minus a consistent value for the two treatment groups, right? That is dodging. And then within each of the dodges, jitter dodge is then randomizing the position of the points within this pipeline. What I could do would be to mutate X and I will then take X and make that as numeric on treatment. We get a warning because I had forgotten that I haven't made treatment a factor yet. So let me go ahead and comment that line out. And this is good anyway because it would be helpful to get things in the right order on the x-axis. So we'll come back up here to where I've got this mutate statement where I defined time as a factor. And let's do treatment as a factor and we'll do treatment and we'll do levels. And now I want things in the order I want them or the order that they had them in the original perhaps. So, we'll do C TR RL AC R AB X AB X + ACR. And then I'm going to go ahead and put this levels on a separate line. And just to prove to ourselves that that worked, we now see that we've got our control going all the way across matching the ordering that they had in in their panel. Okay. Now I can come back to my pipeline and do D piped into the mutate X as numeric and we can then see we've got this X column right and so the control is one ACR is 2. If we did like last value pipe that to tail we'll see that we have X= 4 at the very end. Okay so we've got that X. What I want to do is to modify my X to dodge it and jitter it. So, I'm going to create another line in this mutate statement. Maybe I'll give myself a little bit of room here. X equals if else time equals equals before, then I'm going to do X minus my dodge. Otherwise, I'm going to do X plus my dodge. And we can then pipe that into our ggplot statement. And instead of mapping treatment to X, I'm now going to be mapping X to X. So I need to make sure I've got my jitter and my dodge loaded. And then I also want to take out this position statement. And let's remove it from here as well from the GM line. And so now what I see is that I've got my dodging perhaps a bit more of a dodging than I want. And I see that all of the before points are connected and all the after points are connected. Let's not worry about that just yet. So maybe because that's a little distracting, I'll go ahead and turn that off. And let's go ahead and reduce the dodge to 0.2. And that's that's a good place to start. Okay. So now we've got our points dodged. And now we want to add the noise. We want to add the jitter. So let's come in here and we'll do x equals. And then we're going to use runif. And so runif takes three arguments. the n that you want, the number of random numbers you want, and then the range. So if I do run 10, I get 10 numbers between 0 and 1. If I do run f10 -1 to 1, I get 10 numbers betweengative - 1 and 1. And if I do run f10 minus jitter to jitter, I'm going to get 10 numbers between my negative jitter and my positive jitter. And then I can add that to my x. And so what I'd like to do is to generate this vector of numbers again between negative jitter and jitter. And I'm tempted to do like one because I want to get one value at a time. But what that will do is that will turn x to basically be uh the same random number. And I think what I'd rather do is to use n that which will give me the number of rows in x. Not sure if this is going to work. So, let's try that out. And sure enough, we now have our jittered values, but I want to add this to X. So, now when we look at this, we then get our jittered values. And we can then bring that into the rest of our pipeline. And now we've got our jittered and dodged points, right? And so that looks pretty nice. I think maybe the dodging we could reduce a little bit to say like 0.15. And so that brings those a little bit closer. We we can fuss with things later as we change the sizes of things, but this is looking pretty good. The next thing we want to do is to add the line. So we'll again come back to GM line. We also have this plus sign commented out. So we'll run that again. And as we saw before, our grouping is by color. And so I want to change the grouping to be by the replicate and by the treatment. So then back up here within ggplot I can add group and I'll do paste treatment and replicate. Okay. And so this will create a dummy variable effectively telling geome line what points to connect. And there we go. We now have connected our points. Right? And so again we couldn't use position jitter dodge with geome line. we couldn't get the the points to connect, right? And here we've rolled our own jitter dodge effectively. Right? And so now we have those lines connecting the points. But uh we need to make this look a little bit nicer. Right? So first of all, I'm going to put the points on top of the lines. And so to do that, we can take go line and run that right up here. I'm also going to remove this position argument and get rid of this final plus sign. And so that then puts those on top. Let's go ahead and make our line a little bit thinner. We'll do line width equals 0.4. And so again, um, that might go a little bit thinner. Let's try 0.3. I think that looks pretty nice. In the process of making our jitter dodge function, um, we kind of screwed up our x-axis labels. So let's go ahead and fix that. To do that, we can come in here and we can do scale x continuous. And again, we have our breaks from one to four. And we're going to want labels. And I think what I could do would be like levels d sign treatment. And then that gets us those labels going across. So one thing I'm not a fan of is these abbreviations for the names. We can change that by changing the label of the treatment factor back up here when we defined D. Right? So back up here, I can then do labels and I can do control a carbos anti-biotics and then I can do antibiotics plus a carbos. And I already know that I'm going to probably want a line break here to put that over two lines. And so now we've got our spelled out names. Okay, now let's go about trying to improve the appearance of this. And the first thing I'll do is put this into theme classic. And that gets rid of the background and those grid lines. Let's go ahead and change our yaxis. I'll go ahead then and do a scale y continuous. And we'll do limits from zero. Let's take that up to say like 6.5. And I forgot a plus sign here. So now we have our limits from 0 to 6.5. I like the look of having the zero run straight into the xaxis. So to do that here in scale y continuous I can do expand equals expansion. Uh and so by default if I use expansion without any arguments it will turn off the expansion. And so there we see now our zero is right at the xaxis. Uh let's go ahead and shrink our font sizes. We can do theme access.ext equals element text. Let's do size equals 7. And then let's do axis.title equals element text size equals 7. And again, that shrinks that down. And then that actually makes this twoline label here fit within the screen. Let's go ahead and change our titles from our X and Y axis. I don't think I need a title on the X-axis because I think it's obvious what those are. So we'll do x equals null, y equals shannon index. Add that in. Let's go ahead and thin the axis line. It's pretty thick. So to do that, we'll do axis.line equals element line. And we'll do line width equals 0.2. And then axis.tix element line width equals 0.2. And then that of course snazzies that up a bit. All right. Now, let's think about that fill color on our points. Part of me is thinking, let's use arrows. I just made a video changing in ordination with paired points using arrows. But let's not use arrows in this case. Let's use an open circle for before and a closed circle for the after. We could easily do this with like white and black, but that's kind of boring. So, let's come back up here to our scales and I'll do scale fill manual. Get a plus sign in there. And then we'll do values before and let's make that white. And then after. And let's make that dodger blue. And there we go. We now have our before and after. Our white before, our blue after for these four different treatment groups. I think that looks pretty nice. Let's go ahead and bring that legend back in. And I think I turned that off up here with geome point. And so there again is my legend. Um I would prefer to have this probably in the lower left corner. So I also don't want that title. So let's come into labs and do fill equals null. And then within theme let's do legend position equals inside. And then legend position inside. And again, we're going to give it a two value vector for the X and Y position. Let's start with 0.2 and 0.2. And I think that's a great place. Um, but we want our text to be smaller and the spacing between our lines of that legend to be smaller as well. Let's go ahead and do legend.ext equals element text. And we'll do size equals 7. Everything else has been seven. So that's seven. Um, I think that works pretty well, but again, the spacing is pretty big. So, we'll do legend.key dos size. Let's do unit 8 pt. And so, that shrinks that down and makes that look pretty nice. I'm actually pretty happy with how that looks. U, maybe we should think about increasing the dodge between the treatment groups. So, back up here again, we had this dodge. Let's maybe take this to 0 2. And something else I should do is set seed because we're using this run if function to jitter our data. So I'm going to use my favorite uh seed, my birthday. And so yeah, I think that looks pretty good. So the final thing I want to do on this version of the plot is to add the p value. So you'll notice they have their p values up on top. And again, hopefully you can already see that mine is easier to interpret than theirs. Um I don't think there's really any argument there. I think it's obvious that by putting things next to each other, by connecting the dots, so to speak, of the same animal before and after, you can see the downward trajectory for these three groups, whereas the control uh is moving up and down, right? There's no consistent direction where there's a very consistent direction for these three other groups. So then let's add the p value. Now, in the original, what they did, I think, was to take the eight treatment groups as separate groups, and they ran it through a one-way ANOVA and then did pair-wise comparisons to see which comparisons were significantly different using a post hawk test. I'm not going to do that. What I'm going to do instead is a paired test. And I'm going to assume that these Shannon values are normally distributed. If they're not, we could use like a Will Coxin test. um if they are normally distributed we could use a t test regardless if we're doing willox or t and maybe we'll do both um we can do a paired test so let's go ahead and try that so I'm going to move all the way back up here so we have d so to do the paired analysis I'm going to need separate columns for the before and the after so let's go ahead and pivot wider and we'll do names from equals time values from equals Shannon and again now we can see that for control replicate one we have a before and an after mouse 2 before and after okay and now what I can do is I can nest the data so I'll do data equals everything but the treatment and again you can now see that we have a table with two columns one for the treatment the other for the data and I can then feed this into a mutate and create a column I'll call test and we'll use the map function to iterate over the data column and we'll do t.est test and then I'll dox dollar sign before comma x dollar sign after and so that x is the argument that data is representing and then what I can do is say paired equals true and this creates our column test uh but that is coming out as a list of h test objects and what I'd like to do then is pipe that into tidy and the tidy function comes to us from the broom package. So I'll do library broom. Get that loaded. And now if we come back to this, we now see that that changed from an h test object to a tibble that's one row and eight columns wide. I can get a look at that by doing unst on test. And then we see that we have our estimate, our statistic, and our p values. So the estimate is the change. And I think if I want it to be the negative, then we're going to want the after followed by the before, right? And so now we can see the amount of decrease from the before to the after for each of the treatment groups. And that's an average decrease. And again, that is a paired analysis. And we see these p values. So let's go ahead and clean this up a bit. So we'll do select treatment and p value gets us that I'd like to correct those p values for the multiple comparisons. So we'll go ahead and do a mutate on p value equals p.adjust adjust and I will then do we'll adjust the p value column and we'll do method equals BH for Benjamin Hutchburg and that gets us those p values which doesn't really change much in terms of what's significant or not. And what I notice is that except for the control they're all much less than 0.05. So now what I'd like to do is make a pretty version of the p value. So in here I'll do pretty p and let's do an if else and I'll say p value less than 0.001 then I'm going to return p less than 0.001 001 otherwise what we'll do is I'm going to say like p equals p value right um and I think what I'll do in here is the glue function and so let's do glue on that and I need to load library glue and again coming back down here to glue this p value then will need to be in curly braces And I think I'm missing a parenthesis here. Okay, so we run that. And so now we see our pretty P is this, which is not pretty. That's a long number. So let's go ahead and round this. So we'll do round that. And we'll do to three digits. And so now we see that's 779. And I think that looks pretty good. And so now what I'm going to do is I'm going to save this as P. Okay. Now what I can do is I can come back into my plot and I can do gome text. I'll say data equals p aes and so on the xaxis we're going to put the treatment right because our p looks like this. So we have treatment and then our y um I'm going to put at say 6.1. We'll see how that does. And then our label will be pretty p. And I'm sure there are things like color that I'm not using. So I'll say inherit aes equals false cuz I always seem to get I get r to bark at me when I don't do that. So it's still barking at me. And it's saying discrete values are supplied to a continuous scale. Yes. Yes. Yes. So, back up here where I had treatment, I need to say asnumeric on that treatment. And so, there we go. There's our p values. They're much too large. Let's go ahead and shrink that size down a bit. And so, I'll do that by doing size equals, let's say, 7 and size.unit equals pt to get to be a sevenpoint font. We now have those p values. Maybe we want to move them up a little bit. And so I put it at 6.1 I believe. Let me make it 6.3. And there we go. Okay. So again, there's on the left, mine on the right. Which is easier to interpret? Also, which gives the results that are more powerful? The one on the right because we used a paired t test. Now I could try it again, but with a will coxin test. And let's see what that does. So again, um, I could take this line. I'm going to comment it out for now. And I'll do tilda willox test. And it's going to be, I think, the same as everything else that we've got in here. Right now, when I look at this and I do P, I get these pretty p values are all 0.01. Right? And so we basically get the same result in terms of significance. And so if you're comfortable assuming that your data are normally distributed, I would use the paired t test. And if you're not, then you'd use the willox test. In this case, the result is the same, right? We're going to get small p values for the a carbos, the antibiotics, the antibiotics plus the a carbos. This was method one. I am going to rename this and I'll call this manual because I did this manually. I made my own jitter dodge. So now I want to try this by a different approach and instead of manual I'll go ahead and call this facet because one way to think about this would be as four separate facets. And this way then I wouldn't have to worry so much about the jitter dodge. I could jitter and that actually might work with the line. Right? And so now let's try it using facets again. We have D. So we'll pipe D into ggplot AES. On the X axis we'll put the time. On the Y we'll put the Shannon. The fill we'll make the time also. And that's good. And then we'll go ahead and do gome point. And I'm going to go ahead and facet wrap by the treatment. Right? So each treatment is its own facet. And then I've got this saved. So, we've got our four facets. Again, we want them on one row. So, let's go ahead and here and we'll do n row equals 1. And that gets those right next to each other. I'm going to go ahead and turn off the legend as we did before. So, I'll do show.leend equals false. And also in here, I want to do shape equals 21. And so, there we go. We have our four treatment groups which we can kind of see those labels up here in those strips. We also have our before and after on the Xaxis. What we've got the dodge. Now we want to add the jitter and we want to add the lines, right? And so maybe instead of geome point, we could do geome jitter. And so then that gets us a jitter to our data, right? And then perhaps what we could do would be geome line. We could then do position equals position jitter. Add that in. And so now what we see, of course, is that we have kind of the same effect that we saw earlier when we tried to draw the line. And that we're basically connecting all of the dots, except they don't connect to the dots we had because we have a different seed for our jittering. So that's something we'll have to come back to. But we want those lines to go across like we had up above. So to do that, we're going to need to add a group argument. And so we saw this before with the previous version, instead of pasting two things together here, I should be able to do replicate. And so we're going to group by replicate to draw lines between the two replicates. And so there we go. We now have our lines, but as I mentioned, they don't really connect to the points because we've got a different jitter for the line as we have for the points, right? This line here should be on that teal point. So to deal with that, we can use the seed argument within position jitter. And I'll give it again my favorite seed 197620. Um to set the seed for gome jitter, I need to also set the position position jitter within geome jitter. Geome jitter is the same as geome point except the position is position jitter instead of position identity. So this now should get us to have our lines connecting our points. So I'm a little surprised that that didn't solve the problem. Um and so I wonder if geome line here should actually be g path. And there we go. So I'm not entirely clear why that makes a difference. The difference between geome path and gline is that geome line will sort the data frame by the column getting mapped to the x aesthetic before plotting it whereas geome path leaves the data as it is. And so maybe there's just something weird happening so to speak under the hood um between geome path and geome line when you are using position jitter. Regardless this works our points line up with the lines and now we are ready to make this look better. So, as we did before, let's go ahead and put geome path before gome jitter. And so, now our lines fall behind the points. So, the next thing that we're going to want to do is we're going to want to get rid of these xaxis labels. And we want these strip titles to actually be the x-axis text. So, to do that, let's go ahead and modify our x-axis so that we only have the single tick like we have here, right? And so we can do that with scale x continuous and I'll do breaks equals 1.5 and I'll do labels equals nothing a quote right and so this is going to complain because I'm giving it a numeric value when our x is a factor. And so here what we'll want to do for x is as we did before as dotn numeric on time. And let's go ahead and put this over a line. And so now what we see is we've got our tick mark and no label there. And we've got this title. So let's go ahead and clean up our labels real quick. So we'll do labs x equals null y equals shannon index. And while I'm at it, I'll also do fill equals null. Okay. And so now we've got our ticks, but we want these strips to be down here. So to do that, then up in facet wrap, we'll do strip.position equals bottom. And so that then puts our strips at the bottom, but it's between the tick mark and the plot. And so to get that on the outside, we'll come in and I'll go ahead and do theme classic to get the solid axes and a white background. And then we'll also do theme strip.placement equals outside. And so now we can see that our strip is on the outside of the tick. But uh we still have a space here for basically that empty string for our axis text. So we can go ahead and do axis.ext.x equals element blank. That brings that in closer. We can also now modify our strip. So we'll do strip.background equals element blank. That gets rid of the border. Um, and we still have quite a bit of space there, though. So what we also could do would be strip.ext equals element text margin equals margin. And that brings that up rather nicely. All of the axis text up in the this version was size seven, as was the title. So, let's go ahead and make those all seven as well. And we'll want to do the same thing in strip text. Again, this is not axis text or an axis title. Uh, it's a strip, right? So, we'll come in and do axis.ext.yals element text size= 7. And then we'll also do axis.title equals element text size= 7. We don't have a title on the bottom. So, we don't need to say x ory. We can just say access title. Now, my antibiotic plus a carbos is getting clipped a little bit on the sides. Not going to worry about that just yet because ultimately we're going to be drawing these together. So, before we get there, let's go ahead and clean up our yaxis. You'll recall that we had some styling up here that maybe we should just go ahead and borrow. And I'll grab these lines that go from axis line ticks and the legend and copy that. And we'll paste that in here. And let's see if we did any damage. So that thins up our lines. And good. Now let's go ahead and worry about our yaxis, which again from the previous we had these scales. So we had scale Y continuous and scale fill manual. I'll go ahead and grab all of that and bring that down because that's that's not new. Um, so paste that in. Cool. It's coming together. It's starting to look a lot like what we had previously again with our yaxis scale. Let's thin our line. And so I think before we had line width of.3. So let's do that here in scale in geome path. We'll do line width.3. That thins that up. And now what I want to do is again we have these four facets. Let's pull them together. And so we could come in here and we can do panel.spacing.x. We'll do unit zero pt. And so now we can see we have a solid x-axis. And no one would be the wiser that we actually have four different facets here except we are getting a little bit of clipping and that is because we don't have enough space on the edges of our plots. So let's go ahead and in our scale x continuous let me move this labs up out of the way. In here, I'll do expand equals expansion. And let's do add equals 0.5. I don't really know what it should be. So, we'll start there and adjust. I think we got it. I think that is pretty much the same thing. Um I I guessed at 0.5 and and that got us pretty close. There's no clipping on these titles. The points are pulled in. The only thing left to do is go ahead and bring in those p values, which you'll recall we had a geome text call in here. And I will copy that and bring it down here. Maybe put that after my geome jitter. Clean this up. Run it. Ah, so close. So close. And I think the problem is that the P is centered at one rather than 1.5. So we need to adjust. You can't always copy and paste your way to success. So X here will make uh 1.5. And voila, we got it. So the final thing we need to do is bring in that legend. Again, I did show legend equals false down here for geome jitter. Get this out of the way. And there we go. And like I said, I think that is like bangon identical except for like the difference of the random seed. Maybe the the dodge could be a little bit larger in our faceted version. Or I guess that would be effectively the jitter could be less. So let's try that. So the jitter and geome jitter. Let's go ahead and bring this down. And we'll then do width equals 0.2. I think that looks like a pretty good jitter. We need to connect the lines by doing a width equals 0.2 for the geome path. So we'll do width equals 0.2 for that as well. Okay, I'm happy with that. I think this looks pretty pretty similar. So again, there's two approaches that I took here to making the same exact plot. The first, which I would be hardressed to tell you which was which without looking at the titles. The first which was over here, I manually did my own jittering and dodging of the points. Okay? And that way I could connect the points with a line with the ends of the lines being dodged and jittered. I'm not able to jitter and dodge the ends of the lines with these multiple treatment groups. And so again, I had to create my own xaxis coordinate value by taking the numeric value of the factor, adding a dodging factor, and then adding a random value to jitter the x position. And so that's what we get here. This one actually is the faceted version. And instead of dodging the points, I effectively put each treatment group in its own facet. And then I fudged the X-axis. And actually, you can tell because these strip titles are horizontally justified. And if I wanted to deal with that, I could come back up here to strip text and I could do VJ just equals 1. And there you go. It's now vertically justified. But again, I treated each treatment group as its own facet. And then I didn't have to do jitter dodge and I could jitter the ends of the lines. And that way then I didn't have to basically roll my own jittering and dodging. So I think both of these approaches that I took have their challenges to them and I wouldn't say one is necessarily easier than the other. I think the faceting is perhaps a little bit easier because you don't have to really think about like how do I dodge, how do I jitter, how do I use run if and all that stuff, right? If you're in a situation where you want to facet on other parameters, then you don't want to burn your facets this way. And so that that then means that you'd probably have to roll your own like I did up here. I mean, I'm pointing to things that look the same, I know, but um it's a matter of whether you're going to be faceting on other things if you want to perhaps take the facet approach versus manual approach. I don't know which I prefer. I think they're both pretty good. Um and I'm really happy with how they turned out. Most important, however, I think is the difference to the original. And I really do feel like my version is much superior. it's much easier to make the comparisons between the pre and post treatment samples. There's an additional set of questions that the authors did not ask and that I'm not following up on which is is the change significantly different between the four different groups right so or between these three groups right so the a carbos the antibiotics the antibiotics plus a carbos they all had a significant change in diversity because of the treatment is the level of change different right and and so kind of eyeballing these I don't know that the antibiotics and the antibiotics plus a carbos that that change was significantly different between those two groups. Yes, I think it was different than a carbos alone. But antibiotics plus or minus a carbos, is there a difference? I don't think so. Of course, you could run that statistical test. That would require a repeated measures analysis of variance design that models that paired analysis. That's beyond what I want to get into today. It's beyond what the authors were interested in describing at least in their text. But that's certainly something that you could do. Again, the beauty of R is that there isn't just one way to do things, but there are multiple ways to get to the same exact path. Um, and so, thank you for indulging me in this video. All right. Well, thanks for watching. Please tell your friends what we are doing and I will see you next time for another episode of Code