Resources

Beyond Static Reports With R Markdown | RStudio Webinar - 2017

This is a recording of an RStudio webinar. You can subscribe to receive invitations to future webinars at https://www.rstudio.com/resources/webinars/ . We try to host a couple each month with the goal of furthering the R community's understanding of R and RStudio's capabilities. We are always interested in receiving feedback, so please don't hesitate to comment or reach out with a personal message

image: thumbnail.jpg

Transcript#

This transcript was generated automatically and may contain errors.

Alright, so here we're going to talk about Beyond Static Reports with R Markdown.

So hopefully everyone is somewhat familiar with R Markdown, but it's a file format that allows us to create HTML, PDF reports, Word documents. You can knit to presentations, but there's a whole world kind of beyond that of R Markdown and it's a really flexible format, allows us to do a lot of different things. So we're just going to walk through a couple of those different uses today. And with that, let's go ahead and jump right in.

So hopefully everyone can see the IDE that I have pulled up here. This is kind of a classic R Markdown report, I'm going to call it a static report. I'll go ahead and knit it so we can just know what we're talking about instead of just grinding through code.

So this is going to create a report for Facebook, for FB, pulls in the price history of Facebook, it charts it. There's this really simple, what we're calling a forecast model down here in the bottom. And hopefully this looks really familiar to everyone as something you can accomplish with R Markdown. This is basically an HTML file, we could save this and send it to whoever we want and they would receive it and be able to read our work.

The reason I think of this as being kind of the most static, almost even hard-coded, you can almost think of this as a hard-coded R Markdown file, is that everything is kind of explicitly defined here. This is a report that I'm saying is for FB, I'm passing in this ticker symbol, FB. There's a few more examples where it's just FB, FB, FB, that's really the guts of what's going on here.

And that's great, but this is not really a document that's easily kind of changed or used for different purposes. So we can imagine if somebody said, wow, this report looks really great, could you set it up for Google, or for Amazon, or for Netflix, or some other stock? And we could definitely do that, right? We could just do a control F and look for all the instances of FB and replace it with something like Goog, and we could say replace, replace, replace. That would work, right?

It's probably a bad idea for a few reasons, one of which would be that this is a really simple report, though we would still almost inevitably make a mistake at some point. As you can see right here, I have Goog, and I'm actually pulling in data from Google, so if I did another find and replace on Goog, this immediately would mess me up.

But even if we were really meticulous about that, you know, for one thing, we've lost our original report on Facebook, and so we could say, well, no problem, we'll just make a copy of this file, and we could call the first one Facebook report.RMD, and the next one Google.report.RMD, et cetera, et cetera. That would also work, but if we ever wanted to make any changes to maybe this forecast down here, maybe we want to make this maybe a little bit more complicated or a better model instead of just calling this simple one, we would have to change it in every single one of those files.

Parameterized reports

So our markdown has a more flexible way of doing this, and that's this concept of a parameterized report. Okay, so this file is going to produce basically the exact same report we were just looking at for Facebook. I'm just going to knit it here just so we can look at it and confirm that I'm not lying. So here's the exact same report.

The difference is that up in the YAML, I created a parameter, and I named that parameter symbol because these are ticker symbols, and I gave it a default value of FB, right? So if we go back to our original document, you can see that the YAMLs look slightly different. But now if you search through this document, you won't see FB appearing anywhere else. You'll just see params dollar symbol.

So now if I want to create what we call a variant of this report for myself as the creator of this report, I don't have to do a control F and replace FB with goog everywhere. I could just do it right here, and I could say, great, okay, and I'm just going to pass in this ticker. So everywhere that originally there was FB, now there's this goog. This is one way you could do it. You could just change the default value.

That's a perfectly valid way, and okay, it works. You could also, when you knit this, instead of just clicking on the knit, if you click on this downward arrow, you could say I want to knit it with parameters because what we've created here is a parameter. We've given it the name symbol, right? So maybe it looks a little familiar from the shiny world, and actually we get this little interface, and it's going to say, okay, well, what ticker do you want? Let's say I put in, I can put in Amazon, I could go back to FB, I could go away from the tech world and say, how about Goldman.

But in any event, to me, this report has taken one step away from its original static, hard-coded nature, right, because it's a lot more flexible now for me to pop in different stock tickers, and indeed, any parameter that you wanted to pass into, say, this model, you could parameterize.

So this is kind of the first step, right, towards, to me, making this a more dynamic document. Again, I think two valuable things, one, less likely to make a mistake, two, now I can change this underlying code without having to worry about doing it for all these different variants of this report.

Multiple parameters

So I'm going to just kind of head on here, because that very simple case probably doesn't really jump out as being all that useful. So let's look at a slightly more complicated case. So here, I've almost intentionally created a lot of parameters that don't even fit on one screen.

So this is a script that's going to take three stocks, these default values to Google, Amazon, Facebook, the parameters are stock one, stock two, stock three, each of them gets a weight. We're going to create a portfolio of stocks, so they need a weight in that portfolio. We're going to assign an interest rate, and we're going to have a starting date.

And one of the things, so we're still up here in the YAML, and one of the things that this is going to show, I hope, is that the parameters don't just have to be text. They can be numeric, so the weights are all going to be numerics. This risk-free interest rate is going to be a slider input, this is going to be a date. Let's just knit this in its kind of default format.

Hopefully it'll help show how we're moving towards things being a little bit more dynamic. And some of it depends on the point of view from which we're defining dynamic versus static. This point, to me, this document has become much more dynamic from our perspective as the creators of this document. From the end-user or the end-consumer's perspective, this is still static. They're still getting an HTML or a PDF report from us, right? From our perspective, it's more dynamic. We can change it faster.

This point, to me, this document has become much more dynamic from our perspective as the creators of this document. From the end-user or the end-consumer's perspective, this is still static.

So here's what that document knits to. It's going to take our three stock tickers, combine them with the weightings that we gave them. It's going to tell us how a dollar would have grown. It calculates the Sharpe ratio, which measures the risk-reward trade-off of this portfolio. On page two here, it just shows us the monthly percentage returns of these individually, if that's important to us.

But there's a lot of parameters here, right? Hopefully this demonstrates a little bit more how, if we wanted to create a variant of this, if this had been our original hard-coded example where we were going to go through and do a Control-F on every single parameter that we needed to change, that would get a little bit complicated here and we would become, I think, more likely to make an error, right?

And this also, I think, shows why it's going to get difficult to just change things directly in the YAML, right? Here it was easy to change the different tickers. There's only one, so we can pretty easily change the symbols. When we get to have more and more, we want to actually really make use of this knit with parameters button.

So let's see what that looks like with these different formats. So one, we can change the title. How about Energy Stocks, BP, and Chevron, another one, Exxon. So these are all text inputs, as we had before, but now we have these numeric inputs, right? So we can change the weighting, so why don't we do a 40, 30, 30, sure. How about the risk-free rate we're assuming? We could take it up, that's going to make our Sharpe Ratio go down. The start date, 2013.

So hopefully this is showing that this is, at least in my opinion, greatly decreasing the likelihood that we're going to make an error and miss one of these parameters somewhere. And it's making it a lot easier to kind of create variance in this report.

All right, so here's a new report, right? Growth of a dollar invested in energy has not been a great place to be for the last four years. So it actually has a negative Sharpe Ratio, but you can see that by changing all those parameters, we changed the title, now it's called Energy Stocks, right? Here's the individual returns. So it's pretty fast to iterate through different variants of reports for us as the archivators. Again, what the end user would be receiving here would still be quite static.

So we'll just quickly look at how these parameters get passed down into the code. That portion of it is actually, you know, it's pretty, that part's pretty intuitive. You create your parameters up here, and then you pass them into the code the same way you would anything else, right? So this is just a function. It's not being affected at all by any of the parameters, right? So kind of the same as the way we loaded up an unparameterized report. Start with your packages and create whatever sort of function that you want.

And then here's where we start passing in parameters, right? We have a portfolio name, that was one, that was our first parameter. Stock one is our second parameter. Started here with a date, parameter dollar date. So we're just passing in these parameters the same way as we would if we were, quote, unquote, hard coding them. But this just makes it a lot easier to create variants of this.

