
R Markdown Advanced Tips to Become a Better Data Scientist & RStudio Connect | With Tom Mock
R Markdown is an incredible tool for being a more effective data scientist. It lets you share insights in ways that delight end users. In this presentation, Tom Mock will teach you some advanced tips that will let you get the most out of R Markdown. Additionally, RStudio Connect will be highlighted, specifically how it works wonderfully with tools like R Markdown. Please provide feedback: https://docs.google.com/forms/d/e/1FAIpQLSdOwz3yJluPR2fEqE0hBt92NtKZzzNACR8KJhHUt9rhFj3HqA/viewform?usp=sf_link More resources if you're interested: https://docs.google.com/document/d/1VKGs1G9GcQcv4pCYFbK68_LDh72ODiZsIxXLN0z-zD4/edit 04:15 Literate Programming 09:00 - Rstudio Visual Editor Demo 15:44 - R and python in same document via {reticulate} 18:10 - Q&A: Options for collaborative editing (version control, shared drive etc.) 19:30 - Q&A: Multi-pane support in Rstudio 20:46 Data Product (reports, presentations, dashboards, websites etc.) 24:15 - Distill article 26:27 - Xaringan presentation (add three dashes --- for new slide) 28:58 - Flexdashboard (with shiny) 30:30 - Crosstalk (talk between different html widgets instead of {shiny} server) 35:03 - Q&A: Jobs panel -- parallelise render jobs in background 36:50 - Q&A: various data product packages, formats 39:35 Control Document (modularise data science tasks, control code flow) 39:58 - Knit with Parameters (YAML params: option) 41:20 - Reference named chunks from .R files (knitr::read_chunk()) 43:00 - Child Documents (reuse content, conditional inclusion, {blastula} email) 47:07 Templating (don't repeat yourself) 47:38 - rmarkdown::render() with params, looping through different param combinations 49:30 - Loop templates within a single document 50:40 - 04-templating/ live code demo 54:37 - {whisker} vs {glue} -- {{logic-less}} vs {logic templating} 55:30 - {whisker} for generating markdown files that you can continue editing 57:49 RMarkdown + Rstudio Connect 1:00:41 Follow-up Reading and resources 1:04:49 Q&A - {shiny} apps, {webshot2} for screenshots of html, reading in multiple .R files, best practice for producing MSoffice files, {blastula}
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
Hey, everybody. Welcome to the RStudio live stream. We're going to be covering a few different things today. Namely, we're going to be going over a lot of R Markdown here from my home here in Texas. So really excited to be here with everybody today. I'm going to get some questions in the chat. We'll do a little bit of live coding. I've got a slide deck. I hope you're going to learn something with me today. And we're going to have fun doing this as an experiment. This is one of my first times live streaming and first time here on YouTube live. I've done a little bit on Twitch. So excited to kind of learn along with all of y'all as we go through this experiment. Let me know if you have any questions and we'll try to answer some of them in the chat. And at the very end, we'll also upload the video to YouTube. One of my colleagues is going to be answering questions in the chat as well and sharing some links as long as we go.
So let's get kicked off. I'm going to start sharing my screen and we'll go from there. Let's do this one. All right. So the first part we're going to go through, I'm going to have a slide deck. You can find the slide deck if you want to along with all the corresponding materials at bit.ly slash rmdmarvel. I love this kind of Captain Marvel movies. They're kind of built the idea around some of that. There's just some little images and kind of playing around with that idea. So the concept for today is we're going to go going higher, further, faster with Marvelous R Markdown. R Markdown is amazing. It's one of my favorite R packages, one of my favorite data products, one of my favorite things for just doing things in R and other programming languages.
I'll also be working inside RStudio primarily. So you might see me log into RStudio here. I want to be very clear that everything I'm showing today up until the very, very end of the presentation can be done in R Studio Desktop or RStudio Server or RStudio Workbench. So there's really not anything here that's proprietary per se. The vast majority of this is open source R Markdown, which is amazing. You can be very productive in your school, in your enterprise, as your hobby without really having to go and buy anything. You do want to go a bit further with RStudio Connect. I'll talk about that at the very end, but that's a small component of today's presentation.
R Markdown as a taxonomy
The way I like to think about R Markdown is that it's a lot more than just, you know, literate programming, although that's a huge component. R Markdown as a taxonomy can do many different things. It can be an environment where you're writing code, and writing text, and creating graphics, and creating statistical models, or data science, or machine learning. But it can also just be an end result as a data product. You can create something like this slide deck I'm presenting, which was made with R Markdown. You can use it as a control document to kind of control your code flow, and how you organize your projects, and bring different snippets of code together. And lastly, you can also use it for templating. So basically, leveling up your skills, and taking one thing and turning it into 100. Or taking one example, and adjusting it, and recreating it without having to rewrite all the code.
So we'll be going into all four of those different taxonomies today.
Literate programming
The first one, and I think the obviously one of the core workflows that you're going to do in R Markdown, is literate programming. The goal here is that you're going to capture your code, text, or comments, and your output in a single document. So you have essentially like this reproducible workflow of capturing your code, along with the output, along with any kind of comments about what the code is doing, or the outputs that you're seeing, all together. So you can share one document, or one report with someone if you wanted to do that. But you can also reproduce it, because you have the source code.
The idea of literate programming has been around for a long time. Donald Knuth has this nice quote about literate programming as a programming paradigm. And the explanation of it is that it's logic in a natural language, such as English, interspersed with snippets of macros and traditional source code, from which the compilable source code can be generated. Now when we think about source code in R, we have code chunks. So you have these little portions here, where you might recognize some of these, your favorite ggplot, some dplyr to filter a data set. But then with R Markdown, you can also intersperse actual text, you know, write about it, just as you would in a word processor. But now you get the benefit of doing code and text together.
The other component I just want to bring up here is that there is the YAML header, which allows you to define certain metadata. So up here at the top, you can say, I want my output to be an HTML document. So this will, when it's rendered, when you finish it and you click render, it will actually create an HTML object that you can open up in a web browser. And you can switch this out to do Schrodingen or any other type of things or presentation like I'm doing today.
Now going a step further beyond just that plain text, visual R Markdown was introduced in RStudio 1.4. So this has been around for six or seven months, but there's still lots of people who may not have heard about it. So I wanted to cover it today. You can essentially think of this as not only do you have the ability to look at the source code and the raw Markdown, you can also view it in a way where it shows you the actual rendered outputs. So when you create a table, it shows you a table. When you include a graphic, it shows you the graphic. You don't just have to believe that, okay, this code should bring in this image. It will actually do that live inside RStudio.
In addition to that, it can do things with LaTeX or with real-time spell checking or all the different source code that you still want to be using. And you get a nice header up here that allows you to add things like bold, italics, cross-throughs, bullet points, tables, all those things with insertion. But it still allows you to do that with code and actually adds the code into it. I'll be walking through this in a second here live.
And then the last part is that R Markdown and literate programming is not just for R. You can do things like include Python via reticulate. You can use SQL inside code chunks to actually write raw SQL code. You can include CSS or JavaScript for some of your front-end development work. And you can include other things for bash, RCPP, SAM, and a lot of other different languages. So altogether, Knitter provides kind of interfaces to 52 possible languages. So you can do a lot in R Markdown, even though a lot of what I'll be showing today will be focused on R.
Live demo: visual editor and literate programming
So with that, let's hop over into RStudio. I'm working inside the RStudio team evaluation. Again, this is not necessary. It's just a reproducible environment I can use. So I'm actually logged into an RStudio Workbench session. This might look a bit different initially from what you're used to in using RStudio on, say, your desktop, but the workflows are essentially identical.
The first one I'm going to use is this visual RMD file. So this file will look pretty similar to any R Markdown document you've seen before. There's a YAML header, there's some code chunks, there's a bunch of text, there's a table here, there's some images, all sorts of things going on. If I want to switch over into visual editor mode, I can click on the visual editor button right here. So this button will switch me to the visual Markdown editor. Once I click that, it'll reload the screen and will then convert what I'm seeing on the page into the actual represented output. So now rather than, you know, three pound signs and intro, it actually creates a level three header. All of my links get turned into hyperlinks. My code chunks get a gray background.
What might be more useful is like jumping into an actual code example as opposed to kind of a demo of what visual Markdown does. So if we go to the Penguins folder, we've got a couple different documents in here. I'm going to start with the Penguin report detail.
We're going to use a couple libraries. So I'm going to load Tidyverse, Polymer Penguins, Broom, Skimmer, and the Bootstrap lib package. I've got a couple different documents here talking about what literate programming is, some initial exploration that we've used for how to use Skimmer, some examples of inline code chunks. And what we're going to do is do a quick skim of these data. So if you're not familiar with the Polymer Penguins data set, it's basically a relatively small data set, about 344 rows. And it includes three different species of penguins for both male and female. This is a nice alternative to say the iris data set.
And Skimmer is just showing us what are the different variables in this. So there's a lot of information about the bill length, basically how long their beak is, as well as the bill depth, how broad it is. And then their flipper length, or how long their arms are, their body weight, their body mass, and the year that this was observed.
Really, what we've done here for a few minutes is just walk through a live coding example. And it's really just me running code. But you can see that if I gave this to a colleague where I was looking at this, this is nice to read through. This reads almost like a report already, even though I'm able to edit it and kind of change things as I go. So, you get this experience of kind of a word editor or a word processor with the ability to run that code. And that's really what the beauty of literate programming is, is mixing in the comments or the things you're writing along with the code you're writing.
And that's really what the beauty of literate programming is, is mixing in the comments or the things you're writing along with the code you're writing.
The other part I want to show, if we go back to the visual editor, is we can also do this same workflow with reticulate. And I can actually use some Python. So, we'll load these libraries. I've loaded reticulate to allow me to use Python on the back end. And then I can import pandas and get the penguins data set into the pandas object now. If I look at the environment, I have the ability to switch between R and Python and see those different objects.
And we can show the final output here in the browser. So, this is very important penguin analysis that we're doing here. So, again, we're pulling in pandas. Instead of skimr, we're using the describe function from pandas and we're looking at a few different things by the species. This is done in Python. And then we'll do some group by summaries with pandas again. We can then take that Python object and pipe it back into ggplot. I'm much more comfortable in ggplot than I am in matplotlib or other libraries in Python. So, I just moved it back in. But really just the idea of, like, if you know a little bit of R and know a little bit of Python, you can work with them in the same document and kind of use that for learning or use it for some of the reporting or other kind of scientific computing that you're doing.
Q&A: collaboration, multi-pane editing
Question number one was, has anyone found a good method of real-time collaboration on R Markdown in a similar way as Google Docs? That's a great question. Obviously, you could do something that's more asynchronous by checking into something like version control. An alternative would be that RStudio Workbench actually allows you to do live editing of the same document with project sharing. So, that is a professional product that we offer. But that is an option if you're worried about, like, collaborating at work and needing to work remotely, but still share documents.
One other thing, how do you have that many panes? Let's talk about, go back into this for a second. So, RStudio 1.4 introduced not only the visual editor, which, again, is this button that allows you to show the kind of rendered output, it also added support for the multi-panes. So, if I go to tools and go to global options, pane layout, I can add new source columns. So, you can see I have my four typical panes, but then I have an additional source column. I use this quite a bit for doing things like Shiny, where you might be writing essentially, like, the front-end portion, the user interface, and the back-end server component in separate files and bringing them both in together.
Data products
So, we talked about literate programming for a while. The next kind of taxonomy of using R Markdown is the idea of a data product. And here we're using R Markdown to, and using R to generate a final output for consumption. So, yes, you know, you want to be reproducible. Yes, you want to include code. But here, you're mostly concerned with I want to create something that I'm going to give to someone to help them make a decision, convince them, or just report on something.
There's a ton of different data products you can create with R Markdown. You can create reports. So, static HTML reports, like I was just showing when we rendered that document. PDFs, you can save out so they could, you know, share them via email or just have something you can have offline. Rich text formats, GitHub documents, or even Word documents. Presentations, just like this one is. This one was created in Schrodingen. So, that is a R Markdown package using reveal.js, or remark.js, I'm sorry. You can create PowerPoint presentations. You can create other, kind of, more native reveal.js presentations, Beamer for LaTeX. You can create full-blown dashboards with flexdashboard that can be either static or you can integrate Shiny and make them interactive. Entire websites. So, some of y'all may actually have R Markdown blogs. I personally use DeCille for my personal blog, and BlogDown is a great option for a lot of power and uses Hugo on the back end to convert Markdown and R Markdown into complex, sophisticated websites.
You can write books, beautiful books that, you know, people have literally published. You think of, like, R for Data Science, a book by Hadley Wickham and Garrett Grohlman. That was written with BookDown. You can actually look at it online in the BookDown format. And lastly, one of the things I'm really excited about for R Markdown and data products are HTML widgets. You may have been exposed to DT, or the JavaScript Data Table Library, or Reactable, which is similar, and creates interactive tables in R that use JavaScript on the back end. So, without even having to use Shiny or a server, you can have the ability to sort, rearrange, or change the data you're seeing on the screen all at once. And there's Plotly for graphics, crosstalk for interaction.
Live demo: Distill, Schrodingen, flexdashboard, and crosstalk
So, the first one we're going to be looking at is, I was talking about different output formats. So, Distill being the ability to create a web page in R.
So, here's Penguin's Distill. This looks quite a bit different. I love that it has this floating table of contents, that it has some information about when it was published, who the author is. It's more of like scientific writing native to web. So, this is an HTML document, but it is really like how to do scientific writing. And again, you still get all the niceties and kind of the core R Markdown work. So, this is still the same code I was using, but I was able to generate a different output simply by changing the R Markdown YAML.
And the next one we're going to do is a Schrodingen presentation. So, again, the data product here is more of a presentation. So, just like the presentation I'm showing you, this one was created with R Markdown. I literally wrote a bunch of R Markdown code to generate the presentation that we're going through. The specialness here is that instead to kind of tell this presentation format, this is a new slide, I use three dashes to say go to the next slide.
Yeah. There's one more example I'm going to go through about data products, and then we're going to talk a little bit more in the presentation. So, number one, a flexdashboard is a way to create dashboards in R. What I can do is actually run this document. I'm running the document because it has a Shiny runtime. Shiny is not required for flexdashboard, but does give it a lot of extra power in terms of now you can have a server component on the back end and execute something.
So, there was a question in the chat, does knit mean render or essentially an enter based function? What knit for render means is take the document, run it from the top to the bottom in a linear fashion, and create the output format. There's all sorts of side effects that are good in terms of you could write out different files. The idea is render is like run the entire document and render the output, or knit the document and render the output. Those are interchangeable. You can use the RStudio knit button, or if you're doing it from the R console, you could do R Markdown render, and just pass the file name to it.
But the beauty here is that with crosstalk, I have an interactive graphic in terms of this here, all these little points I'm hovering over, the hover text comes in for free. You get the hover text in all these different documents. With a table, you have the ability to go paginated or sort by species, sort by sex, sort by any column. So, you have interactive components, interactive graphics, interactive tables, all of this available for free and all this able to be used within your enterprise, within your hobby, within your workspace.
What crosstalk is doing is giving you some of these filters. So, this may look exactly like Shiny, but there is no Shiny server on the back end. This is all done in the browser on your local machine.
What crosstalk is doing is giving you some of these filters. So, this may look exactly like Shiny, but there is no Shiny server on the back end. This is all done in the browser on your local machine.
And again, the beauty of R Markdown and the beauty of crosstalk in this JavaScript library is you don't have to manage a server. You could literally publish this to GitHub or Netlify or RStudio Connect or just take the file and literally like deliver it to someone else by email if you wanted to or by shared drive. They can open it and get this interactivity that you're expecting.
You can still leverage Shiny on top of that if you wanted to to get even more power or to actually execute new R code. You are limited to what these libraries can do in JavaScript, but if you add Shiny, then anything you can do in R can be added into the object as well.
The jobs panel might be new to a lot of folks. This is, again, available in the RStudio desktop, the local IDE. It's a free thing. It's just available. You could render anything R Markdown if you wanted to as a background job. You would just have an R script that literally contained R Markdown render and then whatever the R Markdown document you wanted to do. So, you could parallelize some work if you wanted to, like, you know, render this one. I know it's going to take a while. Also, render this one, and then that leaves you free to continue using the R console to do other things.
Control documents
The next kind of taxonomy I'd like to cover is the idea of a control document. So, this is kind of a step beyond the classical ones. The first two people have probably done a lot of that. Control documents are some that I had not done as much of before I'd done some research. So, the goal here is to modularize your data science tasks and use R Markdown to control your code flow.
Parameters in R Markdown can be added to the YAML header with the params, colon, and then whatever you want the object to be named. So, in this case, like, species equal to Adelaide. When I render this document, it will run the code in here, but then it will pull in whatever the parameter is. So, without changing the body code, I can change what the actual report does. So, I can say, for the Adelaide penguins, generate this, you know, these different filters and this different graphic. And I can just change this one line of code in terms of this parameter, and it will generate an entirely new report or entirely new document that is specific to that.
You can also reference .R files. So, for a lot of folks, you're like, eh, you know, like, R Markdown, it feels like a lot of, you know, there's a lot of different power there, but, you know, I have to write all these different things. I'm just going to start in a .R file. You can use and reference external .R files a couple of different ways. So, you could always just source an internal R file and just read in things from an external file, but the NIDR read chunk option kind of gives you the best of both worlds.
The other idea is child documents. So, I could have a core kind of parent document here that is just an HTML document. It's got a couple library calls in terms of loading Tidyverse and Polymer Penguins. And then just like before with the read chunk, I have a blank chunk here. There's no code in it, but it's saying for this chunk, read in the child report, Adelaide report, .R Markdown. And that will take everything in this. So, the smaller, this code chunk, this text, this code chunk, and embed it into this portion. So, essentially you wrote all this and put it into the parent document.
Another idea of like parent and child documents is blastula. Blastula can be used with things like Gmail or you can use it with RStudio Connect to send emails. The core idea, and there's a bit more code here, we're loading some libraries, we're creating some graphics, and then we have this render email portion. It will basically take a blastula written email. So, you can see that this Penguin email, the output is blastula, blastula email, and render that as an HTML email and then send it. The example I'm using here is rendering it and sending it via RStudio Connect. You can also render it via SMTP, which is a protocol that like Gmail uses. So, again, Connect is not required to do this. It's a nice integration, but you can do this for free with your SMTP style servers.
Templating
The next taxonomy I'd like to cover is the idea of templating. I really love the idea of templating as well. So, for templating, a lot of people think of like taking one thing and making it other things or taking one thing and changing something about it to make it different. The idea is don't repeat yourself, generate input templates or output documents from code.
So, if you think about parameters, that's something we used before was, you know, defining a parameter, setting it as a species equal to Adelaide, and then we generate this report. Obviously, you could go into the R Markdown, delete this, type out, you know, chinstrap or Gentoo or one of the other species and click render, or you could do it from the command line or the R console. So, with R Markdown render, you can take this report, so the penguin.rmarkdown, and define the parameter as something else. So, here, a list of species equals to Gentoo instead of Adelaide, and now this will generate that report with code with that new parameter.
A more interesting example in my mind is multi-render, where you actually take all the different possibilities of the parameter and generate all of them. So, here, I'm wrapping R Markdown render into my own render function so that I pass in penguin to my render function. It takes the same report. It replaces the species with whatever the penguin I put in, and then it creates an output file with the name of that penguin-report-html. So, now I can find all the distinct penguin species. I can pull that column out, and then I can render that with per walk. So, basically, it goes through each of the different possibilities and generates a new report for all of those. So, now I have an Adelaide report, a chinstrap, and a Gentoo report all from one set of starting code.
The last idea I'll talk about is whisker versus glue. So, the way I like to think about this is one versus two, if you're thinking about these parameters on the outside of these brackets. Glue is logic templating in terms of you can take a string, put anything you want with valid R code inside these brackets, and it will interpret that and execute it inside that context. So, very, very cool, very strong package. Whisker is logic list templating, meaning you have to define the object at a time and then pull it in. It also uses two brackets instead of one.
The reason why it's logic list is that it's really thinking of it just as text as opposed to code up here. Where whisker is very powerful is the idea of generating actual dot RMD or dot MD files, like basically generating new input files or text files from an input file. That kind of blew my mind the first time I thought about it.
RStudio Connect
The last component here, and we've only got a couple of minutes, I think that was part of the intention, is that all the things I've showed up to this point have literally been all the amazing things you can do with R Markdown for free and within your own kind of choices. This last component is a bit about R Markdown within RStudio Connect. So, RStudio Connect is a professional product from RStudio. It's a hosting and execution platform for Shiny, R Markdown, Plumber, as well as things like Jupyter, Flask, Dash, and Streamlit for our Python folks.
You can use it to execute or schedule R Markdown for basically anything. So, not only can you host things there, but you can actually have Connect re-render or re-execute this code in the future. So, you could provide parameterized R Markdown where someone can actually go through, change parameters, and re-render it without having to know anything about R. You could schedule ETL jobs and pull from SQL with dbplyr, APIs with Hater, or Spark with Sparkly R, and then bring those into R and do other things with them. Connect provides reports that actually have logging and history, so you can have multiple versions of the same report over time. You can schedule some of your long-running training steps that take three hours and have them run at three in the morning, so that when you come in in the morning at eight, or when you log in your computer, all that's been done overnight and you've got your batch scoring done and ready for you in the morning. And then with blastula that we mentioned earlier, you can actually create and send emails conditionally or on a schedule.
I actually scheduled this report to run every hour for the past few hours. So, you can see I've got a couple emails here it's been sending me. So, we've got an actual blastula email that has an attachment of a PDF, a CSV file, and a PowerPoint file. All this was generated with R Markdown. It gave me an embedded ggplot, an embedded ggplot, and an embedded table. And this was run with RStudio Connect over and over and over with different data and sending me these different parameters. So, this is the power of, like, all these things you learn are amazingly powerful in your local machine. If you want to go a step further and have, like, authentication for these documents you're sharing with an enterprise, or scheduling, or some of these other things that are worth paying for, then you can look in RStudio Connect and do some of these amazing things.
So, that was a whirlwind tour. We got it done in exactly 60 minutes in this fun experiment we did together. So, thank you for tagging along with me, listening to me talk in my 200 words per minute voice. Thank you to Allison Hill for defining that. A bunch of different follow-up links. There's some articles that people in the community have written about how to use R Markdown to be very powerful in your enterprise. So, Emily Ritterer, Charlotte Gelfand have really great articles on this. I have one covering this same idea of, like, taxonomy of R Markdown. There's two entire textbooks about R Markdown. The cookbook for different examples that may answer some of the questions that folks had in the chat that I didn't get to. And then definitive guidebook, which shows all the possibilities of what you can do with R Markdown.
Extended Q&A
Is there a good way to output a specified set of dashboard views to a PDF? So, you can use the webshot2 package. I didn't have enough time to talk about that today, but the webshot2 package allows you to take screenshots of HTML and then embed them somewhere else. So, you can imagine that HTML is amazing. HTML is what I think you should be creating, because you can do so many different things with it and make it interactive. But sometimes people are like, I need a PDF, or I don't have internet access. I need to have this, or I want to print it out. A couple different use cases. With a PDF, you could actually do webshot2 and print different HTML views, like a flexdashboard, to a PDF.
Can you ask Knitter to read several .R files? Absolutely. So, you could either source or Knitter read chunk from multiple times. So, you can imagine I have 10 different .R files. You could read all those into a parent R Markdown document and execute the code there.
What are the best practices to produce Word documents from R Markdown? So, for Word documents from R Markdown, there's kind of two ways of doing it. You can do it with R Markdown proper, and there's also what's called the Office First, that is a really powerful environment for just working with Office things. You can imagine PowerPoint, Excel, and Word, like the kind of Microsoft Office stack. You can do a lot of those different things with R and with R Markdown.
When do you think someone should use R scripts over R Markdown files? I try and almost always use R Markdown files if I'm doing anything that is useful for that. So, anything where I'm creating an output or I'm trying to capture my train of thought. I know there are times where folks are like, well, I have to send a .R file out to a high performance computing cluster. That's fine. You can use a .R file, and you can still do useful workflows.
That being said, I find that working R Markdown, especially with the visual editor, so the ability to not only just see the raw plain text or work with the plain text, but also have the rendered output and the ability to interject all sorts of different things that can insert a level one heading. The amazing things you can do with R Studio and R Markdown are worth it, although .R files can do the exact same with R functions.
So, we've got an actual blastula email that has an attachment of a PDF, a CSV file, and a PowerPoint file. All this was generated with R Markdown. It gave me an embedded ggplot, an embedded ggplot, and an embedded table. Things that are in line in blastula, I can show this. Let's look at a blastula email. So when I actually render the email, this is a preview that you can run with the package. This has not been sent, but it shows you what the email would look like as a preview. So this is an embedded ggplot, it's literally inline, so in your actual email that you send to someone, it'll have this text and it will have this image. However, some clients are very aggressive with stripping HTML.
All right, I think that's actually all of it. We still have around 400 people here, so thank you for spending some time with me and going a bit over. Have a wonderful weekend, be safe, you know, enjoy R Markdown, have a good time, and we will see you next time.


