Resources

Kaija Gahm | greenT (Shiny Contest) | RStudio

video
Jul 27, 2021
19:37

image: thumbnail.jpg

Transcript#

This transcript was generated automatically and may contain errors.

I'm going to be talking about my Shiny app that I created for the 2021 RStudio Shiny Contest, and I received an honorable mention, which was really exciting. This was basically just a side project that I started to get a little bit more experience in Shiny, and also to explore a phenomenon that is special to me, and I'll tell you about that in a moment. So my name is Kaya Gahm, and the title of my presentation is Brewing Green Tea, because the app is called Green Tea, and you'll see why in a moment.

So just a little bit about my background. I have a bachelor's in ecology from Yale, where I studied tadpoles, and this fall I'm going to be starting a PhD at UCLA, also in ecology and evolutionary biology, studying vultures. So I don't really come from a computer science background, but I learned to use R in order to analyze ecological data. So I've been using it for about six years now, and it's pretty much part of my daily routine at this point, but I don't come from the sort of front-end web development user-facing side of things really at all. So Shiny was pretty new to me this year.

For the past year or so, I've been working with the Cary Institute of Ecosystem Studies as a data manager, and doing a lot of data science basically every day, and I had a little bit of spare time this year in between undergrad and grad school, so I decided to create a Shiny app to explore synesthesia.

What is grapheme-color synesthesia?

So for anyone who isn't sure what this is, synesthesia is a neurological phenomenon where, well there are many different types of synesthesia, but there's a particular type called grapheme color synesthesia, and in this case people associate letters or numbers or other sort of graphemes, like characters, with colors in their minds. And that doesn't mean, and I have this type of synesthesia, that doesn't mean that I actually see colors when I see these letters, but I sort of imagine associations between colors and letters.

So I'm showing you a few letters of the alphabet here. A is very strongly red for me, B is blue, C is yellow, D is also blue, but a very distinct shade of blue from B, so you get the idea.

And I have had synesthesia as long as I can remember, and these associations have remained constant since I was a kid, and it's just kind of a fun little party trick. It's not, it doesn't really affect my daily life very much, but when I tell my friends about my synesthesia, they always want to see my alphabet, they always want to know what color their name is, they want me to show them words typed out the way I imagine them in my mind's eye. And this is actually not trivially easy to do because you have to change the color of every single letter. So for a while I had a Google doc going where I could copy and paste individual letters to show people what different words would look like, but that was really clunky and annoying.

So then I started Googling to see if there was a tool online that would allow me to show people my synesthesia, and I came across this project by Bernadette Sheridan, where she is also a synesthete, and she created a tool where you can type in any word, in this case I've entered my name, and you see what it looks like in her synesthesia colors. And that's really cool, but it's problematic for me because this looks really wrong to me, these are the wrong colors. Actually several of them happen to line up with mine, but for example K is not yellow-green in my head, it's more of a magenta, and so this bothers me and there was no way to put in my own colors.

So I envisioned an app like this where I would have one color drop-down selector for every single letter of the alphabet and every number, and I'd be able to set my own colors and have other people set theirs, and then type in my name and have it appear in my colors so it actually looks right to me, or type in any other word, and so other synesthetes could enter their own colors as well. So I decided to build it in Shiny.

Demo of the greenT app

Okay, so I built the app, and I called it Green Tea because I wanted some sort of cute little pun, and the letter T is green for me. It initializes with a bunch of random colors, but you can set them to my colors, so now everything looks very satisfying to me because all the letters are the correct colors, and you see this green T here, or you can set them all to white and you can pick your own colors if that is what you want to do, if you have synesthesia yourself, or if you just want to create a palette. You can download the colors as a CSV that downloads their hex codes and their RGB codes as well, and then you can type anything you want here.

I have it set to type something. I could type my name. You can see there's a slight delay, and I'll talk about that in a minute. I could type, hi Boston, and it shows up in my colors, or it shows up in whatever colors you would like to use. You can turn the letters on and off. You can download the rectangles as a PNG, so those are the images that showed up on my first slide were just downloaded from my app, and then I also added some other features. I added an app where, I'm sorry, a page where you can read more about synesthesia and more about why I developed this app, and I also have a Google survey mimic page here where you can enter your own information optionally, because I was thinking maybe I would do some informal analyses of synesthetes and see if I could figure out any patterns, and you can actually submit your own colors, so this listens to what has been selected on this page and actually contributes it to me as a CSV along with your survey responses.

Technical challenges and features

So that's just a basic overview of the app itself, but I wanted to talk in particular about a couple things that came up while developing this Shiny app that were really fun for me. So I had a little bit of prior experience developing a Shiny app. I actually developed one this year for work, and it was much more complex than this app and took me a long time. A lot of sort of focused effort all day every day. So by comparison, this app was kind of a breeze. I had a prototype mocked up in just a couple hours, but then I kept going and adding features and thinking to myself, you know, wouldn't it be cool if it could do this thing? Wouldn't it be cool if it could do this thing? And I was surprised at how much I could achieve, and so just to call attention to a couple features here that are a little bit more complicated than they seem.

So first let's look at these rectangles. This, although it might not look like it, is actually a ggplot. It looks like just plain rectangles, but it's actually a ggplot with theme void and geom rect, if anyone's familiar with ggplot. And behind the scenes, Shiny is listening to the inputs, the color inputs here, and creating a reactive expression, which is then fed into the ggplot, and it remakes the plot every time that there's a change to one of these colors or a change to one of these letters.

So one challenge that I faced with creating this plot is anyone who has used Shiny before might know that the default with Shiny is that reactive expressions all listen to each other all the time. So whenever one of them updates, anything that is listening to that reactive expression will automatically update pretty much instantaneously. And the challenge actually comes in preventing that from happening instantaneously or delaying things.

So I was having a problem where every single time I tried to type text, for example, if I typed my name, it would refresh five times. So you saw that just when I typed that, it basically flashed once. It showed you the new graph with my name. But before I fixed this, every time I typed a letter, the K, the A, the I, the J, the A, it would do what you just saw, except much faster, and it looked really chaotic because it was refreshing every single time there was a change. So I had to work in a delay where I used the debounce function to only have Shiny listen to that reactive expression every fraction of a second so that a reasonable person could type something relatively quickly and not have the refresh happen on every single letter.

And I want to emphasize that this app absolutely could have existed and could have been functional without that feature. But tweaking little things like that to improve the user experience was part of what I really enjoyed about the opportunity to develop this app.

And I want to emphasize that this app absolutely could have existed and could have been functional without that feature. But tweaking little things like that to improve the user experience was part of what I really enjoyed about the opportunity to develop this app.

Another thing that I would draw your attention to is this toggle for showing and hiding the letters. And this turned out to be a pretty simple on off switch where this switch is set to either true or false depending on whether it's clicked. And the reactive expression that generates the ggplot listens to that and replots the plot either with or without a geom text layer depending on the position of this switch. And this was another feature where I had sort of dreamed about it. Wouldn't it be cool? Maybe some people prefer it with letters, some people prefer it without letters. And I never thought that it would end up being this simple to actually execute. So I was really happy to be able to get this to work.

One other portion of the app that I want to talk about is these color selectors. There are, of course, 36 of them because there's 26 for each letter and then there's 10 for the digits. And 36 is a really interesting number because it's few enough that I could type every single one manually to create the selectors. I could have 36 lines of code where I create the A, create the B, create the C, create the D. And that's how I started the app because I just wanted to get it mocked up really quickly. I could copy and paste. No big deal. But 36 is also a large enough number that doing something 36 times starts to be annoying after a while.

And so this was a great opportunity for me to incrementally develop my app to move toward better practices in Shiny app development. So I started with a lot of repeated lines of code. And gradually, gradually, I streamlined everything, made it slightly more efficient until ultimately I ended up at a structure where I wrote a function that would generate each of these color selectors and then I applied that function 36 times, feeding in the input IDs and the display text and the starting colors each time. And that was, again, really satisfying. And this app, once again, could have existed, could have been functional without that sort of behind the scenes improvement, but it was very satisfying to be able to sort of streamline all of that.

Lessons learned

So those are just a few of the features in this app. I could go on. I wrote a blog post highlighting a couple of the challenges like that that were sort of fun to tackle that made the app what it is today. And I'm going to provide a link to that blog post if anybody's interested in seeing my code or interested in reading about the other stuff. But I wanted to just take a moment to reflect on some general lessons that I took away from this app for developing Shiny apps in general.

And the first thing, which I've alluded to during this talk, is to start simple and then build up and really don't be afraid to dream about what you'd like to see in the app and then try to make it happen. This definitely might not be true for everybody, but at least for me, I'm very much a person who learns best when I have a defined goal and a problem to solve and then I have to figure out how to do it. So I did watch some Shiny tutorials when I was first starting out, but I didn't just sit down with a textbook and try to teach myself Shiny in a vacuum. I taught myself the bare bones. I made a bare bones app and then I thought to myself, you know, what would I like to see and how can I make it happen with really no regard to whether the feature I was trying to develop was appropriate for beginners or whether it was, you know, something I should be working on? Just is it something I want to work on and can I read enough help docs and get enough help from my peers and whatnot and just figure out how to make it happen? And that was extremely rewarding and that's really how I got to have this app where it is today. And it's a surprisingly successful process, at least for me, is to just go intramentally like that.

