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.
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.
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.
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:
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