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.
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.
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.
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:
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.
Source: https://nickcharlton.net/posts/drawing-animating-shapes-matplotlib.html
0 Response to "Draw Circle Perpendicular to Vector Matplotlib"
Post a Comment