Resources

Quarto Dashboards 2: Components | Mine Çetinkaya-Rundel | Posit

Building dashboards in R and/or Python with Quarto, one component at a time. Before watching this video, you might want to watch Part 1. This video takes you through 0:00 - An overview of dashboard components 0:11 - Navigation bar and pages 4:55 - Sidebars, rows, columns, and tabsets 11:07 - Cards 22:40 - Live coding demo Slides can be found at https://mine.quarto.pub/quarto-dashboards/2-dashboard-components and the starter documents for the accompanying exercises at https://github.com/mine-cetinkaya-rundel/olympicdash. Materials for all parts of the videos can be accessed at https://mine.quarto.pub/quarto-dashboards

image: thumbnail.jpg

Transcript#

This transcript was generated automatically and may contain errors.

In the second video of the Quarto Dashboards video series, we're going to talk about dashboard components. So, what do I mean by dashboard components?

First of all, let's look at the top of a dashboard, the navigation bar, where we have things like the icon or a title for our dashboard, things like an author field if you've added it to your YAML, along with links to subpages if we have more than one page to find. And by the end of this video, we are going to create a dashboard with two subpages in it.

After our navigation bar on top, we can add further content into the dashboard. We do this in rows and columns. We do those with markdown headings, and we can add optional attributes to control the height of your rows or the width of your columns.

Sidebars are mostly used for interactive input, so if you have an interactive dashboard, that's where some of your widgets that your users can interact with can go, but they can also be useful for overall information about your dashboard or drawing the attention of your audience to a particular part of your dashboard as well.

And then to further divide content, we can use columns inside of rows as well as tab sets as well. And finally, the content of your dashboards generally live in cards. So these are containers for code cell outputs. It could be a plot, a table, a value box, as well as free markdown text. The content of the cards typically maps to executable cells in your notebook or your source document, but they could be coming from other things as well, like the markdown text we mentioned.

Throughout this video, I'm going to give some examples of dashboard components and layout and what might go into these cards. So we are going to see some code cells as well. The examples will primarily feature R code, but all of the code in these cells can be replaced with a Python version, a Julia version, or an observable version, and the layout would look exactly the same, except in a couple places, particularly when we get to value boxes, I'll call out that to do something that we are first shown in R in Python, we may need slightly different syntax. So we'll have callouts for those, for those of you following along in Python.

All right, let's start with navigation bar and pages. So here's a dashboard in a QMD file. I have on top my YAML with a title, it's called pages, and then format dashboard, since that's all we need for a QMD file to render to a dashboard. And then we can see that we have first level headings. So one of them is called scatter and the other one is called bar. When we render this, we can see that those first level headings map onto pages in my dashboard.

So here's page one, here's page two, and in the first video, we've seen that when we actually give names to these headings at the second level for rows and columns, those don't get reflected in our dashboard, but page names actually do. So those words will go on your navigation bar.

And then another thing that could go in the navigation bar is a logo, and that's something we define in our YAML. So I've defined that underneath dashboard in my YAML, and I'm referring to a local image in this case, because we're working with the cars dataset, I picked the picture of one of my favorite cars, a little beetle. So we can see that that is coming from the images folder, and it's, Quarto is doing the right thing to size it. So you don't need to do anything for that.

Other things we can add to our navigation bar are other buttons. For example, social buttons. Here I have buttons to GitHub, to LinkedIn and YouTube. We can see that we're using bootstrap icons for them. So that's when we say icon, column, GitHub, for example, that's what it's looking for. We then have an href to where we want that link to go, and we can also add an accessible label to them as well.

And here we go. We can see those three social buttons, and Quarto is doing some like default styling to move them to the other side of the navigation bar. As you can imagine, anything is customizable, and we're going to talk about sort of styling and customizing the style of your Quarto dashboards in our third video. But for now, we're going to stick with the default layout for these things.

For some of the social links, we actually have special aliases for them. So that's LinkedIn, Facebook, Reddit, Twitter, and GitHub, things that we've assumed to be the most commonly used. So in that case, you can actually list them as a list in nav buttons and then give their URLs individually, referring to the particular icons that we're pulling in.

Next, let's talk a little bit about sidebars, rows, columns, and tab sets. So sidebars are going to be for information about the dashboard or your data, or as we said earlier, for user inputs and interactive dashboards. They can be at the global level, so shared across each of your pages, or they can be at the page level as well.

To have a global sidebar, we define it just like we would define a page, so with a first-level header, but we are denoting the class to be sidebar in curly braces with .sidebar. And then I have some text here that's going to be reflected in the sidebar of my dashboard, as we can see here. And if I scroll over to the other page, we're seeing that the same sidebar is available there.

For a page-level sidebar, we can then leave the page label as a first-level heading. And then inside of that, we're using a second-level heading for our sidebar with the same class and the same text available here. So here we can see that that sidebar is available on our scatter page, but it's not on our other page on the dashboard.

By default, your cards are going to be laid out in rows. So when we give Quarto Dashboard second-level headings, the first one is going to be row 1, and the second one is going to be row 2. So we can see that these cards are basically laid out in those rows. And once again, the words scatter and bar do not appear on our dashboard. Those are things that I personally prefer to give meaningful names to so I can navigate my QMD document nicely, but they're not meant to be reflected to your users.

Another way of saying by default your cards are laid out in rows is to say that the default value of the orientation field in your YAML is rows. So we could add that, and we would get the same result. And if we switch that to columns, that makes each second-level heading a column instead of a row. So in this case, those second-level headings for scatter and bar create two cards that are placed next to each other across two columns.

So one way of designing your dashboard would be first divided into rows and then to columns. So in this case, your second-level heading is going to define a row, the overview row. And then inside of that, we're going to have third-level headings that define columns. And similarly, the second row is going to be plots. And inside of that, we're going to have a scatter plot and a bar plot. So this is what a four-quadrant dashboard created like this would look like.

If we wanted to do columns and then rows, we would set the orientation to columns. And then the second-level headings are going to define your columns. And inside of that, the third-level headings are going to define your rows. So we can see that overview is going to be one column with two rows inside it, some text, and then an image. And plots is going to be the second column with two rows inside it. That's going to be two plots on top of each other.

We can then set the heights and widths of our rows and columns. So here, I have set the orientation as default. So that's going to be rows first. So overview and plots create some rows. The first one is of height 30%. The second one is taller, 70%. And inside of the first row, we have two columns split 20% and 80% in width. And inside of the second row, we have two columns split 75% and 25% in width. So you end up with something like this.

We've seen that each row in a dashboard that's not given an explicit height will determine its size by either filling the available space or by flowing to its natural height. The filling layout is generally the default. But for certain types of content, for example, when you have marked-down text, flow layout is the default. If the default behavior is not what you want, you can explicitly specify filling or flowing by using the .fill or .flow classes applied to a row.

And you can also apply another class, either at the dashboard level or at a page level. Scrolling could be set to true. So this is to accommodate any sort of page overflow if things are simply not fitting into your page. I should note, though, that while this option is handy for adding many, many more rows of cards to a dashboard, spreading these across pages and tab sets can be a better way to present information.

Oftentimes when we're looking at a dashboard, it's sort of like you're looking at a printed poster. You expect things to fit in that one screen. And if more depth is needed, you look for those across pages or tab sets as opposed to scrolling down on that dashboard.

Oftentimes when we're looking at a dashboard, it's sort of like you're looking at a printed poster. You expect things to fit in that one screen. And if more depth is needed, you look for those across pages or tab sets as opposed to scrolling down on that dashboard.

Orientation and scrolling can be provided at the dashboard level, which would mean that those would be set at the YAML or at the page level as well. So here I'm defining, for example, orientation rows or orientation columns and then scrolling true in addition to that as well.

To divide content further, we said tab sets could be handy. In order to do that, we would define a tab set class that is associated with a heading. So here we have two headings, Overview and Plots, that are both set as tab sets. And we can see that inside of my first row, I have two tabs. Those are my third level headings, Objective and Car, being translated to two tabs in my dashboard. And similarly, in my Plots row, I have Scatter and Bar that end up being the titles for the tabs for that second row.

Cards

And finally, let's talk about cards, sort of the primary building blocks of a dashboard. These are, as I said, the fundamental unit of display, and they are created automatically for cells, computational cells, and also markdown content that are within rows and columns. So you don't have to say, I want a card here. You get the cards for free, and then you can further control their behavior. But if you would like to manually create a card, you can also do that with a fence div as well. So that's three colons, and then the card class applied to that.

Cards can provide an expand button, which appears at the bottom right on Hover, and that will allow you to sort of make that card bigger, which can be really handy if you have a detailed plot or a table that is originally taking up only a little bit of space in your dashboard, but you want it to be able to zoomable.

So here we have some computational cells, and the card titles can be provided as a cell option to that. Or if you would like to computationally generate those card titles, we could use a function like cat in R or print in Python. So let's take a look at this.

So in this particular code cell, we've given the card title as a code cell option that is following the hash pipe. So that's title colon highway versus city mileage. That's going to be the title for that first card. In the second card, we are first calculating how many cars are in this data set by finding the number of rows, and then we're writing a cat statement that will put together some pieces of information. The first element is title equals, so that's going to be something that your computational cell needs to emit so that it can be picked up by Quarto. Then we have some text, drive types of, and then we're basically pasting together the number of cards that's calculated and then followed by the word cars.

So we can see that in the first cell, the highway versus city mileage appears as a title, and in the second cell, the number 234, which is the number of rows that's calculated, is being used in the title of the cell.

All right, time for a pop quiz to see if you've all been following. Let's take a look at these. Which of these is going to become a card in a dashboard? Remember that we said we get cards for free, but in order to get cards, what do we need? We need an output to be emitted. I'll give you a second to stare at these options, and let's take a look at them.

In A, we're loading a package. That's not going to emit anything, so that's not going to result in a card. In B, we're assigning the value 2 to X. That's not going to emit anything either. In C, we actually have a plot that we're generating, so this will result in an output, which then will be placed in a card, so that was the right answer. And in D, we have an arithmetic operation, 2 plus 2, that should result in an output as well, the number 4. However, note that we have set output to false for this particular code cell, so that's not going to result in a card either.

That can be a helpful tool when you're trying to troubleshoot. I wouldn't necessarily recommend a bunch of code cells that have output set to false. You should, I think, divide them up so that each code cell that generates an output should actually result in a card that's being used by your dashboard. However, during the development process of your dashboard, it can be handy to turn output off by setting it to false, just so you can see how layout of certain components might look like, for example.

If a cell generates multiple outputs, they are going to get wrapped in a single card. So let's take a look at this cell. I'm making a plot and then another plot as well, and both of these end up in a single card.

If you want, you can further control the layout of these two plots. So we can use the layout and call option, which is an option that's available in Quarto outside of dashboards as well, that tells us how to lay out the outputs. But in a dashboard setting, that will still keep the output plot inside of the card, but lay them out one next to each other or across two columns. So this is what that would look like.

Value boxes

And finally, value boxes. These are pretty commonly used in any sort of dashboard, so they're available in Quarto dashboards as well. They're a great way to prominently display simple values. You can create value boxes with executable code cells or in plain markdown divs as well. Value boxes use bootstrap icons, so whatever is available in bootstrap icons will be available for you to use in your value boxes as well. And they can be set to any color, so you can give it some of the color names that Quarto will recognize or a hex code, or you can use one of the color aliases that's defined by your theme.

So we're going to talk more about themes in our third video, but you've probably seen if you've worked, for example, with Quarto and added some callouts to a simple document you may have created, you're probably familiar with what info versus warning versus danger might look like, and you can also leverage those colors as well.

This is what value boxes would look like in a Quarto dashboard with R code being used in executable cells. So here we are defining a row with a height of 25% to put our value boxes. Generally, we don't want them spanning a huge amount of height in our dashboard. They can, I think, take a little bit of space. That's why we've only set them to 25%.

And then I have an executable cell where I'm doing a little bit of calculation. So for example, the lowest city mileage car, I'm trying to pull out what that mileage is. As well as the highest one as well, and then also the average. So we have three values calculated that we're then going to use in our value boxes.

This is a code cell that doesn't have any output, so these are going to be objects that are available for us to use in a subsequent code cell that might look something like this. We set content to value box to say that content of this executable cell is going to make up a value box. We can give it a title. We can give it an icon from bootstrap icons, and we can give it a color as well. And then we define what we want to go into the value box as a list item.

So in this case, we're saying value is sort of made up of these two things, the lowest mileage city that we had already calculated and the character string mpg so that we can add some units to that. So this is the lowest or least efficient car, most efficient car, and we have different icons selected for them.

And here we're exemplifying something else. We are creating a value box using plain text markdown and also as a fence div. So we have a fence div with a value box class. Then we can define the icon here as well, as well as the color. We add some plain text markdown here, and then we're able to refer to that value that we have calculated as just inline code. So within BAPTX, I have in curly braces my engine R, and then I can refer to the value that I had calculated.

And then in a second row, I have my plots from earlier. So this is what this dashboard would look like. We have the various colors that we're drawing from our default theme. And you can see that the formatting of these value boxes are a little bit different. The ones that were created with the executable code cells get these much larger value numbers and much smaller text versus since we haven't expressed anything similar for the one that was created with plain text markdown, the text sizes are the same regardless of whether it's the informative text of what's in there or the value followed by MPG.