And the second tip that I have for people is it was very useful for me to debug via video chat with willing friends or collaborators. In my case, it was people I met on the R for Data Science Slack channel. So I reached out to a couple people who were working on their own Shiny apps and had them sort of at a stage of development. And we set up some video chat calls where I helped the person debug their app and then they helped me debug my app. And it was really refreshing and really helpful to be able to show people in real time what was going wrong and to be able to help them in real time with their problems. And that was that helped me a lot and I got some great ideas by talking to other people. So if you have the opportunity to set up a collaboration like that, I think that can be a great way to learn Shiny.

So I'll stop now because I know we don't have a lot of time, but I would welcome any questions and I will share some more resources in my slides at the end. Thank you.

Q&A

Kaya, something that I was curious about is for like the actual, like when you first made this application, did you use some sort of template or you just started from the beginning like Shiny app example? No, I started from the beginning and it looked really ugly. I knew I wanted the selectors sort of in a section and I knew that I wanted to get them into some sort of grid. And I think I used some combination of fluid row, fluid page, columns, rows. I think initially I just had them all in one column and of course it looked really stupid and it was really, really long, but you know, it worked and I could see that that was functional. And then I gradually tweaked the UI. I figured I, it was sort of this interesting tug of war between not wanting to focus too much on UI design from the beginning, but also it's just hard to look at something that looks really bad. And I wanted to have everything sort of, you know, compact enough that I could reasonably work on developing it.

James, I see you had a question in the chat. Do you want to ask it live?

Sure. Yeah, that, that I found the time delay feature you included kind of interesting. Could you expand on that a little bit? I didn't, I missed the package you used.

Yeah. This was a fun one because I, so I've, in the past I've written apps where there's like a submit button or something where I think the, the reactive inputs respond only when a button is clicked or something like that. So I was thinking about doing that, but I actually wanted this one to be more responsive in real time and to have a little bit less user input. So I was trying and trying to figure this out. And I had, I was talking to somebody on R for Data Science about this whole approach that I had mapped out that involved some reactive values and some, I don't even remember what was behind the scenes. And he said, Oh, do you know about the debounce function? And I was like, no, I don't know about the debounce function. So the debounce function is, I'm actually, is it a native Shiny function? I'm checking right now. Yeah. So it's just a function right in Shiny and it throttles the code in the background on the server a little bit. And you can specify how much to slow it down. So in my case, I just had a reactive expression that was the data frame that was going to get passed into the ggplot. And I just piped that data frame into the debounce function and specified, I think it was 25 milliseconds or something like that. And that just means that instead of checking for updates to the reactive expression as fast as Shiny possibly can, it will only check every 25, whatever, every, I don't know exactly the details, but it checks only every so often. And I just basically played around with that until it updated still fast enough that it seemed like it was responding to the user input, but slow enough that it wouldn't have to flash every single time you entered a letter.

Yeah. So debounce is the function. And so that was a function of how quickly someone was typing the letters in?

Yeah. So because each, the, the object in, hang on, I'll share again. So this text to display right here, this was an input, a text input. And so every time this text input changed, I took that text input, I transformed it into a data frame that then got fed into the ggplot. And so every time that data frame was updated, the plot would refresh. And so anytime that somebody was typing, you know, this is a different entry, this is a different entry, et cetera. Yeah. And you can see when I type really slowly, it does update every single time, but it takes just a little while. And if I write something really long, it'll show it all at once like this, because I type relatively fast, whereas before it was this horrible chaos of flashing colors until you finally got to the end. And so that's kind of the way that it works.

Thank you. I see you, there was one other question from Robert Klein. Do you want to ask that one live as well?

Or I can read it too. Robert asked earlier, can you read from the colors on their own?

Hmm. Not really, because there are a bunch that are similar. I have a lot of greens and browns, but I can't, especially with the numbers, because the numbers are all really distinct. There aren't any that are similar at all. And so that's very useful for memorizing, like bank account numbers or credit card numbers or, you know, pins, for example. I have a couple pins that, you know, I would never remember the sequence of numbers, but it's some logical, it like goes well together. And so I remember it. So if you really pressed me, I could probably figure stuff out, but it would be a lot harder with the alphabet than with the numbers.

Awesome. Thank you so much, Kaia. That was great. And if anyone else is interested, maybe in the future, I know they have the Shiny contest every year, and I'll put the blog post where I learned about Kaia's app in the chat, too. But thank you so much for the presentation. That was great.

Thank you for having me. If there are any other questions, too, feel free to put them in the chat as well and maybe put Kaia's name on them, and then we could save them for the end, too. But I'd love to turn it over to our second presenter.