Draw Circle Perpendicular to Vector Matplotlib

Drawing and Animating Shapes with Matplotlib

Besides a existence the best Python package for drawing plots, Matplotlib also has impressive primitive drawing capablities. In recent weeks, I've been using Matplotlib to provide the visualisations for a set of robot localisation projects, where we tin use rectangles, circles and lines to demonstrate landmarks, robots and paths. Combined with NumPy and SciPy, this provides a quite capable simulation surround.

Note: You should already know how to work with Matplotlib. If you don't, I propose either Matplotlib for Python Developers or the SciPy Lecture Notes.

Primative shapes in Matplotlib are known as patches, and are provided by the patches module. Subclasses of patch provide implementations for Rectangles, Arrows, Ellipses (and and so Arcs, Circles) so on. All of this is part of the Artist API, which also provides back up for text. In fact, everything drawn using Matplotlib is part of the artists module. Information technology'southward just a different level of access for drawing shapes compared to plots.

Drawing

There are multiple means to write Matplotlib lawmaking1. Whilst I'thousand using Pyplot in the demonstrations below, the usage is essentially the same. The differences are in how the figure is initialised.

Drawing is a affair of adding the patch to the current figure'south axes, which using Pyplot looks something similar this:

                          import              matplotlib.pyplot              every bit              plt              plt              .              axes              ()              circle              =              plt              .              Circle              ((              0              ,              0              ),              radius              =              0.75              ,              fc              =              'y'              )              plt              .              gca              ().              add_patch              (              circle              )              plt              .              axis              (              'scaled'              )              plt              .              testify              ()                      

gca() returns the electric current Axis instance. Setting the centrality to "scaled" ensures that you can meet the added shape properly. This should requite you something like Figure 22.

Figure 2: Circles
Figure 2: Circles

Rectangles

                          rectangle              =              plt              .              Rectangle              ((              x              ,              10              ),              100              ,              100              ,              fc              =              'r'              )              plt              .              gca              ().              add_patch              (              rectangle              )                      

rectangle is a Rectangle patch. It accepts a tuple of the lesser left hand corner, followed by a width and a pinnacle.

kwargs of either ec or fc set the edge or confront colours respectively. In this instance, it gives the states a red rectangle without a border. Various others are likewise supported, as this is just a subclass of Patch.

Circles

                          circle              =              plt              .              Circle              ((              0              ,              0              ),              0.75              ,              fc              =              'y'              )              plt              .              gca              ().              add_patch              (              circumvolve              )                      

circle is a Circle patch. It accepts a tuple of the centre point, and then the radius.

The argument of fc gives us a yellowish circle, without a border.

Lines

                          line              =              plt              .              Line2D              ((              ii              ,              8              ),              (              half-dozen              ,              half dozen              ),              lw              =              2.5              )              plt              .              gca              ().              add_line              (              line              )                      

A basic line is a Line2D instance. Note that it's an Artist itself and and so its not added every bit a patch. The showtime tuple gives the x positions of the line, the second gives the y positions. lw specifies the line width. Much like lines that are part of plots in Matplotlib, the line has a lot of configurable styles, such every bit the following:

                          dotted_line              =              plt              .              Line2D              ((              ii              ,              eight              ),              (              iv              ,              four              ),              lw              =              5.              ,              ls              =              '-.'              ,              mark              =              '.'              ,              markersize              =              50              ,              markerfacecolor              =              'r'              ,              markeredgecolor              =              'r'              ,              alpha              =              0.5              )              plt              .              gca              ().              add_line              (              dotted_line              )                      

which gives the lower line in Effigy 3. ls defines the line style and marker gives the start and end points.

Figure 3: Two Lines
Effigy 3: Two Lines

Note: If you can't see the lines and merely the end markers: There's a Bug in WebKit which stops you seeing straight lines. You probably tin't meet the plot filigree lines, either.

Polygons

Polygons are simply a series of points connected past lines — allowing y'all to depict complex shapes. The Polygon patch expects an Nx2 array of points.

                          points              =              [[              ii              ,              i              ],              [              8              ,              i              ],              [              viii              ,              4              ]]              polygon              =              plt              .              Polygon              (              points              )                      

Polygons are also a nice way to implement a multi-footstep line, this tin be done by tuning the Polygon constructor somewhat:

                          points              =              [[              ii              ,              4              ],              [              ii              ,              8              ],              [              4              ,              6              ],              [              6              ,              8              ]]              line              =              plt              .              Polygon              (              points              ,              closed              =              None              ,              make full              =              None              ,              edgecolor              =              'r'              )                      

This gives the red line in Figure 4. airtight stops Matplotlib drawing a line betwixt the first and last lines. fill is the colour that goes inside the shape, setting this to None removes information technology and the edgecolor gives the line information technology's colour.

Figure 4: Polygons
Figure 4: Polygons

Animation