In Python, in order to do this, we're again going to create a row where our value boxes can go and calculate some values. So obviously the code for calculating them is different, but the idea is the same. We calculate some values, put them away so that you can refer to them later. We set content equals to value box, the title, icon, and color. So all of those code cell option definitions is exactly the same, but we're using a different function here in order to be able to create those values that go into the value boxes.

And similarly here, we can also add some of these choices like icon or color and add that into our list that were created in the dictionary that were created in Python as well. Or we can do the same thing as we've done on the R side and create them using fence divs and we're using the same trick of being able to pull that value that we had calculated using inline code, once again, defined by backticks and then the name of the engine in curly braces.

And the second row is just a much taller row that has our plots. So this is what it looks like. You can see that it is basically impossible to tell the difference between the two dashboards once rendered, but under the hood, things are a little bit different, particularly in terms of the function that we're using to create the content of the value boxes.

And let's talk a little bit about markdown text. You probably want to keep markdown text to a minimum because people don't necessarily tend to go to dashboards to read a lot, but you can include markdown text anywhere within your dashboard. It's automatically placed in cards, but you can also explicitly put them in cards with fence divs as well. And when you do that, that allows you to add titles to your cards too. You can place markdown text and other cell output in a single card as well. So here we've defined a card with a fence div, given it a title. And then inside of that, we have some text as well as some code that generates some output. And all of that is going to get encapsulated in a single card.

We're going to get a little bit of practice with that when we get to the live coding portion of the video. So let's go ahead and do that. Let's build. If you would like to refer back to these slides, they're at the link on the top. And if you are curious about how the slides are made, they're also made with Quarto. And you can take a look at the source code for those too.

But our goal this time is to take that Olympic dashboard that we started with in our first video and pick it up where we left off at the end of the first video. So whether you were doing the R adventure or the Python adventure, pick up where you left off. And our goal is to get to something like this. You can see that there are a few things happening here since video one. First of all, we have content spread across two pages for summer and winter Olympics. We had everything together in the first one. Secondly, we have some value boxes, some tab sets, some tables that we have nicely colored. And also over here, we have some markdown text and a plot that appear in a single card.

And on the Python side, things look very similar. The only really visible difference is the default color selection for the two visualization packages we're using. That's a little bit different. Similarly, the color palette for the tables that we're using with either the GT package or the great tables package. But ultimately, we're creating very similar looking dashboards in either way.

Live coding demo

So let's go ahead and switch over to R. And if you have already gotten the materials for the starter files from the Olympic dash repository, open up file that ends with dash two. So whether that's Olympic dash R dash two or pi dash two, whichever version. And let's go ahead and render that. And this should be right where we left things off at the end of video one. So here is what our dashboard looks like.

First thing we're going to do is we are going to separate our content across two pages. So we're going to create two pages, one of them for summer Olympics and the other one for winter Olympics. So I'm going to do that by adding a first level heading. And similarly, at the very end, I will add another first level heading, winter Olympics. I think that I had also used some emojis. So let's go ahead and get those as well. Maybe a sun for summer Olympics. And for winter Olympics, let's do a snow.

Okay, I'm using the insert anything tool. Since I am at the beginning of my line, I'm able to use just a forward slash. And that brings up the various options I have to insert some content into this. Okay, so I haven't really put any content into the winter Olympics part, but I'm going to just render the document to see that I indeed do have two separate pages now.

And the way we're going to do this is we're going to basically build a bunch of stuff for summer Olympics. And then we're going to duplicate that content for the winter Olympics as well. But before we can do that, let's go ahead and actually, in summer Olympics, let's go ahead and get a data set that only has the summer data. So I'm going to go ahead and add a code chunk. Let's give this a label. Call it summer prep data. Our data set was called Olympics. And I am going to simply filter where season is equal to summer here. And I am going to name the resulting data frame summer underscore Olympics.

And going forward for any of the places where I was calling the overall Olympics data, I'm going to just refer to summer Olympics instead. So let's go ahead and do that. And for now, I'm going to set winter Olympics aside. Let's go ahead and build our dashboard how we want it for the first page. And then we can copy and paste what we have done into our second page.

Then what we want is in the summer Olympics page. If we go back to sort of our goal, we can see that our two columns are not the same width. So it's roughly 65% for the first and 35% for the other one. So we can go ahead and edit those columns. I can do that using the visual editor. So I could go here and say something like width equals 65%. Let's go ahead and render that to see what that looks like. And that made the other one much narrower. But we can explicitly define that as well. Let's see how this is reflected on the source code side. So we can see that that added the width definition in curly braces. So I can do something similar here as well. And I will set that to 35%.

And for the rows, our rows are already set to 60% and 40%, where we have a little bit more space for our bar plot than our line plot. So we're good there.

Another thing we wanted to do was to add some text, some informative text into this card, where we have the medals by year plot. So that text says something like due to World War II, no Olympic games were held in 1940 and 1944. And if I keep this as is, we'll see that this is going to generate two separate cards for me, which is not really what I want. And because I'm already in a row, then it splits them across two columns. So I need to say these two pieces of content, markdown text and plot, need to go into the same card, which means that I need to define a card using a fence div.

So let's do that. This is a card. I will give it a title. So I can actually remove that title now from this plot. It becomes a moot point. We don't want it to have another title inside of that. And then at the end of that code cell, I can close that fence div. So this will encapsulate those two pieces of content in the same card, as we can see on our output.

What do we want to do next? The next thing we want to do is move on to our second column. So let's take a look here in our second column. We have two types of content, some value boxes and then a table as well. And then that table has tab sets in it. So let's first do the separating. We're going to create one row inside of our second column. So columns are defined with second level headings, which means that my row is going to defined by a third level heading. My first row is going to be value boxes. And then my second row is going to be the table. And in fact, this is tab sets of tables.

So let's go ahead and render this. Because for these rows, I haven't yet indicated a height. And I also have absolutely no content in my first row. I'm ending up with nothing reflected in my rendered document. So usually what I like to do is add some placeholder content here. I'm going to add one markdown text. And let's go ahead and render to see what that looks like. And let's give this a height. We're going to make this 30%. And we're going to make the height of the second row 70%.

So now we have the two pieces of or two cards where our content is going to go. Let's start with our value boxes. So let's take a look to see what is in our value boxes. We have things like most golds, which country, most silvers, which country, most bronzes, which country. Looks like for the Summer Olympics, that was the United States for each one of them. So what I need to do first is calculate these values. In order to do that, let's add a code cell.

I will label this Summer Calculate Medals or maybe Most Medals or something like that. And there are three types of medals we want to calculate. So we're working with the Summer Olympics data frame. I'm going to first maybe filter for where a medal is gold. And then I might count which team and sort them. So the team with the highest number is on top. And then let's do something like slice head and equals 1. Let's run everything up to this point. And then let's run this code cell as well. That gives me the 2363 that I was seeing in my finished dashboard as well. And we can do something similar for each of the other medals.

So that will give me the pieces of information that I need. And I'm going to also save the results of these, something like summer, most golds, most silvers, and most bronzes. And when I render this, I should not see anything reflected in my dashboard because I'm calculating these. But right now, it is not giving us any results that need to go into a card. So next, what we're going to do is we're going to create our value boxes. In this particular case, I'm going to choose to create the value boxes using fence divs.

So that will be a dot value box. And I could say something like most golds. And let's take a look to see what do we exactly want them to look like. The number. So that's going to be, if I take a look at this object, let's run this code cell. If I take a look at this object that has the number 2363 is in the n column. And then we also have the name of the team, summer, most golds. And that's going to be the team. Let's go ahead and see what this would look like. That should create a single value box for us. And I'm getting an error. I'm getting an error that is saying that it failed to parse the inline R code.

So let's take a look at our summer Olympics data frame. I'm going to glimpse at it. And one of the things I can see here is that when we created this over here. So let's take a look at this output where we counted. So this is the piece that I want out of here, right? The team variable. Oh, it is actually failing because I'm missing a back tick. So let's go ahead and do that. Let's go ahead and add our back tick to see if that actually resolves the issue for us. We actually do have a value box. It's missing the icon and also the color.

So the icon we're going to use is award-fill, and the color, I will cheat and tell you what color I had used, but you can really pick something that is gold color-ish. So D4AF37 was the hex code for the gold color-ish color that I used for this particular value box. So we can see that that is looking pretty good. And what we need are now the other three value boxes. So I can go ahead and leverage what I've done here. This is going to be most silvers, most bronzes. Instead of golds, let's use silvers and bronzes. And we're also going to want to adjust the colors as well. A gray-ish color for silver and a bronze-ish color. I'll do CD7F32. And here we have our value boxes, too.

So what's left to do here? What's left to do is something about the tables, finally. So let's take a look at our goal. It looks like we want to find the top 30 medals and bottom 30 medals. And then we're going to apply some formatting to that as well. So currently, our table over here gives us a single table of medals by country. So we're going to want to split this into two. And we are going to want the results of those across two tab sets. So how will we go about doing that?

Let's, first of all, split the calculation into two. So instead of medals by country, we are going to update the label of this to say something like Summer Top 30 Total Medals. And it looks like we want to call it Top 30 Total Medals for the title. And then we're going to want to create something similar. And this is going to be Bottom 30.

So let's go ahead and leave this for a second. And let's see, what would this look like with two code cells in this row? And we're going to then see, how do we put them across tab sets and then finally bring in the calculation? So we're in a row. And what it did is it sewed two code cells that both emit some output and hence put them across columns. But we want to say, do not put them across columns. Actually, put them across tab sets. So we're going to add the tab set class at the row level.

And that basically gives me, if I pop this out to the browser, it's a little bit easier to see that we actually have the two tab sets now. It just so happens we have the same table in them for now. We'll fix that. But let's take a look at our inspiration. It also looks like we don't just want the table, but we also want some text in there as well. So team sorted in descending order of metals. And it's probably the ascending order on the other side. So let's go ahead and add that text. Sorted in descending order of metals for the top and for the bottom. That's going to say ascending order of metals.

Now I have four pieces of content in this row that has a tab set class assigned to it. So what does that look when we render things? It actually places the text in its own tab as well, which is obviously not what we want. And because it doesn't have a table, it sort of gives it a placeholder table. But we know how to place some text and some R output into a single card. We've already done that here. So let's go ahead and use that same technique. Let's go back to where we had done that. So we did that by adding a card. So here I'm going to add a card. And we can name this Top 30 Metals instead of naming our executable cell that. And similarly, add another card here that encapsulates that text that has the bottom 30 metals as its title. And then we close the fences for that as well.

This is looking good, except that we now actually have to deal with what is in the executable cell. So let's go ahead and do that. We are going to say, before we actually turn it into a table, once we have arranged them, we want to take the top 30 rows. And then we can make a table out of those. And a few things that we might want to do is let's go ahead and align the columns. So we have two columns here. But we want the team name to be aligned on the left.

So let's see what this would do if we were to do the same thing, except not in descending order for the second one, and do something similar in terms of the code cell content. And here we go. Now we actually have different content in here.

And finally, one thing we did was to try to line up the colors we're using in the table with the rest of the theme of the document, the colors of metals, and also colorize the data. So different colors mean different magnitude. And we can do that with the data underscore color function in the GT package. This is going to be a numeric variable. So we'll set method to numeric. And for the palette, I'm going to use a palette from the Nord package. And let's go ahead and do that for both of our tables.

We basically achieved our goal, except one thing that I haven't done in this video was to then duplicate the content for Winter Olympics as well. How much work would that be? So let's see if we can do that pretty quickly. Let's go ahead and copy everything that we have done so far under Summer Olympics. And then let's start here and say that we want this to be Winter Olympics.

And then what I'm going to do is simply do Summer Olympics, replace it with Winter Olympics when I can. So let's move to each instance that we are seeing it. We don't want to go any further. And then also, let's go ahead and starting here, look for the word Summer. We have used it in a few places. So let's see where we're finding it. For example, we don't want code cell labels with the duplicated code cell labels. So I'm going to change them here and also where we're referring to them in our value boxes as well as in these code cell labels as well.

And we're going to remove this filter for Summer Olympics only from our step one for the preparation of our data so that we get both the Winter and Summer Olympics. Let's take a look to see what is giving us some error. Medals by sport is a cell label that we've used twice, it seems like. So maybe we can call this one Summer medals by sport. And then the next place that we see that, we're going to call that Winter. And my guess is we're going to have some similar issues with other code cell labels. So I'm going to name this Summer as well. So that's Summer medals by year. And the next instance of that, we're going to name that Winter. Let's see if that catches everything that we needed to deduplicate.

And here we go. We actually have our content for both Summer and Winter Olympics. And we can see that in the Winter Olympics, there are some other countries that have the most gold, silvers, and bronzes as well. If you would like to follow along with this or refer back to some of the code that we've written in the repo where you got the starter code under the R directory, you can also find the answers, everything that I have gone through for this step, and similarly under the Pi directory, the equivalent answers for the Python version.