So again, this is all sort of from the R coders perspective. This has become a more dynamic document and a lot easier to change. And if we did want to update this model in some way, you know, maybe we wanted to change this function to daily stock returns or weekly stock returns, you know. Or indeed, maybe if we wanted to have that be parameterized, you know, we can make this, we could add a parameter here, make this a text and call it something like, right, params dollar period or something like that, right? And then we could create a parameter up here. And then all of a sudden we'd be able to toggle between monthly, weekly, daily, different types of period returns.

All right, so that's kind of another, at least to me, another nice thing about parameterizing these is that it's a little bit of a mindset shift because now all of a sudden this, to me anyway, this feels like a more dynamic document and I can start to think, well, what can I parameterize? What would be interesting to parameterize? Well, here, I think this period might be interesting to parameterize. We're getting log returns. We could parameterize that.

The opposite side of that coin, of course, is you start to think about, well, what should I not be parameterizing, right? Maybe we want to enforce a risk-free rate, so maybe we might want to obliterate this and just quote unquote hard code the risk-free rate and say, this is one thing we're not going to toggle. It's an assumption. It's an unchanging assumption. Let's change everything else and see how the different reports come out. So a lot of flexibility. Again, this is for us as the creators of the reports.

Moving to Shiny

So to me, the ability to create these multiple parameters takes us another step towards being more dynamic. So this is the original hard-coded and then we just had one parameter and then we have a lot of parameters. I think this is maybe eight total parameters. We could keep going. If we go to 10, there's really no limit to the number of parameters that we can put in here.

All right, so now, you know, hopefully I've convinced you that this parameterization is a valuable thing for us as the creators of these reports, but let's take the next step to Shiny. And this is where things are just, they're always going to be dynamic in the sense that even the end user is going to receive a dynamic document. And again, a lot of the important stuff is happening up here in the YAML, which to me is kind of the good news, even though as our coders, maybe the YAML isn't the most intuitive place for us to be.

You know, it's nice that we can just make these changes up here and not have to touch our code a lot. There are some changes in the code, but this is really where a lot of the important changes in the format are happening. I'm just, again, going to quickly knit this, and then we're actually going to go way back to the beginning of Shiny apps, but I just want to show where we're headed with this Shiny world.

So this is, you know, the most sort of dynamic iteration of this in the sense that here we'd be delivering this app to an end consumer. We'd be saying, you can choose your own stocks and your own weights, right? And you can see in real time how they change. So this is kind of inherently dynamic. It's never going to take a static state and just stay there. Both for us as the creators and for the end consumers, this is always going to be a dynamic document.

So this is the code that was used to create this. It's very similar to the code that was used to create those reports, but the main difference is up here in the YAML we have this runtime Shiny instead of having all these parameters. So when we include this runtime Shiny line, our machine, our local desktop where we're running this or whatever server this is sitting on knows, okay, this is a Shiny app.

Shiny apps from app.r to Flex Dashboard

But just in case there's maybe some people out there who are more familiar with the traditional way to create a Shiny app, I'm going to take a brief departure here and just start at the beginning with Shiny and then we'll come back to this and we'll go through the code. So we're just going to do a five-minute departure here.

Okay, so here's kind of a classic Shiny app. It's sitting in an app.r file. This is the hello world example, right? One of the hello world examples where it can change the number of bins and see how it affects the histogram, right? So we have our inputs, a reactive sitting between these, and then our outputs, which is this histogram, right? So here it is in the app.r file.

And then here's just a Flex Dashboard skeleton with runtime Shiny. So if you want to just get started and begin kind of playing around with Flex Dashboard and the ability to create Shiny apps there, what you can do is you can take your entire app.r file and you can copy it, right? So I just did Control-A, Control-C there. This is just if you want to get started playing around. And you can copy the entire app.r file into that first code chunk, right? Library Shiny UI fluid page. And you can run this document within the RMD and it will basically reproduce that Shiny app in a Flex Dashboard format.

So I just copied the app.r over to Flex Dashboard and here's pretty much that exact same map, right? The reason I think it's useful to do this in the beginning, if you're just getting started and you're more used to app.r than using Flex Dashboard and R Markdown for creating Shiny apps, is you can kind of deconstruct the Shiny app and put it into its component pieces and see what is needed and what is not needed. In our Markdown-based Shiny app versus the more classic app.r Shiny app.

So the first thing that's not needed is this Library Shiny. You can get rid of that because we've already called Runtime Shiny. So we don't need that. There's really no concept of UI and server in the Flex Dashboard in R Markdown. So we can get rid of that.

You can see we had to do a lot of work here to tell the UI this is a sidebar layout. It's a sidebar panel, a fluid page title panel. That's not really how it's handled in our Markdown file. We just tell it up here, this is a sidebar. We drop in a line of dashes and that's how Flex Dashboard and R Markdown knows there's an element coming here and we told it that it's a sidebar. We can actually get rid of this fluid page. We can get rid of sidebar layout, sidebar panel, because I just told it it's a sidebar. To me this is going to be just a much simpler app.

This is our sidebar. I've called it inputs. You can call it whatever you want. You can call it sidebar. You can really just give it any name you want. This is really what's telling R Markdown that this is a sidebar for inputs. I think we just want that slider there for inputs. We don't really want our outputs sitting in the sidebar. We're going to make that it's own code chunk and we'll come down here. We'll create a new code chunk for our outputs.

Main panel, we don't need that main panel and the reason why is that we've indicated here that this is a sidebar. We want to let R Markdown know that we're done with the sidebar by putting in another line of these dashes. Now R Markdown knows, okay, we're done with this sidebar. Let's go to the main panel. We don't need this anymore. We said there's no server or UI logic we have to deal with. Function input output, don't have to deal with that.

We have our inputs, we have our outputs. No UI, no server, logic really needed here. We can get rid of some of this white space, it doesn't really matter. Let's see what this looks like when we run it. It's an adventure to do these live. Never quite know what's going to happen when we deconstruct and reconstruct. This looks like a pretty close approximation of what we had before in our app.R file.

It's probably a matter of personal preference or just aesthetics, which one we prefer. There's not really a big substantive difference between what you can do in app.R and what you can do in our markdown shiny file. I personally like this format better. I think this is simpler. I think that you could probably show this to someone who wasn't all that familiar with what we're doing here today and say, this is the sidebar. It has a slider input. These are where the outputs go. The output is going to be that histogram.

To me, this is just a little bit more intuitive and a simpler way to lay out your shiny apps. There's nothing wrong, of course, with using the classic method of app.R, but today we're just talking about our markdown, so this is the way we're going with today.

It is actually, you could make this even more parsimonious. You could take out this. You don't need plot output, output dollar displot. You could take that out. We could knit this. It would be fine. Just to prove I'm not lying, hopefully this is going to be fine. Okay, so it looks the exact same. I like to keep it in there, though. Again, this really is just a matter of preference. I just find mentally having this at the top makes it easier to just glance up and see that this is where I'm putting an output. It's not necessary to have it in there.

Just to kind of complete this and show what I think is kind of the power of using R Markdown for creating shiny apps is, let's say we wanted to add another plot that was responsive to another slider, or really any input. It's really fast and easy to do that, R Markdown, so this is how you add a second slider. Just copy paste it. We're going to call it bins two to distinguish it from input bins one. I think we want another histogram that's going to be responsive to that one, and we want this to be responsive to bins two. We'll call this output two and this output two.

Now we have the histogram on the left is responsive to our first slider. Histogram on the right is responsive to our second slider. We could put these on different pages. We could reorient them. We could have a sidebar that just has the first slider, and then on the second page, a slider that just has the second one.

The point, hopefully, that I'm demonstrating is it's really easy to add new elements and drop things into an R Markdown Flex Dashboard when you're building your shiny apps. For me, I just find it a little bit easier than dropping elements into the kind of classic app.r file where I would be dealing with these three calls if I wanted to put in a new input, and then I'd need to deal with my server logic. I just think it's a lot easier to kind of drop things in.

There's a whole website devoted to Flex Dashboard called rmarkdown.rstudio.com slash Flex Dashboard, and then there's a whole section on Shiny. So I'm not going to go through this, but this is all out here. The different layouts are here. Some different examples of Shiny are here. So anyway, I highly encourage, if you want to get into building Shiny with R Markdown, this website's a good place.

Back to the portfolio Shiny app

Okay, so that was a little bit of a detour just to make sure we're all on the same page in terms of how to port over Shiny apps that were constructed using the app.r format over to a Flex Dashboard.

