Drawing Circles in Image With Matplotlib

Drawing and Animating Shapes with Matplotlib

As well a being the best Python parcel for drawing plots, Matplotlib likewise has impressive archaic drawing capablities. In recent weeks, I've been using Matplotlib to provide the visualisations for a set of robot localisation projects, where we tin employ rectangles, circles and lines to demonstrate landmarks, robots and paths. Combined with NumPy and SciPy, this provides a quite capable simulation environment.

Annotation: Y'all should already know how to piece of 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 then Arcs, Circles) and so on. All of this is part of the Artist API, which also provides support for text. In fact, everything drawn using Matplotlib is part of the artists module. It'due south just a different level of access for cartoon shapes compared to plots.

Cartoon

There are multiple ways to write Matplotlib codei. Whilst I'm using Pyplot in the demonstrations below, the usage is substantially the same. The differences are in how the figure is initialised.

Drawing is a matter of adding the patch to the current figure's axes, which using Pyplot looks something like this:

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

gca() returns the electric current Axis instance. Setting the axis to "scaled" ensures that yous tin can meet the added shape properly. This should requite you lot something like Effigy ii2.

Figure 2: Circles
Figure 2: Circles

Rectangles

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

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

kwargs of either ec or fc set the border or face colours respectively. In this case, it gives us a red rectangle without a border. Various others are also supported, equally this is but a subclass of Patch.

Circles

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

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

The statement of fc gives us a yellow circle, without a edge.

Lines

                          line              =              plt              .              Line2D              ((              two              ,              8              ),              (              vi              ,              6              ),              lw              =              ii.5              )              plt              .              gca              ().              add_line              (              line              )                      

A basic line is a Line2D case. Note that it'south an Artist itself and so its not added equally a patch. The first tuple gives the x positions of the line, the 2d 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 as the following:

                          dotted_line              =              plt              .              Line2D              ((              two              ,              8              ),              (              4              ,              4              ),              lw              =              5.              ,              ls              =              '-.'              ,              marker              =              '.'              ,              markersize              =              l              ,              markerfacecolor              =              'r'              ,              markeredgecolor              =              'r'              ,              alpha              =              0.5              )              plt              .              gca              ().              add_line              (              dotted_line              )                      

which gives the lower line in Figure iii. ls defines the line style and marking gives the start and end points.

Figure 3: Two Lines
Figure 3: Ii Lines

Note: If you can't come across the lines and only the cease markers: In that location'southward a Problems in WebKit which stops you seeing direct lines. You probably can't see the plot filigree lines, either.

Polygons

Polygons are just a series of points connected by lines — allowing you to describe circuitous shapes. The Polygon patch expects an Nx2 array of points.

                          points              =              [[              2              ,              ane              ],              [              8              ,              1              ],              [              viii              ,              4              ]]              polygon              =              plt              .              Polygon              (              points              )                      

Polygons are too a nice way to implement a multi-pace line, this can be done by tuning the Polygon constructor somewhat:

                          points              =              [[              2              ,              4              ],              [              2              ,              8              ],              [              four              ,              vi              ],              [              half dozen              ,              viii              ]]              line              =              plt              .              Polygon              (              points              ,              airtight              =              None              ,              fill              =              None              ,              edgecolor              =              'r'              )                      

This gives the red line in Figure 4. closed stops Matplotlib drawing a line between the first and final lines. fill is the colour that goes within the shape, setting this to None removes information technology and the edgecolor gives the line it's colour.

Figure 4: Polygons
Figure iv: Polygons

Animation

The interest here is to move sure shapes around, and in the case of something like a line (which could, for example, represent a path) update its country. Hither, I'm going to go a brawl to orbit around a cardinal point at a ready altitude abroad from information technology:

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

To do this, I'thou but using the equation for a indicate on a circle (just with the sine/ cosine flipped from the typical — this merely ways it goes around in clockwise), and using the breathing function'due south i statement to aid compute it. This works considering I've got 360 frames.

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

And and so, this (with the addition of the section below) produces the video in Effigy five below:

Figure 5: The Ball Animation every bit a Video

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

Output

I initially wanted to exist able to export in two formats, one as an H.264 video, similar the one above and equally an animated gif. My initial assumption was that a gif would most probable have 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 animation using the relieve method on Animate. It pipes out support for video to ffmpeg, merely video formats are somewhat fickle and then you demand to add together a few more flags to become information technology to render correctly.

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

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

Sadly, Matplotlib doesn't support producing gifs on it'south own, but this was only the get-go of a few issues. We can convert the image we've just produced using ffmpeg and stitch it dorsum together equally a gif using ImageMagick:

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

Here, ffmpeg converts the video file from before into a series of PNG files, then we use ImageMagick'south catechumen command to button these back together into a gif. On its own, this ended up with a 4MB file. Even the video was only 83KB and then this isn't and then great. After attempting to compress the final output gif using ImageMagick (they take a huge article on Animation Optimisation), I turned to compressing each input file using ImageOptim. This ended up giving me a concluding image size of 8.0MB (and took a good hour.) Worse than I started with.

With this, I concluded that a gif isn't that great of an choice. I'd like to encounter animated SVG support for Matplotlib, merely 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" mail service. Even for something much more complex than these contrived examples, using JavaScript to animate the SVG is much ameliorate option. Only for at present, a video is the best way.

And that'due south about it. 1 of the advantages of having the Matplotlib provided grid is that the numbers are relatively easy to determine — for my purposes this ways hooking the view to the calculations.

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

            And so I'd use the OOP method for embedding in bigger projects, I've done this for apply in PyQt, for example. The OOP method is slightly more complex, but a amend culling if you need to brandish multiple, similar plots using  different data.                      

dinardocasere1951.blogspot.com

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

0 Response to "Drawing Circles in Image With Matplotlib"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel