How to make a circle and lines outwards, please? Shape like:
I have a circle, but I do not know how to continue with lines.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig, ax1 = plt.subplots(figsize=(10,10))
circle = patches.Circle((0.45, 0.5), radius=0.13, transform=ax1.transData, clip_on=False, zorder=10, linewidth=2,
edgecolor='black', facecolor=(0, 0, 0, .0125))
ax1.patches.append(circle)
plt.show()
Sine and cosine of 16 angles can be used to create the lines:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
fig, ax1 = plt.subplots(figsize=(10, 10))
rad_circ = 0.13
rad_line_start = 0.17
rad_line_end = 0.21
xc, yc = 0.45, 0.5
circle = patches.Circle((xc, yc), radius=rad_circ, transform=ax1.transData, clip_on=False, zorder=10, linewidth=2,
edgecolor='black', facecolor='gold')
ax1.patches.append(circle)
theta = np.linspace(0, 2 * np.pi, 16, endpoint=False)
for th in theta:
ax1.plot([xc + rad_line_start * np.cos(th), xc + rad_line_end * np.cos(th)],
[yc + rad_line_start * np.sin(th), yc + rad_line_end * np.sin(th)],
color='gold', lw=10)
ax1.set_aspect('equal')
ax1.axis('off')
plt.show()
PS: To create all the line segments as a "line collection":
from matplotlib.collections import LineCollection
# ...
line_interval = np.array([[rad_line_start], [rad_line_end]])
segments = np.array([xc + np.cos(theta) * line_interval,
yc + np.sin(theta) * line_interval]).T
lc = LineCollection(segments, colors='gold', lw=10)
ax1.add_collection(lc)
Related
I am working with the following image:
from matplotlib import cbook
import matplotlib.patches as mpatches
from matplotlib.axes._base import _TransformedBoundsLocator
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np
# a numpy array of 15x15
Z = cbook.get_sample_data("axes_grid/bivariate_normal.npy", np_load=True)
gs = GridSpec(2, 3)
fig = plt.figure(figsize=(3*3,2*3))
ax1 = fig.add_subplot(gs[:2, :2])
ax2 = fig.add_subplot(gs[1, 2])
Z2 = np.zeros((150, 150))
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z
ax1.imshow(Z2)
ax1.set_aspect("equal")
ax2.set_aspect("equal")
plt.tight_layout()
plt.show()
output:
As shown in the image, the x-axis of both plots are aligned. However, when I am adding a patch to the first plot the alignment becomes distorted:
Z = cbook.get_sample_data("axes_grid/bivariate_normal.npy", np_load=True)
gs = GridSpec(2, 3)
fig = plt.figure(figsize=(3*3,2*3))
ax1 = fig.add_subplot(gs[:2, :2])
ax2 = fig.add_subplot(gs[1, 2])
Z2 = np.zeros((150, 150))
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z
ax1.imshow(Z2)
x, y, width, height = 30, 30, 15, 15
ex, ey = (0,1)
xy_data = x + ex * width, y + ey * height
p = mpatches.ConnectionPatch(
xyA=(0,1), coordsA=ax2.transAxes,
xyB=xy_data, coordsB=ax1.transData)
ax1.add_patch(p)
ax1.set_aspect("equal")
ax2.set_aspect("equal")
plt.tight_layout()
plt.show()
output:
Why is this? How can I add a patch whilst retaining the original layout?
when plotting by below code I am getting c,d,e plots but I am getting only the last plot for plt.plot
def normalize(x):
return (x - x.min(0)) / x.ptp(0)
c=sns.distplot(mk[0]['mass'], hist=True, label='p', rug=True)
d=sns.distplot(mk[1]['mass'], hist=True, label='q', rug=True)
e=sns.distplot(mk[2]['mass'], hist=True, label='r', rug=True)
datadist=[c,d,e]
xd=dict()
yd2=dict()
for i in datadist:
line = i.get_lines()[0]
xd[i] = line.get_xdata()
yd = line.get_ydata()
yd2[i] = normalize(yd)
plt.plot(xd[c], yd2[c],color='black')
plt.plot(xd[d], yd2[d],color='yellow')
plt.plot(xd[e], yd2[e],color='green')
sns.distplot() returns the ax (the subplot) on which the histogram was drawn. All 3 are drawn on the same subplot, so the return value is the same three times.
The array lines = ax1.get_lines() contains exactly 3 elements: one for each of the kde curves, so you can extract them as follows:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
def normalize(x):
return (x - x.min(0)) / x.ptp(0)
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(14, 4))
sns.distplot(np.random.randn(30) + 10, hist=True, label='p', rug=True, ax=ax1, color='black')
sns.distplot(np.random.randn(30) + 15, hist=True, label='q', rug=True, ax=ax1, color='gold')
sns.distplot(np.random.randn(30) + 20, hist=True, label='r', rug=True, ax=ax1, color='green')
for line in ax1.get_lines():
ax2.plot(line.get_xdata(), normalize(line.get_ydata()), color=line.get_color())
plt.show()
Now, if you just want the kde-curves and "normalize" them, you could use scipy.stats import gaussian_kde:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
def normalize(x):
return (x - x.min(0)) / x.ptp(0)
fig, ax = plt.subplots(figsize=(12, 4))
mk0mass = np.random.randn(30) + 10
mk1mass = np.random.randn(30) + 15
mk2mass = np.random.randn(30) + 20
all_mkmass = [mk0mass, mk1mass, mk2mass]
x = np.linspace(min([mki.min() for mki in all_mkmass]) - 2,
max([mki.max() for mki in all_mkmass]) + 2, 1000)
for mki, color in zip(all_mkmass, ['black', 'gold', 'green']):
kde = gaussian_kde(mki)
yd = normalize(kde(x))
ax.plot(x, yd, color=color)
ax.fill_between(x, 0, yd, color=color, alpha=0.3)
plt.show()
How to colour the base on y = 0.3 by the same color as the middle part of the cylinder have, please?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
def data_for_cylinder_along_z(center_x,center_y,radius,height_z):
z = np.linspace(0, height_z, 200)
theta = np.linspace(0, 2*np.pi, 200)
theta_grid, z_grid=np.meshgrid(theta, z)
x_grid = radius*np.cos(theta_grid) + center_x
y_grid = radius*np.sin(theta_grid) + center_y
return x_grid,y_grid,z_grid
fig = plt.figure(figsize=[6,5])
ax = fig.add_subplot(111, projection='3d')
ax.azim = -39
ax.elev = 15
Xc,Zc,Yc = data_for_cylinder_along_z(0,0,0.05,0.3)
ax.plot_surface(Xc, Yc, Zc, alpha=0.4, color = 'grey')
plt.show()
I try to make 3 subplot which share one colorbar and the xaxis, as already explained by spinup in
Matplotlib 2 Subplots, 1 Colorbar
Using maps (with coastlines) in the subplots, it seems that a sharex is not supported.
However, is there a way, to apply a shared axis?
import cartopy.crs as ccrs
from cartopy.mpl.geoaxes import GeoAxes
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import AxesGrid
import numpy as np
def sample_data_3d(shape):
"""Returns `lons`, `lats`, `times` and fake `data`"""
ntimes, nlats, nlons = shape
lats = np.linspace(-np.pi / 2, np.pi / 2, nlats)
lons = np.linspace(0, 2 * np.pi, nlons)
lons, lats = np.meshgrid(lons, lats)
wave = 0.75 * (np.sin(2 * lats) ** 8) * np.cos(4 * lons)
mean = 0.5 * np.cos(2 * lats) * ((np.sin(2 * lats)) ** 2 + 2)
lats = np.rad2deg(lats)
lons = np.rad2deg(lons)
data = wave + mean
times = np.linspace(-1, 1, ntimes)
new_shape = data.shape + (ntimes, )
data = np.rollaxis(data.repeat(ntimes).reshape(new_shape), -1)
data *= times[:, np.newaxis, np.newaxis]
return lons, lats, times, data
def main():
projection = ccrs.PlateCarree()
axes_class = (GeoAxes,
dict(map_projection=projection))
lons, lats, times, data = sample_data_3d((6, 73, 145))
fig = plt.figure()
axgr = AxesGrid(fig, 111, axes_class=axes_class,
nrows_ncols=(3, 1),
axes_pad=0.6,
share_all=True, #doesn't change anything
cbar_location='bottom',
cbar_mode='single',
cbar_pad=0.2,
cbar_size='3%',
label_mode='') # note the empty label_mode
for i, ax in enumerate(axgr):
ax.coastlines()
ax.add_feature(cartopy.feature.LAND, zorder=100,
edgecolor='k',facecolor='w')
ax.set_xticks(np.linspace(-180, 180, 5), crs=projection)
ax.set_yticks(np.linspace(-90, 90, 5), crs=projection)
p = ax.contourf(lons, lats, data[i, ...],
transform=projection,
cmap='RdBu')
axgr.cbar_axes[0].colorbar(p)
plt.show()
Is there any way to create a 'wavy' arrow in matplotlib / python please?
Ideally, I'd like to recreate something like the following:
To reproduce the wavy arrow from the question, you may use a line plot and a triangle
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.path as mpath
import matplotlib.patches as mpatches
fig, ax = plt.subplots()
x = np.linspace(0,9*np.pi,151)
y = np.sin(x)
ax.plot(x,y, color="gray", lw="3")
verts = np.array([[0,1],[0,-1],[2,0],[0,1]]).astype(float)*1.3
verts[:,0] += 9*np.pi
path = mpath.Path(verts)
patch = mpatches.PathPatch(path, fc='gray', ec="gray")
ax.add_patch(patch)
ax.axis("off")
ax.set_aspect("equal",'datalim')
ax.relim()
ax.autoscale_view()
plt.show()
I made a general version (function that returns a Patch for any given start and end coordinates) from the previous post snippet.
def curly_arrow(start, end, arr_size = 1, n = 5, col='gray', linew=1., width = 0.1):
xmin, ymin = start
xmax, ymax = end
dist = np.sqrt((xmin - xmax)**2 + (ymin - ymax)**2)
n0 = dist / (2 * np.pi)
x = np.linspace(0, dist, 151) + xmin
y = width * np.sin(n * x / n0) + ymin
line = plt.Line2D(x,y, color=col, lw=linew)
del_x = xmax - xmin
del_y = ymax - ymin
ang = np.arctan2(del_y, del_x)
line.set_transform(mpl.transforms.Affine2D().rotate_around(xmin, ymin, ang) + ax.transData)
ax.add_line(line)
verts = np.array([[0,1],[0,-1],[2,0],[0,1]]).astype(float) * arr_size
verts[:,1] += ymax
verts[:,0] += xmax
path = mpath.Path(verts)
patch = mpatches.PathPatch(path, fc=col, ec=col)
patch.set_transform(mpl.transforms.Affine2D().rotate_around(xmax, ymax, ang) + ax.transData)
return patch
arr_size - size of the arrow, linew - linewidth of the arrow, n - number of wiggles, width - "vertical" (latitudinal) size of the wiggles.
Example of usage:
fig, ax = plt.subplots()
ax.add_patch(curly_arrow((20, 20), (2, 10), n=10, arr_size=2))
ax.set_xlim(0,30)
ax.set_ylim(0,30)
PS. You'll also need to import:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import matplotlib as mpl