So now let's go back to the Flex Dashboard, the Shiny app we wanted to look at. It's basically going to be built on the exact same components as our example, right? So here's our example. The key line here is runtime Shiny. Same here, runtime Shiny. We're going to load up our packages here in the setup chunk, and we're going to define our functions.

So very similar to any other Shiny app. You can define whatever functions you want up here in the setup, and then they're accessible to you. A question that we get a lot about Shiny in general is, well, what functions can I drop into a Shiny app? The answer is any of them. Any function you can create here can be called in this app.

So then, just to kind of refresh everyone what this app looked like, because I know we took a detour over there to look at the Hello World example. We have this sidebar in our Hello World example. This was just the slider input. But here we have the stocks, their weights, starting date, the risk-free rate. This is sitting in our sidebar, and the actual chart is sitting over here in our row.

The reason this is double-line instead of single-line is that you'll notice when we toggle back to it that this sidebar only appears on the first page of this app. It doesn't appear on the second page.

So here's how we constructed the sidebar for this Shiny app. And I actually did use the fluid row format here, and there's a reason for that, which is that this Shiny app is trying to put a lot of elements into this sidebar. So we have eight inputs. If we didn't go with that fluid row, they would just be stacked. So we would have eight different boxes, one, two, three, and it would start to get, I think, kind of hard to see it on one screen. So the reason that I went with that fluid row is just to be able to put them next to each other.

So the point is that you're not going to lose the ability to put nuanced layouts into your Shiny app by going with our markdown. The same things that were available to us in app.ar are available to us within the sidebar. I still think it's a little bit easier just to house them within this sidebar call.

So we have our reactive inputs, stock one, weight one. Basically we're mirroring the parameters that we had here in our parameterized report. Stock two, weight two, and I'll stop toggling in a second because I'm sure everyone kind of gets it. Stock two, weight two. The code is very similar. It has a different layout because in this case we want the user to have the chance to actually do it themselves.

And then we come down to where we're actually going to be passing those reactive inputs to the function that we defined up in the setup code chunk. So we pass in the year, stock one, stock two, stock three, and we calculate portfolio growth. We're going to calculate the sharp ratio, which is what's sitting in those value boxes. These are all just calculations. We haven't actually done any charting and graphing yet.

This is an interesting place to look at a Shiny app. So here's three lines that are layout oriented. They're not substantive. With these double lines, we're telling this Shiny app, this is page one. And we're saying this is the first row of page one, and this is the name of it. So remember that portfolio growth, row, group of $1, maybe we want to call it something like portfolio performance.

So now this is page one, portfolio performance. When we toggle to page two, you're going to notice this sidebar is going to go away. Or no, actually, I'm sorry. The reason the sidebar doesn't go away is that we defined it as a universal sidebar. If you come back up here to the top, you'll see these double lines are telling this app, this sidebar is universal. Normally this is how you define a page, but since we called sidebar first, Flex Dashboard and R Markdown know, okay, we're calling a universal sidebar that we can keep toggling no matter what page we go to.

So that's kind of a substantive choice. Do we want each page to give the user the ability to change inputs and outputs? Sometimes yes, sometimes no, sometimes we won't want that.

So back to page one, which was portfolio performance. We said this is going to be our first row, we're going to call it growth of $1. And then very similar to what we did in our hello world example, we have, in this case, it's a DY graph output. In our hello world example, we just called it plot output because that's in base R. We're using a simple plot of the histogram. Here we're using DY graph, so we're going to call DY graph output, $graph, render DY graph, and we're going to pass in our reactive to it here.

So very similar to actually our hello world example, the only difference here is we have a couple of functions, more complicated functions, sitting in between our inputs and our outputs. That's really the only difference is that instead of just passing in these tickers straight to our output, we're running them through these functions here. Other than that, this is really just the exact same as this hello world example.

So hopefully I'm convincing you that you can take your app.R, shiny apps, and kind of parse them into an R Markdown file and have them do the same thing in what I think is a nice format.

And then let's take one more look at this app. We're not just looking at code. You might have noticed that in addition to the chart that's showing the growth of $, which is here, which is here, we also have these two value boxes down here, and those are going to be responsive to any change that we make to the calculating chart ratio. So let's look at the Flex Dashboard code and how we actually put this into the file.

