 In this last section, I want to walk through some of the advanced visualization stuff that's built into Rapture, because at this point you can build a pretty functional tool, but we haven't really done much with the output. We've looked at curves, we've looked at histograms, there's a lot more that you can do on the output side. Suppose that your program produces a molecule, you simulate and part of the thing that it generates is a molecule, maybe you're doing molecular dynamics calculations, there's a way to do that in Rapture, there's an element called structure, and again this isn't built into the builder yet, so I'm again showing you advanced stuff that you can't just drag and drop really easily. But if you can create XML in the output section that looks like this, then you can get a molecule in Rapture, either as an input or as an output, usually I guess it could be either in this case. So all you need to do is make the right XML, you start with something that's like a structure and it has a current and components and then molecule and then inside there basically atoms that have a symbol and an XYZ coordinate, another atom with a symbol and an XYZ coordinate and so forth. So if you can generate that XML in your program, you've got a molecule and Rapture automatically knows how to draw molecules, it automatically connects to a rendering server, talks to a program called PyMol written in Python that does molecular visualization and it'll take your molecule and render it in 3D. There's another way too, after we created that a lot of people said there's this PDB, protein data bank format, I don't know if you guys know anything about that but it's a real popular file format. There's a protein data bank site where you can download all of these molecules. If you want the molecular configuration of aspirin, you can find it in the protein data bank along with lots of other things. And there's a PDB file format and a lot of people said, well, I don't want to have to convert from PDB into Rapture. So we made a way that you can say structure, current, components, molecule, and then you can just say PDB and inside the PDB section, you can put something from the protein data bank in there and Rapture knows how to plot that too. So if you get something from the protein data bank, shove it in there, boom, you've got a molecule. So how do you do that? In your program, and now again we're, this is what your run.xml file would look like if you're successful and this is how you actually generate it. And suppose we have a Fortran program, I'm assuming Fortran. We've seen these calls already, the builder does this. The builder adds calls for like RPlib put string and all that. There's an RPlib put file command that you can use. And you pass in, as the first argument, the thing that Rapture loads at the beginning. Could be called driver, could be called IO. It's the thing in your program. If we look at an example program, you guys are looking perplexed at me. I think it's the end of the day. So let me show you my example program. So in my Fortran program, if I look at what Rapture generated, the in my example program, it was called IO in this program. See, just like the builder says RPlib put string and it automatically generated this text IO, and then you put in a path. And then you put in what you want to save at that path. The same kind of thing here. And it's called IO because somewhere near the top of your file, see this is RPlib command here that generates that name IO. All right. So if you wanted to do a molecule right here in your program in the output section, we could add like an RPlib put file command. And we could add in a path output dot. Let me stop the example at this point and flip back to my slides. Okay, so in that Fortran program, this is what I would have typed. Call RPlib put file, that same name IO, output dot mall dot current components molecule dot PDB. Again, that's the way I reference things. It's in the output section. I'm creating this structure called mall. In the current section, under components, under molecule, I want to tag PDB and I want to put all my data there. The RPlib put file looks for a file, in this case called data dot PDB. It reads the contents of that file and stuffs it in, in your output. So if your program generates a file called data dot PDB, here's how you can take that file and suck it in to your Rapture program. And Rapture will read that file and stuff it in right where the PDB tag is. So if I looked at that file on disk, I'd see all that atom 1C, blah, blah, blah, all that atom stuff that you see up there. That's what's in my file. My program generated that. And when I call RPlib put file, and I give it the name of the file, it's going to read that file and stick it in, just like you see it up there. If I look in the run dot XML, that's what it looks like after I'm all done. So that's the kind of Fortran code that you'd write to stick some protein data bank stuff in your tool. The one here means compress the data, and the zero means overwrite, as opposed to append. I guess if we set compress, it wouldn't look exactly like that. It would look like a bunch of compressed gobbledygook. But if I made this zero, so that I didn't compress the data, then you'd see it looking like that up there. All right? So just remember, if you ever run across a case where you need to produce a molecule, and if you've got that molecule in the protein data bank file format, just remember, yeah, there's a slide. I can go back and I'll grab that off the slide and put it in my program. All right, moving on to show you another thing. Another thing that's possible, you can create surface plots like this in your program. A lot of times you'll have a program that generates a bunch of data that you want to see as a mountain plot or a surface plot. And the way you do that, depending on what your data is, your data is usually composed of two things, a mesh and then a bunch of values that sit on the mesh. And a lot of times a mesh might be uniform and rectangular, just because it's easy to generate a mesh that way. So Rapture has a thing called the Unirec 2D. It's a two-dimensional uniform rectangular mesh. Uniform in X or Y, but it doesn't have to be uniform everywhere. It's just each axis is uniformly spaced. So this Unirec 2D means that I'm on a rectangular mesh and you can specify the sizes and everything in the mesh. And then at each point on the mesh, you have a value, a field value. And then if you give Rapture those two things, the field and the mesh, then it will generate the surface, the mountain plot as an output. Let me show you how you do that. Again, if you were looking in your tool dot, or I'm sorry, if you're going to look in your run file at the end of your program, in the run file, if you looked in the output section, you'd see something like what I'm showing here. You'd see, for example, this Unirec 2D with some name, my grid, or whatever. It's got a label, energy grid. It's got an x-axis section and a y-axis section. The x-axis and the y-axis describe the two dimensions of your mesh. The x-axis has a label and a mean value. It goes from 0 to 1, max value 1, and it has 50 points. So imagine it starts at 0, it ends at 1, and you divide it into 50 points. Similarly, the y-axis goes from 0 to 1, and it's also got 50 points. Doesn't have to, but it could. I mean, might have 20 points or might have 70 points, but it's going from, in this case, 0 to 1 with 50 points in x and in y. And I have a label, Fermi-Drak factor, and another label, energy, and all that. So if I put that information in there, in the output section, then you'll see at least a uniform rectangular mesh. I haven't gotten to the field yet, but that defines the mesh. Now, again, you can hard code this information in your tool.xml. If you know ahead of time everything about your mesh. If you know your mesh is going to always go from 0 to 1, and it's always going to have 50 points, and it's always going to have this label and all that, all of this information that you see here, you can hard code into your tool.xml. But you may say, well, I don't know how many points I'm going to have. If I simulate, in one case, I might have 100 points. If I simulate in another case, I might have 1,000 points, right? I don't know how many points I'm going to have. So you can put a lot of the information in the tool.xml, and then you can change it in your program. This is how I would change it in a Python program. I would do the usual Python put command, and I would say, in the output section, look for a Unirec 2D with the name Migrid. Look in the x-axis section for a parameter called max, and give it a value 1.0. So for this run of the program, I leave 0 alone, but it's going to go to 1.0. Actually, it didn't change, but anyway. So I'm overwriting the value here, pen no. I'm also going into the output section in the Unirec 2D, in the x-axis, and setting num points to 50, for example, and append equals no. So I can hard code that information in the tool.xml, and I can overwrite it in my program. Have my program put in the latest values for max and num points or whatever. So there's kind of a duality between the tool.xml and these program statements that create things in the tool.xml. We saw that in one of the, not the last, but the one before, the lab exercise before, we saw how you could create brand new things in the XML just by putting information in there. And that's what we're doing here. You could start with most of that information defined and then overwrite selectively whatever values you want. Or you could create every single bit of one of those information. You could set the about label, you could set the x-axis label, the y-axis label, you could have all kinds of commands here to set all those different labels and set all the various values. And that would create that structure. So that's how you define things in the XML like a Unirec 2D. In order to see the field plotted, you also have to define a field. And this is what the field looks like. The field has an about label, the field has component section. And the component has a mesh and values. The mesh that you see here, this mesh right here, this statement in red, this defines that mesh that we were looking at a second ago. When you define a field, you have to say which mesh it belongs to. This field goes to this mesh. And the mesh says where all the points are in space, right? So inside the component section you have a mesh output Unirec 2D parentheses migrate, okay, now I know where all the points are in space. And then you specify all the values. At the first mesh point, it's this value. At the next mesh point, it's this value. You can kind of see here, this is sort of how the values are laid out. V11, V12, V13, and so forth for X and Y. And again, the way that you would do that, if you want to put program field values in, you might hard code a lot of this in your tool.xml. In your tool.xml, you might have a field statement with about and label and component and mesh. You probably don't have the values though. The values are something that get generated at run time, right? So most of that information can be in your tool.xml. But then your program has to do this. Your program can take a bunch of values. There's a reshape command. I took a matrix Z in MATLAB. Z tick is the transpose of it. The reshape kind of reshapes it. And then the vales makes it so that it's a big long list of numbers. So I'm basically taking my MATLAB matrix and I'm converting it into a big long list of numbers. And then I'm stuffing it in using the call rplibputstring in the output section. Look for the field named Z. See, field ID equals Z right there. And then in the component.value section, stick all those values. So this call in MATLAB takes my Z matrix and makes a bunch of different numbers. And then I put those into the values section to generate the code. So getting a little complicated, you have to kind of work for it. If you want to do all the advanced graphics, it's not easy. You gotta work for it. But this is how you do it. You define a lot of the stuff in the tool.xml and then you override things in your program to set the values and kind of tweak it. There's also a way of handling an irregular mesh. Sometimes the world isn't so easy. Not everything's on a rectangular mesh. So you might have a bunch of different points. And there's something called a cloud mesh in Rapture, where you can just specify all the different x, y points. So for the cloud mesh, again, all these things have an about section with a label. So you can talk, you can say what that thing is. This is a 2D mesh. A cloud mesh also has units, I said microns. Hide yes, that means I don't want to see the mesh. Usually I just want to see the field. And then you can specify the points. x, y, new line, x, y, new line, x, y, new line. So these are all the points on the mesh. Each point here, each x and y value corresponds to one point on the mesh. So this first line is probably this point and this next line is like this point and so forth. So you just specify all the points on the mesh and then Rapture will read all those points and it'll connect them all together and make triangles out of them. So if you have an irregular mesh that looks like this, then you do that in Rapture. And again, how would I do that? Well, in Python here, if I had an x vector and a y vector, there's a zip function that puts them together. And for each x, y in x and y vector, it's going to go through and create a string that's x and y and the new line. So using x and y substituting in, and then I stick those things in. In the output.cloud points section, I'm going to put in the x and the y and the new line and append equals yes. Which means each time I'm going through this loop, it's adding another x, y, x, y, x, y. So I'm converting x, vex and y, vex into a list of points that show up in the points section. That's what I'm doing. All right, and if I've defined that cloud mesh, I might have a field that goes with the cloud mesh. Just like the field we saw a minute ago, except this one's using a different mesh. So there's a mesh line here that says mesh output.cloudM2D. That's the cloud that we defined right up here. I've got a cloud named M2D. So I set the mesh down here to output.cloudM2D, and then I give all the values. And the values are just in order with the mesh points. This is the first mesh point, this is the value for the mesh point. This is the next mesh point, this is the value for that mesh point. Next mesh point, value for that mesh point, so forth. So if you're doing finite element simulation, this stuff probably seems really familiar to you. Cuz you just have a bunch of x, y points and you have the value that you've computed at each point on your finite element mesh. Anyway, that's how you do fancy plots like the one that's shown up here. You notice it's really regular because wherever I have points, you can kinda see the triangles here. But over here I don't have any points, so there's nothing plotted. All right, there's another thing, completely different thing that you can do. There's a thing in Rapture called a sequence. And you can use a sequence to create something like a movie. The sequence you can use with a sequence of images and you get something like a movie. You can create a sequence of curves and you get something like a plot that acts like an animated plot. You can also create a sequence of molecules. And again, you get a molecule, for example, with molecular dynamics that may be jiggling around and doing different things. So a sequence has some kind of Rapture object as a function of time or index or something like that. And here's how you do it. Again, if you can create this XML in your program, then you're good to go. At the end of the day, if your run.xml file looks like this, you can load it up in Rapture and it'll show you a sequence. The way the sequence works, the sequence has an about label. That's the label that shows up at the top above the plot. It has an index. The index is, in this case, it says parameter A. So down here, there'll be a little movie control and it'll say parameter A for the movie control. You can actually move around on this movie control and set whatever frame you want. Or you can press the play button and it'll play through all the frames. And as it's doing it, it'll show you parameter A equals each of these indexes. You notice for each element, there's like index one and index two and all of that. So you'll see parameter A equals one, parameter A equals two. You can use those however you want. This may be a time point, it may be at one microsecond, at two microseconds, at three microseconds, or 1.7 microseconds, 1.8 microseconds. So in general, that index that you're using doesn't have to be an integer. Could be anything, could be time, could be day of the week, could be whatever you want. So whatever index you label here and whatever index value you show here, Rapture will label it that way. And then for each element that you create, you can stick in a curve like this or an image or anything that we've created so far in Rapture, molecule and all of that. So the sequences are pretty powerful. I don't know if they support every possible combination of Rapture objects, but the basic things like curves and images and stuff you can do inside of sequences. So if you look in your run.xml, that's what you'd see. And you just have to use commands like this kind of stuff, these put commands to kind of generate that stuff. All right, one last example, it's kind of neat. Suppose you have MATLAB and there's a really great picture that you can generate out of MATLAB. MATLAB can do all kinds of neat visualizations, 3D surfaces and crazy looking plots. And here's a little bit of MATLAB or Octave code, for example. I set up a Bessel function and then I went ahead and surface plotted it with some shading. So you can type that code into MATLAB or Octave and it'll generate a plot that looks like that. And you might say, ooh, ooh, I want that plot in Rapture. And I actually like that plot better than the other one that Rapture does. I want that in Rapture, how do I get that? You can take any image that you can generate from any other program and you can always save it as an image in Rapture. Now you won't be able to interact with the plot. You won't be able to rotate the plot, zoom in and all of that. It's just an image. But anything that you can generate as an image, you can put into your program if you want to as output. So let me show you how to do that. Here's my little main program and here's my MATLAB or Octave code. I'm generating a Bessel function and I'm doing all those commands that I showed you just a second ago to generate the surface plot, right? So this is just my straight up MATLAB code. I can also tell MATLAB to draw it and I can also tell MATLAB to save the output into a file called output.png. So all of that stuff tells MATLAB to very quietly in the background, generate a drawing and save the result in a file called output.png. Now if I can get output.png into Rapture, I'm done. And the way I do that is with my friend, putfile, remember we saw putfile a couple of slides ago. Putfile will take any file, read the contents and stuff it in wherever you say to stuff it. So in this case, we say rplibputfile in the output section, look for an image called snapshot and set its current value to the contents of that file. And by the way, the one says compress the image and the zero says overwrite. Don't append. So that'll take that output image, load it up, compress it, and put it in as the current value for that image. So voila, now I have an image in Rapture. I could use the same thing for the sequence thing that I showed you a minute ago, I might have a sequence of images. And I'd go through in a loop and for each output image in the sequence, I'd do a putfile, take that image and put it into the sequence. Take that image and put it into the sequence. You can build really complicated things like that if your program has generated a bunch of images. All right, and there's examples too, a lot of example code. And I should mention that, let me do that right now. If we go into Rapture and we've shown you the documentation for all this stuff, when you're looking in the documentation and you go into the GUI XML elements and you're trying to figure out, how do I do a Unirec 2D? At least you know it's there now. You can look at the documentation and see all the stuff in there. And you can look at some of the examples and what's described here in terms of how it works, and it'll show you what it looks like and all that. There's also examples in the code for Rapture. If you go into the code for Rapture, there's an examples directory. And the examples directory has a zoo of examples. And you'll find this on Nano Hub too. I think there's even a menu entry to help you copy the examples. So for any one of these things, if you wanted to see, I want to see what an example of Unirec 2D looks like or something. Every one of these has a tool.xml file and then it has a little program that generates a mesh and all of that. So as you're doing more and more complicated things with Rapture, take a look at the zoo of examples. You can try out, you just run an example and see what it does. And then if it does something kind of neat, you say, I wonder how they did that? You can go into the code and kind of look at it and figure out how it works. So there's a lot of different examples there in the zoo and there's the app Fermi stuff that I showed you before, all the different languages and so forth. So a lot of different good examples there to poke around with. So if you have any energy left in the day, this is the last thing that we can try to do today. Maybe it's the first thing we'll finish up tomorrow morning. What you can do is play around with this function in MATLAB. If you get into Octave or MATLAB in your workspace and you type these commands, you'll be able to generate like a Bessel function. And then the question is, can you make a program where you can prompt the user for the max order, the max x and the number of grid points, which is these parameters here, end points, new max, x max. Basically, I want to prompt the user for these values. I want to generate the Bessel function and I want to spit it out to Rapture as a Unirec 2D in a field. In order to do this, the way I'm showing it here, you have to do it as a field and Unirec 2D. So you look back through the notes and you'd be looking at kind of this stuff right here, figuring out how do you generate a Unirec 2D in the output section that looks like that, and how do I generate a field that looks like that. And I want to take the values from MATLAB and kind of get them stuck in my XML, kind of like that. So if you're curious and you want to mess around, you could also try this route too. If you want to bag it with the field in the Unirec 2D, you could also try this route too where you're actually generating the image in MATLAB and then just doing a put file on the image in MATLAB to try it out. That's another way to do it too. So if you want to mess around a little bit with some of the advanced visualization, get started with this example and we'll pick it up in the morning and I'll go through the solution. Okay, so here's the solution that you've got for this lab assignment. We wanted to take this little bit of octave code and kind of wrap it into a Rapture interface. Like that, so first thing, I can run the Rapture Builder. And I can at least get part of my interface going. Rapture Builder doesn't have some things like the Unirec 2D and all of that field and stuff like that. But at least I can get a number and an integer and a number. And if you wanted to have an image on the output side, you can get that far. So you can use the Builder to do as much as you can and then save out the tool.xml. Let me open the tool.xml, I'm not gonna save that. Let me open the one that I generated. Now again, the Builder loads as much as it can understand. So again, it's got my definition for new max and xmax and num points and it's got the image there and all that. So that all looks good. I've got the tool set to octave, that all looks good. Got some nice explanations in for each of my parameters. But you notice on the output side, the Builder is not showing the Unirec 2D or the field and I'm not gonna save this. If I save this right now, it'll save exactly what you see here. It won't save anything else. What I did was I built my tool.xml as much as I could and then I went in and edited some stuff, added some stuff. So this is the stuff the Builder added and then I went in and added some extra stuff into the tool.xml right here. I added the stuff that the Builder doesn't know about by hand. So I define myself a Unirec 2D named grid. It's got an x-axis with a label and a min value and a y-axis with a label and a min value. There's a max value and num points too, but I'll set those later in my program. Cuz you could set them here, it wouldn't hurt. But you need to set them later inside your program for sure. Once you know what the user wants them to be. So that's my Unirec 2D, basically defining the x-axis and the y-axis as best I know it. And then I have this field here. And the field, by the way, you should always have a label on things so that Rapture can show them. But anyway, I've got a field here that I want Rapture to show, best of function surface. And I've got a component with a mesh. And for the mesh, I at least want to say what mesh it belongs to. I set output.Unirec2DGrid. That means look up there to the Unirec2D, that's my grid. Some people were getting errors about, didn't know the dimensionality of your field. And that happens when there's no grid. There's no grid and Rapture doesn't know what dimensionality, what you're trying to plot. So again, in my tool.xml, none of this stuff is ever gonna change. So I set all of this in the tool.xml. And then in my program, I can add the stuff that is gonna change. The number of points, the min and the max values for the grid, and then also the values for the component. Obviously the field values are the most important thing here that I need to add. I'm also gonna add in, I've got this image here, that I'm gonna show you how to do that part too with putting the image in. And I didn't have any specific current value for the image. That comes later again in my program. But at least I've got the label there. If you ever forget about the label like this, if you create an image, but you don't give it a label, it won't show up as an output. So you wanna make sure, maybe that's a bug or a feature, I don't know. But the idea is if you don't label stuff, then Rapture figures, you don't wanna look at it. So if you're saving an image like this, make sure you at least give it a label. And the builder will do that if when you're using the builder, it'll at least give it a label. All right, so I've got that tool.xml. Now, I've got my octave program and I can run my test script. My test script didn't look like it did very much. It basically ran these functions and it did this plotting thing. And it saves out an output.png and then it quits. So it didn't look very spectacular. But if I Xload image now this output.png, you can see that's what my test script did. So what I wanna do now is take that test script and integrate it into some kind of skeleton. Maybe I generated a skeleton out of the builder for my main program. So here's my main program coming from the builder with my kind of skeleton code. And then I stick my code in here for my MATLAB script. So those are the three lines, basically, that I needed to generate two vectors for new and X and then the Bessel function, Z. Everything else now just becomes a matter. I mean, all the computation is happening right here. Everything else now is just figuring out how to get the values and put them back out into Rapture. So let me show you that part. All right, so, I wanna save in the output section. I've got a thing called Unirec2D. And as I told you before, I need to update the x-axis num points and the y-axis num points. And I do that according to the number of points, end points here that we've got. If I try to pass end points in there, then MATLAB or Octave is gonna get mad because the function is wrong. It wants a string. It doesn't want an integer or a double or something like that. It wants a string value. So there's this handy function here. There's int to stir or num to stir that I can use to take an integer or a number and convert it into a string. So that's what I did here. I called int to stir to take my num points value and convert it into a string called num. And then I use that string value there. So I'm setting the x-axis num points and the y-axis num points according to this variable end points. It's just kind of converting to a string. Also on the grid, I wanna set the x-axis max and the y-axis max. And here I did it more in line. I set x-axis max to num to stir x max and y-axis max num to stir new max. So call the function in line and these are doubles. So I use num to stir instead of int to stir. And then finally, I wanna save out all the values. And to save all the values, I copied this stuff out of the notes. But just to explain, what I wanted to do, I wanted to go in the output section of my field and I wanted to set the component values. And whenever I do that, I'm supposed to set that to a big string. I suppose I could have set it point by point and done a pen to pen to pen. But in this case, I just wanted to generate one gigantic string with all the values in it. So how do I generate one gigantic string with all the values? There's a trick in MATLAB, the sprintf function. If you give it a vector of values, if I have a vector of 2500 values, sprintf will take all of the 2500 values, substitute them into whatever format string I've got and generate me a gigantic string of all the results. And my format string here says percent 12g. That means some kind of double precision number that's about 12 digits y. So double precision number followed by a new line. If any of you looked in your run.xml, you would have seen that, right? When you look in the field values section, you see a number and a new line. And a number, number, number, they're put down like that on different lines, right? That's because right here, we put the percent 12g blackslash n for the new line and we stuck in the vector of values that's 2500 long. And so it gives you 2500 lines of output. Now, where did I get that 2500 wide vector? Because wait a minute, I've got a matrix up here. This gives me a matrix of 50 by 50. And I wanted a vector with 2500 points. So this is what that function does. The reshape function takes my vector, my matrix, z. And it reshapes it into a vector that is n points times n points long and one row tall. So it turns it into a vector of 2500 points, basically. 2500 long and one tall, or however many good points I have, right? And then one last wrinkle. When you do all of this and you look carefully at your results, you might notice, wait a minute, everything looks flipped. It looks wrong. My x-axis is my new axis and vice versa. And so in order to fix that problem, Matlab versus Rapture, what I really need to do is use z transpose. Z transpose flips my matrix so that it matches the way Rapture expects the data. And then I convert it to a vector of 2500 points. And then I convert it to a string, and then I put it out. So it's all a bunch of headaches, but basically I'm just trying to take the z matrix and get it out as a list of 2500 points in the right order. All right, so that's the code. And if you do that, if you set the stuff in the tool.xml, and then what this does is it fills in the values that are changing dynamically, then you get a nice interactive plot. There's one other thing here. If we, I'll show you the other solution. The other solution was to have Matlab generate the plot. And so this is the code that we had in the notes that tells Matlab to draw a surface plot, to do the shading, draw it, and then save the output as a PNG file. And it does it all without popping up on the screen. The visible off makes it so it doesn't pop up on the screen while it's writing. So all of that generates a file called output.png. I just need to take that image and stuff it in the output. And I do that with this line. This line, rplib putfile this time, putfile instead of putstring. The putfile thing is similar. It finds a path output.image called static.current. But instead of putting that string in there as the contents, it treats that string as a file name. It loads up the file and takes the contents of the file and puts that in. So it's going to open output.png, get the contents of that file, and stuff it in as the current value for the image. And by the way, images are big and binary and all of that. So I set a flag for compression. So it'll compress the image and put it in. And then 0 again always means overwrite the value. So this is the way I take the file output.png and stuff it in as the value of the current image. So I've got both outputs now. And then like any other program, I finish up with rplib result and quit. So if I run this now, it asks me for some values and I can simulate. And it gives me a nice plot. And I can also look at the image. That's one generated by MATLAB. The difference is that this one I can actually rotate and interact with. There's buttons over here to zoom in. I can move around on the plot like that. There's also other things I can do. Let me reset the view. I can fiddle with the contour lines, turn them on and off. I can make it a wireframe or not. I can turn the grid off. So there's all kinds of weird things that I can do with this interactive version of the plot. And I can't do any of that with the image that I got from MATLAB. Because MATLAB's not running anymore, it's done. So the only thing I can do with the image from MATLAB is I can zoom in on the image. And when I zoom in, I can see the axis a little bit better. So I can zoom in and zoom out. But that's it. The image, if I try to drag on it, it doesn't rotate. It doesn't change. So this one's slightly better because it's a little more interactive. And if I like that picture, I can always download it to my desktop. And now I can copy and paste and put it in my document or whatever. So that lets me kind of maybe I want to zoom in on this peak. And I'm trying to write a, maybe I'm writing a paper that talks about this particular peak. And then I can download that and grab that image and put it into my report. That's what's a little nicer about it because I can fiddle with the image. One other thing, just to mention real quick, if we fiddle with the values, say I set that to 5 and 5 and run it again, so now let me turn my grid back on and everything sort of back to the way it was, not wireframe. So some people looked at that and thought, wow, that looks like really weird. Why is it so weird? My original plot looked like that. And my new plot looks like that. Why is it so weird? Actually, it's doing the right thing because the original plot was all the way from 0 to 20 and 0 to 10 in the new and the X axis. So the original plot covered that whole space. Whereas the plot that I just did goes from 0 to 5. And if you look, it actually is doing that, right? It's going from 0 to 5 in one axis and from 0 to 5 on the other axis. So this new plot is much smaller than the original plot. And that's what this is showing you. Rapture, when you have two results in Rapture, it always puts them on the same axis so that you can compare them. And that's useful here because otherwise, you might not realize when you're flipping back and forth between results, you're actually zooming in on the axes. If it didn't do this, you might have thought at first it was OK, but it would've fooled you later because this is actually covering a much smaller space than the original function. So that's good to know. Rapture keeps everything on consistent axes when you're plotting so that you can compare things when you're looking at them.