Hey folks, I'm Pat Schloss and this is Code Club. June 19th, 1865 marked the date that slaves in Texas were finally liberated in the United States and has become the day annually that is recognized as the Emancipation Date and is celebrated as a holiday and has been celebrated for some time among the Black community. And recently in the last several days, President Biden signed into law an act declaring this to be a national holiday. To commemorate this holiday over the past several episodes, I've been developing data visualizations using data drawn from the CSDE lynching database. This database has done its best to catalog lynchings of mainly Black men and women between the years 1877 and 1950. Two episodes ago, I built a line plot showing the total number of lynchings of Black individuals between 1877 and 1950, as well as a heat map that indicated the number of lynchings that occurred by state and by year. In the last episode, I then went on and took that heat map idea and applied it to a map of the southern United States, the states where lynching was in practice, and to show the number of lynchings by county. As we've gone along, I've commented that one of the refrains that we hear from the Black Lives Matter movement and from the protests last summer is the concept of, say the name, right? Say the name of the victim. Don't just let them be forgotten to history. And so in some ways, the visual is that I've already been showing, we didn't say the name obviously, right? We were looking at aggregated statistics, we're looking at counts, we're looking at, you know, a total, something like that. And in a way, it kind of dehumanizes the victims. And of course, we can't always show data at the individual level. But as I was thinking about this concept and kind of reading literature and how people think about racial violence, again, this idea of say the name came back to me. And what I would like to do in this episode is I'm going to create a movie, a data movie, where each frame of the movie is that map of the southern United States with each county lit up as the name of the victim is pronounced, so to speak, in the movie. And so that is the task for today. As you've perhaps seen over the last several episodes, there really isn't anything new that I'm presenting if you've watched, you know, the past 100 some episodes of Code Club. To make this all happen, we're going to use the great GGAnimate package, and we'll also do a fair amount of data cleanup so that we can have a nice attractive label, and that we will finally produce this video to show how to make the video. And then I will also produce a video that I will also post in parallel to this. So I encourage you to watch this, but I certainly also encourage you to watch the video where I show the name, the county where that person was killed, as well as as much information as we have about that individual. Sadly, many of the people in the database, we don't know their name. We perhaps know their sex, maybe their age, and we do know how they were killed. Let's go ahead over to our studio and we'll get going with today's episode. So I've gone ahead and taken the code from my JuneteenthMap.R script and put it into a new script, which is JuneteenthMapMovie.R. Let me go ahead and source this so we can see the map I've already shown you in the intro of what it looks like, but let's double check that the code actually works. Great, we get the figure that we ended the last episode with. A couple of things that I see in this that I'd like to go ahead and clean up. So for the movie, I'm going to get rid of the title as well as the legend. Also, I'm going to put this up onto YouTube that has an aspect ratio of 16 wide nine high. And so I'm going to go ahead and change the proportions of the figure. And I can then come down to my code where I built out that figure. I'm going to go ahead and remove the title. And I'll remove this legend position coordinates. And in here, I'll put none, which means don't show a legend. And then I also don't need to worry about legend direction. I'm going to do lynchingsmap.tiff. That's fine. My height, I'm going to make 4.5. And my width, I'm going to make eight, right? So that'll give me my 16 by nine dimensions. Let's go ahead and double check this all works. We have our map in that 16 by nine aspect ratio looks good. And now what I'd like to do is go back into the code and remove the aggregation so that our data frame that we're mapping that we're plotting is at the individual level rather than the aggregate level. I'm going to go ahead back up to the top of my script here. And I'll go ahead and comment out the assignment. And let's look at the code to see where we're aggregating things and make sure that like the information we're interested in is actually coming through the pipeline. So again, we read it in, we turn all of the column names to be lowercase so they're easier to work with, we then filter the data only work with the black victims, there are some white and Hispanic victims in here. Again, because this is commemoration of Juneteenth, I really want to focus on the black victims. This line 12, where we do the count on state and county is where we aggregated the number of victims again by state and county. So I'm going to go ahead and remove that. We then join together, because we had two letter abbreviations for the states to a full name for the state so that makes it easier to merge our database data for the lynchings to information from the map. We do that all here. And then we get to select function where we're looking at the state county and end well we no longer have an end. And also I want information about the victim right so let's go ahead and look at these lines. And we can see the types of data that we have from the database we have the information about the date, the name of the victim their race which we already use for filtering. We also have the victim sex the victims age. We've already used the county and state information. There's information here about the mob, the accusation. I'm not so interested in that I am interested in the method of death to report that out. And there's also lynch date. So I think we've got some good information here that we can modify our select statement with. And so I'll use name victims sex victims age method of death and lynch date. Again, we have the state county name sex age method of death and the lynch date. Looking at this data, I can already see that we're going to have to do some cleaning up of the data so that it works well. What I'd like to do again is each frame of the movie be that map, light up the county that the victim came from in red, and then have a little caption to say something about the victim. As you can see, we don't know a whole lot about the victim. So I want to put as much of this information in there as we can. But we start seeing things like, you know, we don't know everyone's age. I suspect we don't know everyone's method of death. You know, so here we have unreported as a method of death. Well, we could say they were lynched, right? We could say that, at least also looking at the date is an eight digit number rather than a date formatted column. And so we'll have to clean that up a little bit as well. But before we do all that, what I'd like to do is think about how we can then integrate this information into the figure. So I'll go ahead and reassign this back to a variable that I will call lynchings. And then wherever I had lynchings per state county, I need to replace that with lynchings. All right, to make sure I've got all my good stuff here. And I think that did it. And again, now I can run all these code chunks. And I can look at lynchings, map data, and see I've got the state county, the name, this their sex, their age, method of death, the date, and then the launch lat group and order for making the map. Okay, I think we're in good shape. What I don't have, though, is that end column for indicating the number of victims per state and county, right? So what I'm going to do for this lynchings map data, I'll go ahead and pull lynchings out from here, and then pipe that into this right join. And then I'll go ahead and add a mutate and do n equals one. And that will kind of be a pseudo count, right? So each lynching was a single, a single murder, right? And so we then have lynchings map data, that looks good. And then we can maybe clean up our code a little bit here. All right, and then let's go ahead and build the plot. We're getting an error, probably coming back up here from where I did my mutate. Again, we did this right join so that we have all the counties, even those where there wasn't a lynching. And those are represented as an NA. And because before N was an integer, because it was produced from the count function, when N was NA, so if that's true, then we needed to plug in zero as an integer. And so that's why we use the L. And so now N is a double. And so we're good with using zero as a double. Now we have our map. Again, every county where there was a lynching is lit in red. Good. The next thing I'd like to do is go ahead and build the animation. But before I build that animation, I don't want to build an animation with all 3200 victims because that's going to take a long time to render.  Maybe I'll only look at 10 random victims. And up here again, where I make that lynching's map data, I can do a slice sample and equals 10. And if I look at that, I then get 10 random individuals from the data set. And I can then pipe that into the rest of my join. And that reminds me, because I'm going to do this random sampling, I need to go ahead and set the seed. And so I will use 1865 06 19 as my seed. And that way, every time I rerun this, I'll get the same order of victim. I get my map with 10 counties lit up. Yep, there are 10 counties that I can quickly count. And so this will be good for again, testing our animation and testing everything else that we're working on to build the animation. The first thing that I want to do is call this static version of the animation static. And so that will create again, the static data frame, with that static variable holding the plot, we can then add on the animation information from gg animate. And so we can do static plus transition manual. And then we're going to index the plot or the movie over a variable. And for now, we're going to use name. Eventually, we'll come back and make a more attractive caption. And so I will then call this animation. And then we can do animate as a function on animation. And I'm going to give it this height and width, which again, comes from the aspect ratio for YouTube. And we will then do units equals inches, res equals 300. I will do FPS. So frames per second, I'll do one frame per second. So each victim will get one second. If that's too slow for some people or too fast for some people in YouTube, they can, they can modulate how fast the video goes. And then we end frames for the number of frames. And so I'll do then 10 frames. We'll then have to modify that later on. And then we need a render. And then we'll do magic render. And so that will produce a gif. And again, later, we'll change the render to produce an MP4. Again, I just, I just want to start, start simple, and we'll build up. And then we can do annum save. And we can then save this as Juneteenth map movie dot gif. And annum save will save the last plot that was generated as a gif. Before I generate the animation, I need to be sure to do library gg animate. And then we can go ahead and run these lines to build out our animation. That took a couple seconds to render. And we now have our gif here in Safari, as I'm looking at it, where we see each county being lit up in red. And so this is the startings of a really nice movie, I think. So I see in my output in the console that I am getting some warning messages, I'm not totally going to worry about those just yet, we'll come back and clean those up later. So I'd like to go ahead and start thinking about how we're going to build the caption. To do that, we're going to use a geom called geom text box, which comes to us from gg text. And so here I'm going to give it a different data frame that will be caption data. And I will then use an AES for the label to be you know, for now, it's going to be the caption. And so that that text box will have the caption in it. So we have to build up caption data as well as the caption. And then our x, we need to figure out where that is on the coordinate system, as well as the y position. And I'm sure we'll have to do other styling as well. So I'll go ahead and put a comment before that, just to kind of give us a sense of where we're going and what we need to develop. So again, we need to develop this caption data data frame. So I'll put that up here. And again, our lynchings map data, the state, the county, the name, the victims and so forth. Ultimately, I think we're going to have a column that takes a lot of this information about the name, sex, age, method of death and date, folds that together as a caption. So for now, what I'll do is I will take lynchings map data. And then I will do select on name. And I'm going to rename caption or name to be caption, right? And then I can assign this back to caption data. And so that if we look at caption data. So I'll go ahead and do distinct on caption. And so now if I look at caption data, I then get those 10 or 11 names. So this 11th, I think, is coming through because lynchings map data has NA values for the victims. And so that's, that's a problem, right? So let's go ahead and in here, I'm going to do a drop and a maybe after my distinct. So I will do drop NA on caption. And now if I look at caption data, I see I've got those 10 names. While I'm at it, I think what I'll do up here instead of worrying about this, this mutate line that I modified earlier is I'll do a drop NA on the end column. Again, that came through because we did a right join to get all the county information, even for counties where there wasn't a recorded victim. So what I'm going to do down here in static is for the time being, I'm going to turn off theme void. So I can see the x and y axis labels. And let's go ahead and look at static. So I can now see the latitude and longitude for my map. And I can use those values to position where I want to put that caption. So I have a couple of different options for where to put the caption. When I was initially thinking about this, I was thinking about putting it in the Gulf of Mexico, right? Because there's a lot of white space there that we could put in a caption. But then that means that you're looking at the bottom to find the name when there's all this action happening up in the map. I think what I'd rather do is perhaps put it up here, kind of where you'd expect to see like Missouri and Illinois and Indiana and Ohio, so that the name is at the top. And then you can see where they were from because I think the name is what's really important here. So I think we'll do that. So we'll go ahead and pick coordinates that are up here in the upper left quadrant of our map. So maybe what we'll do is like minus 95, and maybe 45 as our coordinates. So we'll do minus 95. And y will be 45. And we'll go ahead and bring that back on and let's see what this looks like. So we're getting an error that object group not found. And that's because my geome text box, I need to say inherit AES equals false. That's because the AES up here for the main plot has group, but I don't have group down here below. I'm going to go ahead and put the arguments for geome text box on separate lines, because I think we're going to do some more fiddling with the parameters here and it'd be easier than having them kind of running off the screen. So I'm not seeing it. I did pick 45, which is perhaps a little bit beyond the range of the y axis. So let's go ahead and do 40 in our geome text box. And so we can see part of a text box there. And I'm wondering if I have a problem with my justification. So what I'll do in here is I'll do hjust. So that's the horizontal justification. If I pick zero, that should be left justified and vjust, which is the vertical justification. So if I pick one, that should be at the top. So that then puts the name will hood right there at 40. When I try to go ahead and move it up a little bit, maybe I'll do 41. And let's move it over to the left a little bit. Let's do 95.5. So that placement looks pretty good. What I'd like to do is get rid of the bubble around the name. To do that back up here in geome text box, I'll go ahead and do fill equals na. And then box dot color equals na. And that should get rid of the surrounding border. So I see my county is still moving around with the gif. But my names aren't. And it occurs to me that when I did this transition manual, I did it on name. Whereas the column in caption data is caption not name. So let me go ahead and fix that and put that back to name. And then I think down here in my geome text box, I also use the label caption. All right, so let's go ahead and rerun all this. And I think it should work. This is working, right? We've got the name, we've got the county, each iteration, each step in the gif is a different victim being represented in the map, which is exactly what we wanted. One thing I'm noticing is that I lost my county borders. So before I go further, I'm going to come back and solve that problem. And the problem was that I did drop na on n. And that got rid of all my warning messages, you'll notice. But that also got rid of all those counties that weren't represented in the data, right? That didn't have a victim. So I need to go ahead and add that back. And what I'm going to do is I have county map and state map. And I think what I'll do is I will add a geome. So I've got this geome polygon for the victim, right? And that's getting filled in for each victim. And I'll add another geome polygon that will be much like this state map one, but will be county map. And I think what I'll do is this will be then size equals 0.1 for that state boundary. I think this should work. So I see my county boundaries there now on the static version. Great. And now I have my county lines for all the other counties. I don't know. Maybe you might think that all those county lines are a bit busy. I kind of think it helps provide structure within each of the state and make it more clear what's actually being lit up rather than these kind of odd shaped polygons in the middle of the state. So I kind of like leaving it in there. What I want to turn my attention to next is building a better caption that we can put on each slide of the video. What I'd like to include is the name of the victim, their sex, their age, and how they were killed as well as the date they were killed. I can imagine having their name. Let me go ahead and write this down up here under lynchings. So I want to have like name in bold. And then I want to have their sex and age, method of death, and then the date. Right. And so each caption will be like three lines to build out this caption. I need to make sure that the values for these different variables look right. And so I'll start with sex. And the process that I'm going to follow is very similar to what we did in the last episode when I tried to make the make sure the county names in the database match those in the files for building the map. And so what I'll do here is I'll do count on sex. And I'll also come back up here. And so I don't have to type lynchings over and over again. I'll put that on a separate line so that as I run this pipeline, it outputs to the screen what's going on. And that should be victim sex. And so I see I have female male and unknown. So right that unknown should probably be an A. So I'll go ahead in here and do a mutate on victim sex equals if else victim sex equals equals unknown.  Otherwise, I want it to be victim sex. Okay, and then we can pipe that into victim sex. And so now we see we got rid of that unknown that that became an NA. I think something else that I would like to do is go ahead and make that lowercase. So we'll do victim sex equals to lower victim sex, right? And so now we've got our sexes all in lowercase. So good. So we've cleaned up the sex, right? So I'll go ahead and do a count now on victims age. There's a lot in here. So I'm going to go ahead and pipe this to view. And we'll get that to pop up here in a nice table. And so I'm seeing things like less than space 20 less than 20, 10, 12 months, right? And I've got a range of date ages, right? These are the numbers. I see about 25 aged boy child elderly, right? I've got some funny numbers. I've got NA, right? Where we don't know old old man. So I'd like to go ahead and clean these up. Again, my process cleaning up the ages is going to be very much like what we did with the sex and what we did with the county. So for example, I could do mutate victims age. And then I will do STR replace. And so I'm going to be looking for patterns and then modifying those, right? So victims age. So perhaps the first modification I'll make is for those ages that had a less than sign. Notice some had a space after the less than and some didn't. So I can do a space question mark to match zero or one spaces. And then I can replace that with less than something. And perhaps then I need to put in here a match to the the number that the age right in parentheses. And so then I can do less than backpack one years old, go ahead and throw that into our pipeline. So now we no longer have that less than. And if we come down here, we should see less than 20 years old, right? And so that then got those three individuals. So I'll go ahead and do one more example with you before I kind of do some fast forwarding. And we'll do victims age. There's another string of place on victims age. And let's look at those ages where there was a range, right? And so there we could do in our capture parentheses, backpack D star hyphen, backpack D star, then close out our capture.  And so now we see that where we have the range of ages, we have 14 to 15 years old, 14 to 20 years old. So that looks good. Alright, so I'm going to keep going through this. I don't want to bore you with all the kind of the typos and all the working out the regular expressions. So I'll be right back. So I went through and I came up with maybe a dozen or so different string replace functions to clean up those ages a bit. And I think it's all fairly straightforward, nothing too controversial, I hope. There was some, there was like an aged category or old man or old. So I just kind of gave them some respect and said elderly, right? There was a young category. And so like boy child youth, I also made those young. For someone in their late 30s, I said they were 35 to 39 years old to again kind of give everything a more common format. There were some weird characters in some of the ages. And so I cleaned that up. One other thing I did was that if it said unknown for the victims age, I made that an NA. And so what this looks like then is that we come down to 113 different ages, so to speak. And you can kind of see what they look like here. And I think I'm pretty happy with how this all turned out. The next thing that I want to turn my attention to is the method of death. And we now look at that. And again, we see some funny characters in those names.  You know, some of these cases, there's a hyphen, I'd rather that to be a comma. Again, what I'm going for is to try to give everything a common appearance. You know, here it says hang, like that to be hanged, right? Hanged and shot strangulation, you know, let's maybe put a comma in there and make that just look a little bit nicer and more uniform across all the different victims. So the approach to cleaning this up is very similar to what we did with victim sex and victims age. So we'll do a mutate method of death equals str replace. And again, I'll do method of death. And then the pattern, you know, let's match a semicolon space, and I'm going to replace that with a comma space, right? And then I can pipe that into my count. And then I see that I no longer have semicolons in here. So there's like burned riddled with bullets. I'll perhaps want to fix that capitalization as well. But I no longer have that semicolon. Again, just trying to get something uniform, I can do something similar with those hyphens, right? So if I have space hyphen, I can make that comma space. And if there's no space around the hyphen, I can make that comma space. Again, I can keep turning through those. I'm not going to bore you. So I'm going to go ahead and fast forward. And I'll show you what I come up with in the end. Again, I went through and made a series of string replace function calls, as well as a case when statement. There were a variety of things that were NA, not reported unknown, unreported, unreproated. And so all those I made lynched again, this like kind of generic category, and cleaned up some of these other things as well. And when you look at kind of the categories that we got out in the end, I think they look pretty nice. One thing that I did in here was method of death str to sentence. What that did was if I had two capitalized letters in the same sentence, that makes it sentence format, you could also make it title format so that the first character of each word is capitalized string to sentence makes the first character of the string capitalized. Next, what I want to do is let's look at the name. So looking at the names, most of these look pretty good. Let's see. Yeah, there's like 3000 of these. So this will take a while. There's a couple of things that stood out to me when I was looking at this. And one of those is that there's some of these funny characters, right? So like Bill with this odd character. So I'm going to go ahead and clean that up. Again, much like we did before, mutate name equals str replace. And then we'll do that on name. And the pattern is going to be that funny character. And then replacing it with nothing. So I'll go ahead and copy and highlight that question mark, plop that into here, pipe that over. And let's see if we can find, well, now we have that we've got a reorganized list here. And I think these are the last names. So before perhaps it was a question mark stylized question mark for the first name and then the last name. And what I'm also noticing is that these are the last names in alphabetical order. And that there's a space actually before like woods before getting to bear. And so I think there was a space around that odd character. And so let's go back and go ahead and do another one of these replacements. And we'll do name. And then instead of that character, we'll look for things that start words that start with a space. Good. So we no longer see those space last names. We've got names that start with quotes nicknames no doubt, and then alphabetized by first name. So I'll go back through the list and see if there's anything else that catches my eye and I'll go ahead and fix those and come back and show you what I found. So there wasn't too much more that I had to go through and polish up. You'll see that I have two things that I've added, unnamed, and then following string or unknown and following string. This should actually be period star, right. And so in those cases, these have been like unnamed Negro, and perhaps unnamed Negro one of three or something like that. And so I figured I'd just name them as unnamed, right. And that way, that this name or tag that was given to the victim was given by the newspaper or by the researchers. And so I don't feel like I'm stripping them of their identity by saying that they're unnamed because that's already clear, right. So I think that looks good. I'll go ahead and remove that count and view and do another mutate to make the caption. And I'm going to use the glue function to pull this off. And so I need to make sure I load my library glue. And then for my caption, again, I kind of have the layout that I have down here in this comment. So I'll do glue. And then in double stars, I'll put the name. And that name needs to be in curly braces to insert that into the glue. And then I'll do a comma. And then I will do victims, sex, space victims, age, again, those both of those need to be in the curly braces. And then I'll do a line break to put a method of death. And the Lynch date. And so I'll put that on another line, right? So be our Lynch date. Again, that needs to be in curly braces. Now, one of the things I know is that we have NA values for victim sex and for victims age. And so I'm going to make some contingencies for cases where victim sex or victims age are NA's. So that's likely going to change.  And that will be all this stuff, right? The method of death and the Lynch date. And so that needs to be in glue, in parentheses, as well as in quotes. All right. And so then I can insert in here, the last lines, right? So this is like what we're going to have as a caption when we have all the data. I'm going to replace that though with a case when so if the victim sex is NA so is that NA victims sex. Then I'm going to take this. And what am I going to use? So I'm going to say, I'm going to remove victim sex, right? I'll put in the victims age, as well as the last lines. That's good. And then is that NA victims age. And then we'll do very much the same thing. But instead of victims age, we'll do victim sex last lines. And then because every case when should end with a true, and that will be case where we have everything, we have all the data, will then put in, again, what we thought of as like kind of the ideal situation. And so that closes that the case when for that parentheses. And I think we are good there. Looking at this, our caption falls off the end. So why don't I go ahead and for testing do a select. And I'll do state county and caption. And again, I see I've got the state county the caption that the person's name with the two stars. And again, when I put that into GM text box, that will rep, that'll recognize that as markdown and make that bold. And then I have mail hanged. Ah, and then I have my date and my date is not properly formatted. So let's go back and fix that. Why don't I instead of getting Lynch date, why don't we get the day month year, because that was already in, in the data frame in the database. So where did we get that? So back here, that was Lynch date. Let's do day month year. And I just want to make sure that it's all there. So we've got day month year. One thing I worry about, again, with all this data is whether or not we have sensible values. So I'm going to come back down here before I made the caption. And I'll go ahead and do a count on day. And I've got a zero for a day, right? So that's not that's not sensible. Let's actually let's look at all the values. And so we can do view right. And so we see we have zero through 31 and we have 129. So that's not right. All right, so we'll do a mutate on day and do an if else. And so if the day is less than one, or day greater than 31, then we're going to use na underscore on real. Otherwise we'll use day. Perhaps we might worry about months like February that only have 28 days showing up with 30 days or something like that. But I think we'll be okay. So let's look at make sure that works. And so again, we have one to 31 days and we have that na. So we're in good shape. Let's now count months. And we have zero 23. What's going on? All right. And so here again, we can add another mutate line. And so we'll do month. So if else day if month greater than 12, then we want to give an na otherwise we're going to use the month. So let's look at that. Great. So again, that all looks good. And then our years I think are in pretty good shape, although we could double check for sure it could do a count year. And again, 1877 to 1950, we're in good shape. Okay, so we have clean days and months. And we could probably also do day equals if else is that na on month, then we want to make day to be an na real. Otherwise, we'll use day, right? Okay. So that is good. Now what we want to do is format our date to be text base. And to do that, what I'll do will be date. And I will then use I want this to be month day year. And in the United States, these are American data. So we're going to use American notation. So I'll build this with glue. So to give us something to work with, I'll go ahead and do month day comma year. And I think that will look good. And let's go ahead and do a select on month, day, year, and date. And we see we have November 2nd, 1877, 11 to 1877. Good. Now what we can do is if I have, I can use the month function on 11. And that doesn't work because I haven't loaded liberate. So up here I need to do library, liberate. And so now if I do month 11, I get 11, right? If I do month 11, and I do label equals true, then I get NOV. And if I do ABB equals false, so abbreviation equals false, I'll get November. Okay. And then this is telling us that the month is a ordered factor, right? Because months fall in order. Okay. So again, coming down to where I was working with the dates. Again, for month, I'm going to use the month function around that, we'll do ABB equals false, label equals true. And then close parentheses, that looks good. Now, of course, we do have in our data cases where the month or the day is unknown. So I'm going to go ahead and do another case when so case when is not an a on month. I'm going to then borrow this and let me put this to another line so we get some more real estate. Let's see. And so if the month is unknown, then I'm only going to show the year. And then if the day is unknown, so if the month was unknown, then it'll kick out of the case when if the day is unknown, right, then we need to glue and borrow this, what we had down here, right, where we'll do month and then year. And I think I need an open quote here. And then if true, then I'm going to show my idealized date. And then we'll clean this up. And then we'll pipe this into everything else. And I think I'm missing a parentheses, so I'll add that. And then I've got my dates and those all look good. Okay, so coming back to where we were, we'll fold this into making our caption. And so instead of Lynch date, I'll put in date. And so that all looks good. And now if I look at the output here, again, I've got the state, the county, the caption, that includes the nicely formatted date. So I'm in good shape. Again, I can come back up now and assign this to lynchings and get everything else updated. And I'll need to think about my caption data frame. Again, I'm going through here looking for any warning or error messages. Everything looks good. Again, this is our lynchings map data. That's good. And I want to select the caption, right? So select caption, distinct, drop na, I can get rid of this rename line. And I believe I'll be able to double check my caption data. I think I only have 10 victims in here, we're in good shape. So we'll go ahead and build the static plot. So object name not found. So right here, right in my GM text box. So I want caption, which looks good. I'm noticing some funniness with my caption, being five lines instead of three. So let's look at what the animation looks like. So my animation, I need to cycle over caption rather than name. So that looks good. There was one individual I thought maybe wasn't showing up, but I think they're up here in a small county in Virginia. Yeah, right there. So this looks great. I'm really happy with the formatting here. One thing I do notice is that like there's a more lateral real estate to the right here. But when we get to like May there, it kind of put it down onto two lines. So what we can do in GM text box is actually make that a bit wider. So I can change the width of that text box up here in GM text box by doing width equals unit. And then I'll say three inches. And we'll we'll see how that works. And we'll go from there. So this looks pretty good. Again, I can't see the individual lines, but we don't have five lines. And I don't have anything kind of coming over here into Kentucky. So let's go ahead and look at the animation. So it looks pretty good. I noticed that the May line, it goes off to the right. And I think this looks pretty good. Yeah, there you go. So I'm trying to slowly build things up, right? Why don't we go up and let's do a hundred victims now and see if anything breaks. So we'll slice sample n equals 100. And then we will also then update our number of frames to 100. And let's give all this a run. So this looks pretty good. It did take a while to render for 100 kind of worry about what it's going to be for a few thousand. One thing I'm noticing here about the victim's names is that they're coming in alphabetical order. I'd kind of like to be in that random order. You know, normally when we alphabetize names, we're doing it by last name rather than first name. And I don't know, I kind of like the thought of having these be somewhat random. We could also do it by date. But let's let's go ahead. So now we're going to be an unnamed or there's going to be all these unnamed victims. And I really do think having them in a random order would be much better. So having all those unnames together at the end convinced me that we do want the names to be randomized. And so I'll come back up here to lynching map data. And what I will do is after my slice sample, I'll do mutate caption to be a factor of caption. And then levels caption, right? And so that way, the the factor captions, the order of those factors will be set by the random order that we got out of slice sample. And so we can then pipe that into all this. So I'm going to change how I render this. And I will use AV renderer. And I am going to plop in here, the name of the file. So I'm going to create with AV render an mp4 file. And so then I can comment out that anim save, and go ahead and animate this and then we'll have an mp4. So a video of the animation. So this is great. I'm really happy with the way this visual turned out. We now have a 100 second video for a hundred of the victims, each victim getting one second. It's really not enough. Again, if you're watching this on YouTube, you probably want to go and slow it down a little bit. Who knows, I think this is very effective. I hesitate to say that this is a data visualization. I guess we are showing data, right, like the counties, but really, we're using are to make a movie, which I think is is pretty cool. And again, I think this is a pretty effective way showing the lynching victims saying their name. And yeah, I hope people receive it well. So to get all of the victims, I'll come back up here, where I did my slice sample. And I will do prop equals one. And go ahead and run this and see if we have any problems. And it's complaining that we have a factor that is duplicated, which I find a little bit surprising. So I'll go ahead and do a count on my caption. And to kind of see how many, you know, everybody should be one because I would think they'd be unique, but maybe not. I'll do top n, n equals one on n. And so we see that unnamed male shot September 7. We've got seven of those. So using levels as our caption isn't going to work. So I think what we'll do instead is let's go ahead and do a mutate. And we will do order equals one to n row of the data frame coming through. And we can then do FCT, reorder, caption. And then we will do that on the order column and see if this works. So that seemed to go well. And now we can do our caption data or static. And then we can go ahead and run the rest of our pipeline here. I'm not going to build out that tiff because it's not it's not that interesting. The animation is there. And then n frames needs to be the number of rows that are in caption data, right. And so this will be n row caption data. And we can go ahead and build this out. This is going to take some time to render, I believe the video will probably be so be like 3200 seconds long, which I think will be about 50 minutes. It looks like it'll take 25 minutes or so here to render. I'm going to leave this. And you'll have to definitely check out that video. I'll post that at the same time as this across the top here, I'll put a link to that video. And I really encourage you to go check it out. I know this was a longer video than most of the other ones that I've been doing. But hopefully you can again see how I'm putting together all these different ideas to kind of fulfill a vision using R to make this movie. Ultimately, I hope that you agree that we've done justice to the victims by saying their name, giving as much information about them as we can. So while I'm grateful for you watching this video, I hope you also watch the companion video of the 3200 names kind of scrolling across the screen. I hope you let it wash over to you and really appreciate the effects of racial violence and this horrible plague of lynching in the United States. And of course, we can appreciate that not all of the victims are represented here, that there are no doubt many more black victims of lynching. As I mentioned, there were victims of lynching who are white, Hispanic, Native Americans. And we need to be aware of this, right? And so I'm sorry for this to be such a downer of an episode or series of episodes, but I think it's important to raise awareness and for us to really think about, you know, how can we use our skills that perhaps we developed for one one application like microbiology and can apply it to other things to do to do more good in the world. So again, I hope you watch the video. Let let it all wash over you and and just be more aware. Please, please, please be sure to share that video with as many of your friends and family as you can. If they want to watch this video, that'd be awesome too. But certainly that other video is what's really important. I'd really appreciate any feedback that you might be able to provide me on on this video that we've produced or any of the other visuals that we've been producing as part of this series on Juneteenth. I hope next year when we do something for Juneteenth that we pick a more positive story. And that should not be hard to do. But anyway, this this was something that was on my heart and something that I thought was really important to do. And I hope I hope you agree. And I hope you've gotten something out of this. And if not learning are then kind of learning about American history. So anyway, like I said, please tell your friends about this, please be sure that you subscribe so you know when we kind of get back to talking about microbiology. And we'll see you next time for another episode of Code Club.


Hello, my name is Dennis Vihill and I'm the corresponding author of the paper entitled Enhanced Algal Gross Rate in a Taylor Vortex Reactor, which is co-authored by Bocong and Jacqueline Shanks. In this paper, we explore the effects of using a highly organized fluid flow pattern to culture microalgae. More specifically, we carried out experiments to determine the effects of this flow pattern on biomass productivity and light utilization efficiency by using Clorella vulgaris. We found that the presence of Taylor vortices causes significant increases in biomass productivity and that these increases are caused by the flashing light effect rather than by mass transport effects. The flashing light effect is a well-known and important phenomenon impacting the behavior of phototrophic microorganisms. In the simplest of terms, photosynthesis consists of a series of almost instantaneous photic reactions followed by thermochemical reactions that occur on the order of milliseconds. This large separation of timescales between the photic and thermochemical reactions means that the photosynthetic turnover time is controlled by the thermochemical timescale. As a result, in optically dense algal cultures, light utilization efficiency can be improved by periodically exposing microorganisms to a quick burst of radiation and then shuttling them to darker regions of the culture suspension while the thermochemical reactions are proceeding, before once again exposing them to light. Taylor vortex flow would seem to provide an efficient mechanism for producing the flashing light effect in a photobioreactor. In the annual region between two concentric cylinders was one or both cylinders undergoing rotation on its main axis. In our experiment, we used a fixed outer cylinder and rotating inner cylinder. At low rotation rates, the fluid has a single velocity component and undergoes simple circular motion. However, above a critical cylinder rotation speed, a centrifugal instability causes the fluid to self-organize into toroidal flow structures known as Taylor vortices as depicted in this figure. As you can see, the Taylor vortices caused the fluid to move not only in a circular motion around the main axis of the cylinders, but also in a circular motion between the inner and outer cylinders, thereby providing a highly effective mechanism for inducing the flashing light effect by efficiently transporting microorganisms between a brightly lit transparent outer cylinder and darker reactor volume near the inner cylinder. As the inner cylinder rotation rate increases, so does the rate at which fluid is transported between the inner and outer cylinder. Although the idea for using Taylor vortex flow to culture algae has been around for a long time, in fact, it dates back to a paper by Miller and co-workers in 1964, it is only now that it has been demonstrated that the rate of biomass production can be enhanced by using Taylor vortex flow. In this figure, we plot biomass concentration as a function of time for different cylinder rotation speeds. The black curve is data obtained without rotation of the inner cylinder and therefore represents results for an annular bubble column. The other growth curves correspond to increasing inner cylinder speeds as we move from blue to green to red. In all of these cases, the cylinder speed is sufficiently large so that Taylor vortices are present. Clearly, there is a significant enhancement of algal biomass production in the presence of Taylor vortices, and this effect is more pronounced as the inner cylinder speed increases. We discuss in more detail these and other results and we hope that you will read our paper. Thanks for listening.