Well, we had to tell our Markdown there's a new row coming, because the first row had that chart that was showing the growth of $, so we had to tell it, okay, there's a new row, and the first piece of that row is going to be called the sharp ratio of our portfolio, and it's a value box. And it's going to, again, depend on that reactive sharp ratio that we defined up above, which again is really just the inputs passed through some functions. So we said, okay, new row, first value box is here, and then with these three hashes, we said there's a second. There's a second element coming, and that second element is also going to be a value box.

Okay, so that's how we told our Markdown that there's a new row, it's going to be these value boxes, and we don't want them to be very high, because we're just showing a couple of numbers. We said data height 200, which is really just an aesthetic that we're setting, and it's a relative aesthetic in the sense that it's not an absolute 200. It's going to say, well, if this is 600, and down below is 200, it's going to set these heights relatively, which is why down here we said, okay, let's make this data height 350. This is just some background on the sharp ratio.

It's really just here to kind of show that you can also include static content. Not everything has to be reactive. When you're building a Shiny app in our Markdown, you can still put in, just like you always can in our Markdown, you can still put in your text, right? So if you want to have some text in here, and you want to write something up about your Shiny app, you can still drop that in to your Shiny application, right? So I just said this is going to be a new row, and I said let's give it a title, background, but then this is not in a code chunk, right? This is just text, the same as we would always be doing with our R Markdown files.

And then we said, okay, let's drop in a second page where we can just show the monthly returns. This I think of as almost a way of just telling people, you know, we're doing all these calculations, we're passing all this data through these functions, we're calculating the growth of a dollar, we're showing the Sharpe ratio, but if you want to look at the, we could think of this almost like raw data, just the monthly returns for each of the stocks that you selected, here it is, right? So this is probably just a personal preference of mine. I almost always like to have a page too where there's some sort of way to look at raw data, the data that I haven't really passed through a function.

So here we're changing it into monthly returns, it's not just prices, but it's a place for someone if they are so inclined to check out the raw data that's underlying it. So this is page two, individual stocks, we could call it individual monthly returns. I'll just change it just so we can see how that's going to change the final output.

And you'll see that now we have a page called individual monthly returns with monthly misspelled, but that's okay. Right, and again, so this is going to be responsive to our sidebar, of course, because it's pulling in the percentage returns of each ticker. So if we start changing these to BP and NPM, we're going to get different monthly returns because these are different ticker symbols, right?

Q&A and deployment

Okay. All right, so I'm going to pause here for just a second, and I'm going to take a look to see if we had any questions come through. And one is, can you enforce constraints in the relationships? Yes, you can. You could define them in that way, but you could also, yeah, you can enforce the constraints. You would really just need to code, to put it in the code. But I can send you an example on that if you send over an email how to do it.

How can you use Flex Dashboard with a Shiny server? And the answer is the exact same way as you load your app.r file is you would load up this .rmd file in the exact same way. And when the server, quote unquote, sees this file and the server notices this runtime Shiny, it's going to know this is a Shiny app. So it's going to be the same way as you were loading up your app.r files. But I would really just encourage you, if you want to try it out, just grab that hello world example, put it into a test rmd, and then put it on your Shiny server and see. But trust me, it'll see this runtime Shiny, and then it'll know it's a Shiny app.

Can you run through the deployment options for Shiny rmd? It is the same as a Shiny app. So if you have shinyapps.io account, it's the exact same. You'll publish it by pushing a button. If you have a Shiny server set up, you'll move your markdown file the same way as you would your app.r file. If you have a Connect server, it's the same process. You'll push your button. You'll zip it up to Connect. So there's not going to really be a difference in publishing.

I guess the only difference is if you're used to using a UI and a server individual file, that's not really going to be part of an rmarkdown-based Shiny app. It's going to be one file. But yeah, those are very good questions, because obviously we need to deploy these in some way.

Helpers file and workflow efficiency

And I'll just, if anyone has others, please put them in the chat. There was a couple of other things that I thought might be interesting to cover. So I'll just kind of plow ahead here. And I'm going to toggle over to a different set of rmarkdown reports slash apps. Similar setup in the sense that we start with an unparameterized document. We move on to a parameterized document, and then we move on to a Shiny app, right? So this is kind of my workflow for almost anything I'm creating. Start with something unparameterized, the simplest case. Move on to parameterized, and then move to Shiny.

One thing that having that workflow enables is that if you want to kind of stuff your functions into a helpers file, right? So what we've toggled to over here is a slightly different use case. This use case is going to build a portfolio of stocks, going to calculate their volatility. So we're leaving the world of stock returns. It's going to calculate their volatility, and then calculate the contributions of each asset to the portfolio's volatility, right?

But each of these three documents, unparameterized, parameterized, and the Shiny app, if you look at their setups, which I'll toggle down to right now, their setups are all exactly the same. We start out by loading up these packages, right? This is all three files. And then, second thing we do in each of them is we load up this .R file. And that .R file has a set of functions that I defined earlier.

One to calculate component returns, which is here, it's the first one, right? The second function in here calculates contribution to volatility of each asset that's chosen. And then, the last one calculates the portfolio volatility, right? Doesn't matter what the substance is. The point is that one of the things that I think makes building Shiny apps in R Markdown quite efficient is that if you're building a report using R Markdown, and you're building a parameterized report using R Markdown, and then you're building a Shiny app using R Markdown, they can all use the same helpers function, right?

So to me, that's nice because I don't have to worry about changing all three of these, right? If I want to mess around or test out functions over here, I can just do it in this one file and then all three of these are pulling them in, right? Kind of same with formatting. There's a lot of efficiencies to be gained if you spend a lot of time formatting a report the way you want it.

So this is our unparameterized report. If you spend time kind of formatting this and getting it to look and feel the way you want, and then you decide, I want to turn this into a Shiny app, it's not a lot of work to take this structure and put it over here. In fact, it's going to be really, really similar. Once you have the look and feel the way you want it and your unparameterized static report, you can take it to a parameterized and a less static report, and then you can take it to Shiny and all the trial and error that went into making this report look good, almost all of that learning is going to translate into your Shiny app.

All the trial and error that went into making this report look good, almost all of that learning is going to translate into your Shiny app.

It's going to be a little bit different because the look and feel will vary because in the Shiny app, of course, you're giving the user that sidebar inputs where they can actually put stuff, change stuff, so you need to kind of think about that, but other than that, these formats are going to mirror each other. So I kind of find that there's a lot of efficiencies, especially for someone like myself. I don't really want to spend a lot of time thinking about formatting. I want to spend as little time there as possible. I want to spend as much time as I can here in helpers.r working on these functions, and I want Flex Dashboard and R Markdown to really handle that formatting for me.

The action button and reactive performance

So I'm just going to go ahead and knit this file, because there is one thing that I want to show you all. So this app is a little bit more analytically, I would say, well, at least time-consuming than the other one, right? It's building a portfolio, calculating standard deviations, and then the contributions over timing that's having to do that for three different stocks.

All right, so you can see that this app didn't start running until I pushed go, which is different from this app, from the Sharpe Ratio app. This was calculating the new Sharpe Ratio every time we changed a parameter, which really isn't that efficient. It isn't that big of a deal if your app is going to run extremely quickly, meaning it isn't doing a lot of heavy computations. But for this volatility app, I don't really want that, because every single time anything here gets changed, if I didn't have this go button, it would start trying to recalculate, recalculate, recalculate, and that would eventually drive our end users insane.

So apologies if this is kind of old hat for people, but the way that we handled that was here with this action button go. So clearly what that's doing is it's waiting for someone to push go before anything happens, and then the link between this button and the rest of our app is right here. So instead of creating a straight up reactive, which is what we were doing here in our original app, our Sharpe Ratio app, these are just reactives. They're not waiting for anything, they're just waiting for inputs. Reactive, reactive, reactive. Here we're using an event reactive, and this event reactive is saying wait for input $go, and don't do anything until you get that input $go.

So I just, it's not specific at all to our Markdown Shiny apps. This is the same as you would have in a normal app.r, but I like to just kind of point it out whenever I'm going through Shiny apps because it can save your end users a lot of grief and frustration from having things run every single time they change an input. And it's really, it's not hard to get this set up. You just add an action button, it doesn't have to say go, it can say submit or something. Whatever you kind of want to tell people to do. It's just waiting for input go to get fired off.

So that's going to, it's not really going to change the performance of your app, and since we're doing two calculations, we need it twice here. So I'm calling two reactives input $go. This probably isn't the greatest construction in the world