There are previous questions about quiver plots on polar axes in matplotlib, however they concern vector fields. I'm interested in drawing arbitrary vectors on polar axes. If there is a genuine duplicate, please link it.
I'm writing some software which concerns a circular world. I'm plotting an agent's trajectory from the centre of a circular arena to the edge. This is visualised by drawing a vector from the centre of the circle to the edge. I'm trying to use matplotlib's quiver plot to plot vectors on a set of polar axes. Here's a minimum working example:
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
# Plot origin (agent's start point)
ax.plot(0, 0, color='black', marker='o', markersize=5)
# Plot agent's path
ax.quiver((0, 0), (0, 1), color='black')
# Example of where (0, 1) should be
ax.plot(0, 1, color='black', marker='o', markersize=5)
# Plot configuration
ax.set_rticks([])
ax.set_rmin(0)
ax.set_rmax(1)
ax.set_thetalim(-np.pi, np.pi)
ax.set_xticks(np.linspace(np.pi, -np.pi, 4, endpoint=False))
ax.grid(False)
ax.set_theta_direction(-1)
ax.set_theta_zero_location("N")
plt.show()
If you run the code, you get this plot
The plot shows the origin plotted correctly, an example point at (0, 1) to show where the vector should end, then the vector itself which appears far too short (though the direction is correct). From the docs, I understand that quiver takes cartesian coordinates (x,y) denoting the start point of the vector and (u,v) denoting the vector's direction. In my previous experience with quiver (u,v) essentially denotes where the vector's tip will be, so in this case we'd expect the vector to be drawn from (0,0) to (0,1) which isn't the case and I don't know why.
In short, I want to be able to draw arbitrary vectors on a set of polar axes and quiver isn't working as I expected. Three questions:
Is my code actually sensible given my goal? I want to draw a unit vector from the origin to the edge of the polar plot.
Am I completely misunderstanding how to use quiver?
How can I draw arbitrary vectors on polar axes in matplotlib? I know about arrow and I'm going to give that a try though initial attempts were unsuccessful.
Short of using a standard plot and just defining my own polar system within it I'm completely stumped.
You did not specify u and v in ax.quiver(x,y,u,v). To make sure the arrow is 1 unit long you will need to set the scale und units as well.
ax.quiver(0,0,0,1, color='black', angles="xy", scale_units='xy', scale=1.)
Related
I would like to rotate an array about the axis that is normal to a given location on the surface of a sphere, but unsure how to go about it.
As an example, the below code creates a series of points (a dipole field line), shifts it away from the centre of a sphere and rotates to some angle in the xy plane.
At this location, I would like to rotate the field line to any angle around the axis that is normal to the sphere surface.
import numpy as np
import matplotlib.pyplot as plt
field=np.linspace(-np.pi/2,np.pi/2,100)
circle=np.linspace(0,2*np.pi,100)
theta=60*np.pi/180
r_shift=0.9
r=1.5*np.sin(field+np.pi/2)**2
x0=r*np.cos(field)+r_shift
y0=r*np.sin(field)
# rotate around y-axis
x=x0*np.cos(theta)
y=y0
fig,ax=plt.subplots()
ax.set_box_aspect(1)
ax.plot(np.cos(circle),np.sin(circle),color='k')
ax.plot(x,y)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
plt.show()
I think it could be done with Euler angles or Rodriguez' formula, but I'm not familiar enough to implement this.
For a project I need to create a visualization that draws a circle around some locations on a map. The visualization used Cartopy v.0.18.0 to render the map. It uses the GoogleTiles class to fetch and display the tiles in the relevant region, and the add_patch(Patch.Circle(..., transform=ccrs.PlateCarree())) method to draw the circle.
tiles = GoogleTiles()
fig = plt.figure(figsize=(15,15))
ax = fig.add_subplot(1, 1, 1, projection=tiles.crs)
ax.set_extent((-121.8,-122.55,37.25,37.85))
ax.add_image(tiles, 11)
ax.add_patch(Patch.Circle(xy=[-122.4015173428571, 37.78774634285715], radius = 0.021709041989311614 + 0.005, alpha=0.3, zorder=30, transform=ccrs.PlateCarree()))
plt.show()
However, although I tried several transform objects I either got a ellipse instead of a circle (e.g. using ccrs.PlateCarree()) or no circle at all (e.g. using ccrs.Mercator()).
I found several different solutions online (e.g. Drawing Circles with cartopy in orthographic projection), however, these were not for the Mercator projection and I sadly lack the projection/transformation knowledge to adapt these to my problem.
The only way I was able to produce a circular patch, was when I set the projection parameter on fig.add_subplot to ccrs.PlateCarree(). This, however, distorts the map and the labels become blured, so this is sadly not an acceptable solution.
As the project is due soon, a speedy reply would be much appreciated.
Thanks #swatchai this was the missing hint, so for those intested the code looks like this right now, and it does work! Hooray!
tiles = GoogleTiles()
fig = plt.figure(figsize=(15,15))
ax = fig.add_subplot(1, 1, 1, projection=tiles.crs)
ax.set_extent((-121.8,-122.55,37.25,37.85))
ax.add_image(tiles, 11)
# The diameter is in degrees in EPSG:4326 coordinates therefore, the degrees have
# to be converted to km. At 37N the degree latitude is 11.0977 km.
ax.tissot(rad_km=(0.021709041989311614 + 0.005) * 11.0977, lons=[-122.4015], lats=[37.7877], alpha=0.3)
plt.show()
When executing the above code the following warning is thrown but it has visible effect on the result:
/opt/conda/lib/python3.8/site-packages/cartopy/mpl/geoaxes.py:761: UserWarning: Approximating coordinate system <cartopy._crs.Geodetic object at 0x7fa4c7529770> with the PlateCarree projection.
warnings.warn('Approximating coordinate system {!r} with the '
So thanks again #swatchai you saved my day!
I have a set of points, that I am plotting currently with matplotlib:
x_points = [82,92,90,90,83,74,36,36,36]
y_points = [67,67,66,73,71,69,56,57,57]
import matplotlib.pyplot as plt
plt.plot(x_points, y_points, 'ro')
plt.axis([0, 160, 0, 120])
plt.show()
The goal is to indicate somehow in the plot their order. For example, a different color or a line between two points with an arrow, would indicate that (82,67) came before (92,67). How can this be done?
The generic goal is to plot a directed path on a x-y chart, given a set of input points.
You can use matplotlib.pyplot.arrow
Please see this post:
Draw arrows between 3 points
I have a 64x360 Matrix of values belonging to radial and azimuthal coordinates. I want to visualize them in two plots: a cartesian and a polar plot.
I visualized the heatmap in cartesian coordinates using imshow():
import numpy as np
import matplotlib.pyplot as plt
P=np.loadtxt('Pdata.csv')
print np.shape(P)
plt.imshow(P)
plt.xlabel('radius')
plt.ylabel('theta')
plt.show()
This gives me the desired plot:
The same plot in polar coordinates was also pretty straigh forward using pcolor():
r=np.arange(0,np.shape(P)[1],1)
t=np.arange(0,np.shape(P)[0],1)
R,T = np.meshgrid(r,t)
fig = plt.figure()
ax = fig.add_subplot(111, polar = True)
ax.pcolor(T,R,P)
plt.show()
However, I am not really satisfied with the result:
The resolution of the plot seems to be pretty limited so that it's not possible to distinguish between angles with higher intensity and lower intensity, as it is in the cartesian plot. The whole solid angle seems to be divided into six or seven "cake wedges" only. Is there an easy and pythonic way to enhance the angular resolution?
Ok, I found out something. It works with:
t = np.radians(np.linspace(0, np.shape(P)[0],np.shape(P)[0]))
r = np.arange(0, np.shape(P)[1], 1)
Just as seen here: Polar contour plot in matplotlib - best (modern) way to do it?
I would like to plot a circle on an auto-scaled pyplot-generated graphic. When I run
ax.get_aspect()
hoping for a value with which I could manipulate the axes of a ellipse, pyplot returns:
auto
which is less than useful. What methods would you suggest for plotting a circle on a pyplot plot with unequal axes?
This question is more than one year old, but I too just had this question. I needed to add circles to a matplotlib plot and I wanted to be able to specify the circle's location in the plot using data coordinates, and I didn't want the circle radius to change with panning/zooming (or worse the circle turning into an ellipse).
The best and most simple solution that I've found is simply plot a curve with a single point and include a circle marker:
ax.plot(center_x,center_y,'bo',fillstyle='none',markersize=5)
which gives a nice, fixed-size blue circle with no fill!
It really does depend what you want it for.
The problem with defining a circle in data coordinates when aspect ratio is auto, is that you will be able to resize the figure (or its window), and the data scales will stretch nicely. Unfortunately, this would also mean that your circle is no longer a circle, but an ellipse.
There are several ways of addressing this. Firstly, and most simply, you could fix your aspect ratio and then put a circle on the plot in data coordinates:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes()
ax.set_aspect(1)
theta = np.linspace(-np.pi, np.pi, 200)
plt.plot(np.sin(theta), np.cos(theta))
plt.show()
With this, you will be able to zoom and pan around as per usual, but the shape will always be a circle.
If you just want to put a circle on a figure, independent of the data coordinates, such that panning and zooming of an axes did not effect the position and zoom on the circle, then you could do something like:
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes()
patch = mpatches.Circle((325, 245), 180, alpha=0.5, transform=None)
fig.artists.append(patch)
plt.show()
This is fairly advanced mpl, but even so, I think it is fairly readable.
HTH,
Building on #user3208430, if you want the circle to always appear at the same place in the axes (regardless of data ranges), you can position it using axes coordinates via transform:
ax.plot(.94, .94, 'ro', fillstyle='full', markersize=5, transform=ax.transAxes)
Where x and y are between [0 and 1]. This example places the marker in the upper right-hand corner of the axes.