 Yeah, so our next speaker is Gautam. So we'll be talking about, it has a journey to generate you, and we can work with Matt luckily. So what do you Gautam know? Great, thank you, Gayan, and thank you to all of the volunteers for putting this conference on. I caught a little bit of the last talk. It sounded absolutely fascinating and reminded me that I need to work on the documentation for this project. But I'm happy to talk to you today about a haphazard journey I've taken to a generative art Twitter bot using Mattplotlib. It's work that's been sort of two years in the making and still somewhat a work in progress, but this animation that you see on the screen is an example of one of the pieces that the Twitter bot has created. So a little bit about myself. My name's Gautam Cisodia. I live and work in New York City. I'm a six-year-old data scientist and a two-and-a-half-year-old parent, and the parent part is relevant as you'll see in a couple of slides. I work for the state of New York, but all of the work that I'll show here was done purely in a personal capacity. An outline of talk, so I'll start with what it is I'm talking about, move on to why I created these things and then a bit about how I did so, the up-and-down journey to getting to where I am, some examples of the pieces that the bot has created and a bit about the code. Okay, so first of all, what am I talking about? A bit of some background terminology. So when I say tiling, I mean a collection of shapes which I call tiles that fit together with no gaps and no overlaps, so this picture here is an example of that. I'm gonna be completely focused on the tidings that are made up of square and equilateral triangle tiles and the ones that are symmetric. And by symmetric, I mean in the center, there's either gonna be a single tile square or triangle or six triangles together as a hexagon, which is here, and then all of the tiles around it are symmetric around that center tile. So what is it that I've built here? So one is a Python library to make and draw these tidings. Here's an example of the code to actually build one of these things. You specify a tiling sequence and I'll talk more about what that is. And then there's a function for adding tidings and it spits out things like animations of that tiling being built. And then a Twitter bot that posts an animation of such a tiling daily. So here's an example from August 11th of this year. So that's what it is onto why so as I mentioned, I'm a two and a half year old parent first couple of years of childcare I found where often it was a mix of both being trying to be very alert because I was always afraid that my kid was gonna hurt himself somehow, but then also somewhat being bored because he wasn't doing too much. He was sort of exploring the world around him, the toys and the books, but in practicality that meant that he was sort of picking up a toy and throwing it against the wall and then picking up another toy. You're asking me to read the same book over and over and over and over again. So in that strange mix of feelings that became fascinated by this, this toy that he has which is a set of these plastic shapes that are magnetic on the edges. And so they fit together and you can make all sorts of really interesting things with it. It became fascinated by just how many different ways that we're of putting, or actually it was like one way that I kept going back to, to putting these squares and these triangles together to make a tiling. And it wasn't obvious to me that there should be any way to put squares and triangles together to make a tiling. I understood you can put all squares together and make a grid and you can do a similar thing with all triangles, but the fact that you can have like both of them together and to fit together and no gaps and overlaps and to cover a large space that was really fascinating to me. And it may be wondered just how many different ways are there to tile with squares and triangles. And around the same time, I stumbled across Twitter accounts slash bots that created this generative art. This is one of my favorite accounts, it's not a bot. As far as I know, it seems like a real person who creates these generative art pieces. And by generative art, I mean any sort of visual graphical thing that's created by code. Okay, so some points about how. So my first attempt, so I have got this question. How many different ways are there of tiling with squares and triangles? My first attempt, I was thinking about it, okay, I'm gonna try and code something up in Python. Do you try and answer this? Maybe come up with all the different ways of tiling with squares and triangles. My first attempt, I turned Shapely, which is a Python library open source for geometric manipulations. It's an incredible library. You can do things like define really complicated shapes. You can put shapes together and union them to create new shapes. You can take the intersection of two shapes, so the shape that's sort of the shared area. And you can do things like how can I area and calculate the edge of a shape. There's quite a lot that you can do with this library and it seems like something that should work here. So given the tiling, it tells me what the edges are. I pick an edge, I add a new tile, so on and so forth. And that worked up to a point. So on the left is an example of a tiling that I used creating this sort of heavily relying on Shapely. On the right is, well, the green is sort of the interior of the shape as Shapely understands it to be and the black line is the edge of the full tiling as Shapely understands it to be. And you may notice that these triangle tiles are actually Shapely believes they're separated from the tiling, which is indicated by this black line here. And this really throws off my algorithm because now it thinks that, hey, there's an edge here to the tiling. I can try and add a shape here or it tries to add a shape and now it overlaps with the shape that's already there. You can understand that. This can throw off a naive algorithm like the one I wrote. I don't know exactly why that's happening. I believe it's because when Shapely is making its calculations for where the edge is or when it adds a new tile to its tiling, it's making floating point calculations, which have slight errors that sort of add up as the tiling gets larger and eventually lead to situations where it adds a tile but not quite exactly where the shape is and then that throws off my algorithm. I tried a few different things to try to address this. Nothing really worked and became pretty frustrated and put this aside for months. But I kept thinking about it a few months later. I had this idea. Maybe Shapely wasn't the right tool for the job here. Shapely is generally used, well, it's often used for mapping. It's used to define more complicated shapes like the boundaries of countries and to do intersections and unions of those pretty complicated shapes. That's not really the situation I'm in here. It's not complicated in that same kind of way. Triangles can only be adjacent to, and by adjacent I mean two tiles that are attached that share an edge. Triangle can only be adjacent to three other tiles. A square tile can only be adjacent to four other tiles and there's very specific ways in which they can be adjacent. It got me thinking of an approach that was perhaps more discrete than Shapely. The idea is something like think of each tile as a vertex in a graph and the adjacent tiles. Two vertices are connected by an edge if they're adjacent. The animation on the left shows a picture of what that would look like. Each tile is a vertex, one of these purple dots and then the pink line connects two tiles that are adjacent to each other. The thinking is, well, if I can define what these discrete graphs could possibly be, then maybe I can take a graph and then from the graph actually draw the tiling. Then it became a matter of understanding, well, what are all of the constraints on such a graph? One would be, if you've got a square tile, it can only connect to four other tiles, which is what this diagram here represents. Just to know about what the vertices here, the way I'm calling them, there's a letter S or T, which means square or triangle, which indicates the different tiles. This is an okay situation. Similarly for a triangle connected to three other tiles, that's an okay situation. This, however, is not okay. Here I've got one square that's connected to four other squares. That's fine, but those four other squares are connected to another tile and that's not possible. There are situations like this which I just couldn't wrap my head around. What is a nice, clean way to denote that there are these constraints on the graph? I couldn't think of ways to do that and got frustrated again, put it aside, thought that maybe I was a data scientist because I wasn't good enough at the math or the computer science. I left it for a few months and then came back to it with another idea. I thought maybe I could do some sort of combination of approaches, the discrete and the continuous. The idea is that to define a tile, what the tile is, how to exactly draw it. I'm only using squares and triangles. You need to know where the center is. You need to know what kind of tile it is, a square or a triangle. You need to know where one of the vertices is of the points on the edge of the tile. That's enough to define how to exactly draw that tile. For two adjacent tiles, the centers of the tiles can only be in very specific configurations. If you know if you have a square, then if it's adjacent to another square or another triangle, the centers are exact distances apart and same with two triangles. Given a square, you can figure out where all of the possible centers are of all the possible adjacent tiles. Given a tile or a tiling, all the possible adjacent tiles, I call those child tiles. The approach is something like, you start with a tile, where its center is in the edges. It's what you use to define the tile. You can figure out all the possible child tiles by calculating where all of the possible centers are for the adjacent tiles. You pick a tile, you add it to the tiling, and you continue in that approach. I think of this as a hybrid approach between the continuous and the discrete. It's not purely discrete, because it's not just thinking about the graph. I'm actually calculating geometric things, distances between centers, but it's not a purely continuous thing, because I'm only using the center and the edge, those two points, and what type of tile it is to draw the tile. The animation is something like some depiction of that approach. Here's an example, again, of how you can use this library to create the tiling. One of the interesting things that happens here, is that there are configurations where you can't actually continue the tiling. Here's an example of that. If you've got this configuration of four tiles here, these three squares, and then a triangle, and then a square, this area here, there's actually no way to fill that in with no gaps and overlaps, with just squares and triangles. If we just take this part here, these four squares, to fill this part in, you need a square, but to fill this part in with this triangle and two squares, you need two triangles. There's no way to fill that in, so the algorithm gets stuck at something like this. The algorithm is recursive, so if it does get stuck, it'll go back to a previous step and try and add a different tile to get past this block. In practice, that can actually take a long time. What the algorithm does, and now it's slight modification, is that it actually looks forward a little bit and makes sure that if there's a prospective tile that it wants to add to the sequence, for all of the edges of that tile, is there a potential tile that will fit in the tiling? It does a bit of a look ahead, but this situation here, you can actually extend sort of as arbitrarily long as you want. If you just keep adding squares here and then one square down like that, that's also a configuration that will be stuck. You can't fill that area in with just squares and triangles. This is just one example of a situation which you can actually extend to be arbitrarily long. Some examples of the Twitter bot in action, this was the animation for August 9th. The way the Twitter bot works is it uses this library to create an animation post it to Twitter, and it does it once a day roughly. This is an example of where it got stuck. The animation is showing the tiling being built in sequence, sort of the algorithm in action, and you'll notice that here it gets stuck and then it's trying different tiles to see what works. You can perhaps notice from this that it's actually going to take a little while to figure it out. This is an example of the most squares. This was on July 16th. As I mentioned, you can actually tile with just squares and just triangles. It's never so far down just squares or just triangles. This is the time where it got closest to most squares and this is the time it got closest to all triangles on May 20th of this year, which got me interested. I look for the most balanced one, balanced in terms of a close to equal number of squares and triangles. What's interesting about this though is that it actually looks visually that there's more squares, but I think that's because squares are actually larger in area than triangles. I wonder if I should actually look for more balanced in terms of area, not number of tiles. This was on May 17th. I also got me wondering, I was actually thinking about what are sort of the most visually attractive tilings or appealing. This is interesting, but it's not really visually appealing to me. I couldn't really put my hands on what it really means in a practical sense or in a very concrete sense, what it means to be visually appealing. Maybe I can use the Twitter stats somehow. Take a look at which of the tweets were most favorited or retweeted, maybe that'll give a sense of what people think is the most visually attractive or appealing. Some stats. When did it go viral? From April 24th to August 26th this year, there's been 141 tweets, there's been zero retweets, and only one was favorited, and that was by a friend who was amused by the example where it was almost all squares. Has not gone viral yet, maybe one of these days it will, but the easiest data science questions are the ones where there's no data at all. Just a little bit about the code. The way the code is set up is there's different levels of abstraction at the lowest level is a point. I actually sort of define a point just from the very basics from the coordinates. There are, of course, many libraries, including Shapely that define points that I could have used, but sometimes it's fun to define things from the ground up by yourself. So there's a couple of different kinds of points here. There's a Cartesian way of defining the point x and y coordinates. You can calculate the distance to some other point. You can convert it to polar, which is useful when you're doing things like rotating a point around to find all of the vertex points of a tile. It has a Shapely geometry point, a representation that you can access. You can work with Shapely. The next level up is a tile, and you can define a tile based on the center and the vertex points, as I mentioned. It's got a list of child tiles. This is for this example. This is the first child tile in the list. It's got a polygon representation. That's a Shapely geometry polygon, so you can work with Shapely with these tiles. The next level up is a tiling. This is essentially just a sequence of tiles. In this example, I take the tile example I had before, plus the first child tile of that and the first child tile of that, as my list of tiles here, and then you can do things like plot it. It's got functions that you try to figure out if you have some other tile in the tiling. Is it compatible with the tiling? Are there no gaps and overlaps if you were to add it to the tiling? Things like that. The highest level up is a sequence of tiles. I've shown you this example before of what the code looks like. This is the tiling sequence. It also has the code for tweeting out the animation. I note on some of the libraries used, so all open source mapplotlib used for plotting. Hopefully, your mapplotlib is maybe the most standard library used for data visualization. Hopefully, this gives you a sense of a way that you can use mapplotlib that's out of that normal use case. Shapely for defining shapes. As I mentioned, Descartes is a library for plotting shapely objects in mapplotlib. NumPy for the numerical calculations. Tweepy is the library I use for tweeting, which requires a Twitter API key. And Google Cloud Storage, a Python library for interacting with Google Cloud. I use Google Cloud just to store the tweets and the metadata that the bots created. That requires a Google Cloud key to use. All of these are open source and heavily relied upon. Just a quick note about hardware requirements. The daily pipeline takes about three minutes on GitLab shared runners. And these are computers with 3.75 gigabytes of RAM. And the pipeline does a few things. It clones the repo, installs a package, makes a tiling, runs the algorithm for 70 steps or so, makes an animation post that saves it to Google Cloud Storage. So it's doing quite a few things. Just to give you a sense of how long it actually takes. And the generated animations are about two megabytes in size. So not particularly expensive. Okay. Thank you. So yeah, I think, you know, one of my takeaways here is that Python is a pretty incredible tool for just answering questions that just come from my curiosity. So the original question was how many tiles are there? How many tidings are there? I haven't answered that question yet. I know that there's a whole subject in math around tidings, but I never bothered to pick up a textbook. I just thought it would be more fun to code it. But what the Twitter bot, I think, has shown is that there are many, many more ways of tiling with squares and triangles than I imagined. So thank you again for the volunteers, and thank you all for listening to the talk. I'm happy to take any questions.