The interest here is to move sure shapes effectually, and in the instance of something like a line (which could, for example, represent a path) update its state. Hither, I'm going to go a brawl to orbit around a primal point at a gear up distance away from it:

                          import              numpy              as              np              from              matplotlib              import              pyplot              equally              plt              from              matplotlib              import              animation              fig              =              plt              .              figure              ()              fig              .              set_dpi              (              100              )              fig              .              set_size_inches              (              vii              ,              6.5              )              ax              =              plt              .              axes              (              xlim              =              (              0              ,              10              ),              ylim              =              (              0              ,              10              ))              patch              =              plt              .              Circle              ((              five              ,              -              5              ),              0.75              ,              fc              =              'y'              )              def              init              ():              patch              .              middle              =              (              v              ,              v              )              ax              .              add_patch              (              patch              )              return              patch              ,              def              animate              (              i              ):              x              ,              y              =              patch              .              center              x              =              5              +              3              *              np              .              sin              (              np              .              radians              (              i              ))              y              =              v              +              3              *              np              .              cos              (              np              .              radians              (              i              ))              patch              .              center              =              (              x              ,              y              )              return              patch              ,              anim              =              animation              .              FuncAnimation              (              fig              ,              animate              ,              init_func              =              init              ,              frames              =              360              ,              interval              =              xx              ,              blit              =              True              )              plt              .              bear witness              ()                      

To exercise this, I'thousand just using the equation for a signal on a circle (but with the sine/ cosine flipped from the typical — this just means it goes effectually in clockwise), and using the animate function's i argument to help compute it. This works because I've got 360 frames.

The init() function serves to setup the plot for animating, whilst the animate function returns the new position of the object. Setting blit=True ensures that only the portions of the image which have changed are updated. This helps hugely with performance. The purpose of returning patch, from both init() and breathing() is to tell the animation function which artists are irresolute. Both of these except a tuple (as you lot can exist animative multiple unlike artists.) The Circle is initially created off screen as we need to initialise information technology before animative. Without initialising off screen, blitting causes a bit of an artifact.

And and then, this (with the improver of the department beneath) produces the video in Figure 5 beneath:

Figure v: The Ball Animation as a Video

Jake Vanderplas' notes on Matplotlib were invaluable in figuring this section out. Notably in blitting3. But generally, simple Artist animation is a fleck thin on the ground. Hopefully this helps with that somewhat.

Output

I initially wanted to be able to export in two formats, ane as an H.264 video, similar the one above and every bit an animated gif. My initial assumption was that a gif would virtually likely accept less of an overhead than that of a video and information technology would avoid browser inconsistencies.

To solve the video export, Matplotlib comes with support for exporting video sequences from an blitheness using the salve method on Animate. It pipes out support for video to ffmpeg, but video formats are somewhat fickle and so you need to add a few more than flags to get it to render correctly.

                          anim              .              save              (              'animation.mp4'              ,              fps              =              30              ,              extra_args              =              [              '-vcodec'              ,              'h264'              ,              '-pix_fmt'              ,              'yuv420p'              ])                      

This saves an H.264 file to 'blitheness.mp4' in a format supported past QuickTime4. In Jake Vanderplas' blitheness tutorial he doesn't specify a pixel format and it works fine. I doubtable this might be something to do with ffmpeg defaults. You lot'll also demand to be using Matplotlib version 1.two.0 or greater (I had issues with 1.1.0.)

Sadly, Matplotlib doesn't support producing gifs on it's own, but this was only the first of a few issues. We tin convert the image nosotros've just produced using ffmpeg and stitch it dorsum together as a gif using ImageMagick:

            ffmpeg              -i              animation.mp4              -r              10 output%05d.png  convert output*.png output.gif                      

Here, ffmpeg converts the video file from before into a series of PNG files, then we use ImageMagick'south convert control to push these back together into a gif. On its own, this ended up with a 4MB file. Fifty-fifty the video was but 83KB and then this isn't and then great. After attempting to shrink the final output gif using ImageMagick (they accept a huge article on Animation Optimisation), I turned to compressing each input file using ImageOptim. This ended upwardly giving me a final image size of viii.0MB (and took a good hour.) Worse than I started with.

With this, I concluded that a gif isn't that great of an option. I'd like to meet blithe SVG support for Matplotlib, simply I'd wonder if this required moving to something which was stylised using a Document-Object-Model (DOM). Michael Droettboom touched on this in his "Matplotlib Lessons Learned" post. Even for something much more circuitous than these contrived examples, using JavaScript to breathing the SVG is much ameliorate option. But for at present, a video is the best manner.

And that's about information technology. Ane of the advantages of having the Matplotlib provided grid is that the numbers are relatively like shooting fish in a barrel to determine — for my purposes this means hooking the view to the calculations.

Pylab provides a merging of the Numpy and Matplotlib namespaces to ease transition from MATLAB. It's non recommended and anyway I'm a programmer — not MATLAB user — get-go.

            And then I'd employ the OOP method for embedding in bigger projects, I've done this for utilize in PyQt, for example. The OOP method is slightly more than circuitous, but a better alternative if you need to display multiple, like plots using  unlike information.                      

krausesubbeirie.blogspot.com

Source: https://nickcharlton.net/posts/drawing-animating-shapes-matplotlib.html

0 Response to "Draw Circle Perpendicular to Vector Matplotlib"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel