Python & Matplotlib: how to plot ellipse? - python

I can plot ellipse like this:
from matplotlib.patches import Ellipse
import matplotlib as mpl
%matplotlib inline
from matplotlib import pyplot as plt
mean = [ 19.92977907 , 5.07380955]
width = 30
height = 1.01828848
angle = -54
ell = mpl.patches.Ellipse(xy=mean, width=width, height=height, angle = 180+angle)
fig, ax = plt.subplots()
ax.add_artist(ell)
ax.set_aspect('equal')
ax.set_xlim(-100, 100)
ax.set_ylim(-100, 100)
plt.show()
However, this requires me to set the axis data limits manually. Can it be set automatically? I mean, how to get rid of ax.set_xlim(-100, 100) and ax.set_ylim(-100, 100)?
Or, what is a good way of plotting ellipse?

You need to add the patch using add_patch, not add_artist, then the data limits will be updated properly using ax.autoscale:
from matplotlib.patches import Ellipse
import matplotlib as mpl
%matplotlib inline
from matplotlib import pyplot as plt
mean = [ 19.92977907 , 5.07380955]
width = 30
height = 1.01828848
angle = -54
ell = mpl.patches.Ellipse(xy=mean, width=width, height=height, angle = 180+angle)
fig, ax = plt.subplots()
ax.add_patch(ell)
ax.set_aspect('equal')
ax.autoscale()
plt.show()

Related

Rotate polar stereographic subplot

I am making a figure with subplots which are north polar stereographic projections. I also created a custom boundary shape to display subplot as a circle. However once reprojected, I want to be able to rotate the map, since my data is focusing on the US and thus I was hoping that each subplot would have the US facing "up," thus I would need to rotate it 270 degrees / -90 degrees.
Minimalistic code example pulled from cartopy example
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline # for notebook
map_projection = ccrs.NorthPolarStereo(central_longitude=0, )
data_projection = ccrs.PlateCarree()
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5 # by changing radius we can zoom in/out
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpl.path.Path(verts * radius + center)
plot_extent=[-179.9,180, 30, 90]
fig, ax1 = plt.subplots(1,1, figsize=(6,6), dpi=100, subplot_kw=dict(projection=map_projection))
ax1.set_boundary(circle, transform=ax1.transAxes)
ax1.coastlines(linewidths=1.0, color='grey')
ax1.add_feature(cfeature.BORDERS, linestyles='--', color='dimgrey', linewidths=0.8 )
ax1.set_extent(plot_extent, crs=ccrs.PlateCarree(),)
gl = ax1.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=1, color='gray', alpha=0.5, linestyle='--', zorder=10)
I haven't yet found any good examples or documentation for what I am trying to do, however I am new to using matplotlib/cartopy.
You need to set central_longitude=-90.
So:
map_projection = ccrs.NorthPolarStereo(central_longitude=-90)

Adding rectangles to a plot - doesn't show the right dimension [duplicate]

I'm trying to draw a rectangle in matplotlib using the following code:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig, ax = plt.subplots()
width = 20
height = 10
rect = patches.Rectangle((0,0),width, height, linewidth=4,edgecolor='r',facecolor='none')
ax.add_patch(rect)
plt.show()
Which results in:
The axes do not fit the rectangle limits in this case. I could solve it with:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig, ax = plt.subplots()
width = 20
height = 10
ax.set_xlim(0,width)
ax.set_ylim(0,height)
rect = patches.Rectangle((0,0),width, height, linewidth=4,edgecolor='r',facecolor='none')
ax.add_patch(rect)
plt.show()
This gives me the following picture which solves the problem in this case:
However, as I am trying to plot many rectangles and other shapes in the same figure, I need a way that matplotlib smartly determines the proper axes limits itself, like the way it does when plotting normal diagrams.
You are looking for .autoscale(). You may use .margins(0) to remove any extra space that is added by default.
I.e.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig, ax = plt.subplots()
width = 20
height = 10
rect = patches.Rectangle((0,0),width, height, linewidth=4,edgecolor='r',facecolor='none')
ax.add_patch(rect)
ax.margins(0)
ax.autoscale()
plt.show()

Setting the size of the scale factor on Matplotlib with very large/small scales

The following code:
import matplotlib.pyplot as plt
import numpy as np
r = 1e-20
t = np.linspace(0, 2*np.pi, 200)
fig, ax = plt.subplots()
ax.tick_params(axis='x', labelsize=8)
ax.plot(r*np.cos(t), r*np.sin(t))
Produces this:
Look at the "1e-20" on the x-axis. It isn't scaling with the rest of the tick labels. How do I change its fontsize?
Unfortunately, you will need to change the fontsize for the offset text separately:
ax.xaxis.offsetText.set_fontsize(8)

Way to change only the width of marker in scatterplot but not height?

I want to make a scatterplot with marker type as rectange (not square), such that width is more than height. With the "s" I can control the overall size of the marker but it increases in both dimension.
I can not directly pass height and width as these are unknown properties of scatter.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.scatter(np.arange(1,6), np.random.normal(size=5), marker='s', s=16)
Try the following snippet.
import numpy as np
import matplotlib.pyplot as plt
width = 60
height = 30
verts = list(zip([-width,width,width,-width],[-height,-height,height,height]))
fig, ax = plt.subplots()
ax.scatter(np.arange(1,6), np.random.normal(size=5), marker=(verts,0),s=40)
Here, the argument s changes the size of the scatter. The drawn rectangle keeps the ratio width/height.
Output:
update
Since matplotlib 3.2x, use of (verts, 0) is depreciated. The working code should be changed to
fig, ax = plt.subplots()
ax.scatter(np.arange(1,6), np.random.normal(size=5), marker=verts, s=40)

How do you scale a polygon patch in matplotlib?

In the example below, I create a rectangular patch using matplotlib.patches.Polygon. Is there a way to scale the patch before adding it to the plot?
I've tried using matplotlib.transforms.Affine2D in a variety of ways with no success. As usual, the matplotlib documentation on transformations is woefully insufficient.
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
poly = Polygon( zip(x,y), facecolor='red', edgecolor='red', alpha=0.5)
ax.add_patch(poly)
plt.show()
If by scale you mean multiplication by a factor, you can easily do this via numpy.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
scale = 2
poly = Polygon( np.c_[x,y]*scale, facecolor='red', edgecolor='red', alpha=0.5)
ax.add_patch(poly)
plt.show()
The same can be achieved with a matplotlib.transforms.Affine2D() transform.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
import matplotlib.transforms as transforms
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot([-3,3],[-3,3])
x = [-1,0,1,1,0,-1]
y = [1,1,1,-1,-1,-1]
trans = transforms.Affine2D().scale(2) + ax.transData
poly = Polygon( np.c_[x,y], facecolor='red', edgecolor='red', alpha=0.5,
transform=trans)
ax.add_patch(poly)
plt.show()
Although it seems a bit overkill for a simple scaling like this.

Categories

Resources