what is the right way to draw an arrow that loops back to point to its origin in matplotlib? i tried:
plt.figure()
plt.xlim([0, 1])
plt.ylim([0, 1])
plt.annotate("", xy=(0.6, 0.9),
xycoords="figure fraction",
xytext = (0.6, 0.8),
textcoords="figure fraction",
fontsize = 10, \
color = "k",
arrowprops=dict(edgecolor='black',
connectionstyle="angle,angleA=-180,angleB=45",
arrowstyle = '<|-',
facecolor="k",
linewidth=1,
shrinkA = 0,
shrinkB = 0))
plt.show()
this doesn't give the right result:
the connectionstyle arguments are hard to follow from this page (http://matplotlib.org/users/annotations_guide.html).
i'm looking for is something like this or this:
update: the answer linked to does not show how do this with plt.annotate which has other features i want to use. the proposal to use $\circlearrowleft$ marker is not a real solution.
It seems the easiest way to create an easily modifiable looping arrow is to use patches. I've pasted code to do this below. Change the variables in the variables section and things should all rotate and scale together. You can play around with the patch that creates the arrow head to make a different shape though I suspect that this triangle will be the easiest one.
%matplotlib inline
# from __future__ import division #Uncomment for python2.7
import matplotlib.pyplot as plt
from matplotlib.patches import Arc, RegularPolygon
import numpy as np
from numpy import radians as rad
fig = plt.figure(figsize=(9,9))
ax = plt.gca()
def drawCirc(ax,radius,centX,centY,angle_,theta2_,color_='black'):
#========Line
arc = Arc([centX,centY],radius,radius,angle=angle_,
theta1=0,theta2=theta2_,capstyle='round',linestyle='-',lw=10,color=color_)
ax.add_patch(arc)
#========Create the arrow head
endX=centX+(radius/2)*np.cos(rad(theta2_+angle_)) #Do trig to determine end position
endY=centY+(radius/2)*np.sin(rad(theta2_+angle_))
ax.add_patch( #Create triangle as arrow head
RegularPolygon(
(endX, endY), # (x,y)
3, # number of vertices
radius/9, # radius
rad(angle_+theta2_), # orientation
color=color_
)
)
ax.set_xlim([centX-radius,centY+radius]) and ax.set_ylim([centY-radius,centY+radius])
# Make sure you keep the axes scaled or else arrow will distort
drawCirc(ax,1,1,1,0,250)
drawCirc(ax,2,1,1,90,330,color_='blue')
plt.show()
I find no way to make a loop using plt.annotate only once, but using it four times works :
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
# coordinates of the center of the loop
x_center = 0.5
y_center = 0.5
radius = 0.2
# linewidth of the arrow
linewidth = 1
ax.annotate("", (x_center + radius, y_center), (x_center, y_center + radius),
arrowprops=dict(arrowstyle="-",
shrinkA=10, # creates a gap between the start point and end point of the arrow
shrinkB=0,
linewidth=linewidth,
connectionstyle="angle,angleB=-90,angleA=180,rad=10"))
ax.annotate("", (x_center, y_center - radius), (x_center + radius, y_center),
arrowprops=dict(arrowstyle="-",
shrinkA=0,
shrinkB=0,
linewidth=linewidth,
connectionstyle="angle,angleB=180,angleA=-90,rad=10"))
ax.annotate("", (x_center - radius, y_center), (x_center, y_center - radius),
arrowprops=dict(arrowstyle="-",
shrinkA=0,
shrinkB=0,
linewidth=linewidth,
connectionstyle="angle,angleB=-90,angleA=180,rad=10"))
ax.annotate("", (x_center, y_center + radius), (x_center - radius, y_center),
arrowprops=dict(arrowstyle="-|>",
facecolor="k",
linewidth=linewidth,
shrinkA=0,
shrinkB=0,
connectionstyle="angle,angleB=180,angleA=-90,rad=10"))
plt.show()
Try this:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlim(1,3)
ax.set_ylim(1,3)
ax.plot([2.5],[2.5],marker=r'$\circlearrowleft$',ms=100)
plt.show()
My suggestion uses just the plot command
import matplotlib.pyplot as plt
import numpy as np
def circarrowdraw(x0, y0, radius=1, aspect=1, direction=270, closingangle=-330,
arrowheadrelativesize=0.3, arrowheadopenangle=30, *args):
"""
Circular arrow drawing. x0 and y0 are the anchor points.
direction gives the angle of the circle center relative to the anchor
in degrees. closingangle indicates how much of the circle is drawn
in degrees with positive being counterclockwise and negative being
clockwise. aspect is important to make the aspect of the arrow
fit the current figure.
"""
xc = x0 + radius * np.cos(direction * np.pi / 180)
yc = y0 + aspect * radius * np.sin(direction * np.pi / 180)
headcorrectionangle = 5
if closingangle < 0:
step = -1
else:
step = 1
x = [xc + radius * np.cos((ang + 180 + direction) * np.pi / 180)
for ang in np.arange(0, closingangle, step)]
y = [yc + aspect * radius * np.sin((ang + 180 + direction) * np.pi / 180)
for ang in np.arange(0, closingangle, step)]
plt.plot(x, y, *args)
xlast = x[-1]
ylast = y[-1]
l = radius * arrowheadrelativesize
headangle = (direction + closingangle + (90 - headcorrectionangle) *
np.sign(closingangle))
x = [xlast +
l * np.cos((headangle + arrowheadopenangle) * np.pi / 180),
xlast,
xlast +
l * np.cos((headangle - arrowheadopenangle) * np.pi / 180)]
y = [ylast +
aspect * l * np.sin((headangle + arrowheadopenangle) * np.pi / 180),
ylast,
ylast +
aspect * l * np.sin((headangle - arrowheadopenangle) * np.pi / 180)]
plt.plot(x, y, *args)
To test it:
plt.figure()
plt.plot(np.arange(10)**2, 'b.')
bb = plt.gca().axis()
asp = (bb[3] - bb[2]) / (bb[1] - bb[0])
circarrowdraw(6, 36 , radius=0.4, aspect=asp, direction=90)
plt.grid()
plt.show()
Another possibility is to use tikz to generate the figure:
\documentclass {minimal}
\usepackage {tikz}
\begin{document}
\usetikzlibrary {arrows}
\begin {tikzpicture}[scale=1.8]
\draw[-angle 90, line width=5.0mm, rounded corners=20pt]
(0.25,0)-- (1.0, 0.0) -- (1.0, -3.0) -- (-3.0, -3.0) -- (-3.0, 0) --(-1,0);
\end{tikzpicture}
\end{document}
This is the result:
there is a pgf/tikz backend in matplotlib that you could generate your matplotlib output to tikz code that pdflatex or lualatex can process.
So this way, I think, you could insert seamlessly the looparrow figure in
your matplotlib figure.
See for ex:
http://matplotlib.org/users/whats_new.html#pgf-tikz-backend
#Aguy's answer is useful if you want a smooth arc instead of a complete circle. In Aguy's answer an arrow head is drawn line by line, but instead a FancyArrowPatch can be used. This gives a full arrow head, which might be more suitable. Below gives the code with the FancyArrowPatch arrow head.
def circarrowdraw(x0, y0, radius=1, aspect=1, direction=270, closingangle=-330, rotate_head = 0.0, color='b', *args):
"""
Circular arrow drawing. x0 and y0 are the anchor points.
direction gives the angle of the circle center relative to the anchor
in degrees. closingangle indicates how much of the circle is drawn
in degrees with positive being counterclockwise and negative being
clockwise. aspect is important to make the aspect of the arrow
fit the current figure. rotate_head is used to rotate the arrow head
by increasing the y value of the arrow's tail coordinate.
"""
# Center of circle
xc = x0 + radius * np.cos(direction * np.pi / 180)
yc = y0 + aspect * radius * np.sin(direction * np.pi / 180)
# Draw circle
if closingangle < 0:
step = -1
else:
step = 1
x = [xc + radius * np.cos((ang + 180 + direction) * np.pi / 180)
for ang in np.arange(0, closingangle, step)]
y = [yc + aspect * radius * np.sin((ang + 180 + direction) * np.pi / 180)
for ang in np.arange(0, closingangle, step)]
plt.plot(x, y, *args, color=color)
# Draw arrow head
arc_arrow_head = patches.FancyArrowPatch((x[-1], y[-1] + rotate_head),
(x[0], y[0]),
arrowstyle="Simple,head_width=10,head_length=10,tail_width=0.01",
color = color,
zorder = 10)
plt.gca().add_patch(arc_arrow_head)
To test it:
plt.plot([0, 0, 1, 1, 0], [0, 1, 1, 0, 0])
circarrowdraw(1.0, 1.0 , radius=0.1, aspect=0.3, direction=90, closingangle=-345, rotate_head = 0.003)
circarrowdraw(0.0, 1.0 , radius=0.1, aspect=1, direction=-90, closingangle=-345, rotate_head = 0.0)
circarrowdraw(0.0, 0.0 , radius=0.1, aspect=3.0, direction=90, closingangle=-345, rotate_head = 0.01)
circarrowdraw(1.0, 0.0 , radius=0.1, aspect=0.3, direction=-90, closingangle=-345)
plt.show()
Picture of image (I don't have a high enough reputation to embed the image in my answer)
Related
I try to plot a pattern with overlapping squares using matplotlib.pyplot. I am not sure how to get all squares of the same size.
Here is my code:
import matplotlib.pyplot as plt
plt.plot([2.2,2.2,3.5,3.5,2.2],[4.1,2.5,2.5,4.1,4.1],linestyle='solid',color="red")
plt.plot([3.2,4.2,4.2,3.2,3.2],[3.2,3.2,4.5,4.5,3.2],linestyle='solid',color="blue")
plt.plot([2.5,2.5,3.8,3.8,2.5],[1.8,3.8,3.8,1.8,1.8],linestyle='solid',color="green")
plt.plot([3.6,4.8,4.8,4.8,3.6,3.6],[2.2,2.2,0,0,0,2.2],linestyle='solid',color="black")
plt.title('square pattern')
Here is some code to draw 4 squares of the same size. The squares are represented by their lower left position. You can change these coordinates to easily position each square.
import matplotlib.pyplot as plt
from math import sqrt
colors = [ 'crimson', 'dodgerblue', 'limegreen', 'black']
side = 2
square1 = [1, 1.3]
square2 = [2.1, 0.5]
square3 = [1.3, 1.6]
square4 = [1.7, 2.8]
squares = [square1, square2, square3, square4]
for square, col in zip(squares, colors):
x = square[0]
y = square[1]
plt.plot([x, x + side, x + side, x, x],
[y, y, y + side, y + side, y],
color=col, linestyle='solid')
plt.title('square pattern')
plt.gca().set_aspect('equal')
plt.show()
Here is a way to get squares of all the same size, with the sum of the area of the rectangles equal to the sum of the areas of the squares. And with each square having the same center as the rectangle.
The area of each rectangle is width x height. Dividing the sum of the areas by the number of rectangles finds the average area. The side of a square with this area is its square root.
Code to calculate and draw the squares. The original rectangles are drawn lighter for comparison.
import matplotlib.pyplot as plt
from math import sqrt
colors = [ 'crimson', 'dodgerblue', 'limegreen', 'black']
rect1 = [[2.2,2.2,3.5,3.5,2.2],[4.1,2.5,2.5,4.1,4.1]]
rect2 = [[3.2,4.2,4.2,3.2,3.2],[3.2,3.2,4.5,4.5,3.2]]
rect3 = [[2.5,2.5,3.8,3.8,2.5],[1.8,3.8,3.8,1.8,1.8]]
rect4 = [[3.6,4.8,4.8,4.8,3.6,3.6],[2.2,2.2,0,0,0,2.2]]
rects = [rect1, rect2, rect3, rect4]
total_area = 0
for rect in rects:
width = max(rect[0]) - min(rect[0])
height = max(rect[1]) - min(rect[1])
total_area += width * height
square_side = sqrt(total_area / len(rects))
half = square_side / 2
for rect, col in zip(rects, colors):
center_x = (max(rect[0]) + min(rect[0])) / 2
center_y = (max(rect[1]) + min(rect[1])) / 2
plt.plot(rect[0], rect[1], color=col, linestyle='solid', alpha=0.2)
plt.plot([center_x - half, center_x - half, center_x + half, center_x + half, center_x - half],
[center_y + half, center_y - half, center_y - half, center_y + half, center_y + half],
color=col, linestyle='solid')
plt.title('square pattern')
plt.gca().set_aspect('equal')
plt.show()
I have a rectangular frame and a circle with center and radius randomly generated. The center is always located within the limits of the frame, as shown:
I need to estimate the area of the fraction of the circle that is located within the frame. Currently I employ a simple Monte Carlo estimate that works ok, but I'd like to compare this with an exact geometric estimation of this area.
Is there a library and/or method to do this? I'm open to pretty much anything that can be installed with conda or pip.
import numpy as np
import matplotlib.pyplot as plt
def circFrac(cx, cy, rad, x0, x1, y0, y1, N_tot=100000):
"""
Use Monte Carlo to estimate the fraction of the area of a circle centered
in (cx, cy) with a radius of 'rad', that is located within the frame given
by the limits 'x0, x1, y0, y1'.
"""
# Source: https://stackoverflow.com/a/50746409/1391441
r = rad * np.sqrt(np.random.uniform(0., 1., N_tot))
theta = np.random.uniform(0., 1., N_tot) * 2 * np.pi
xr = cx + r * np.cos(theta)
yr = cy + r * np.sin(theta)
# Points within the circle that are within the frame.
msk_xy = (xr > x0) & (xr < x1) & (yr > y0) & (yr < y1)
# The area is the points within circle and frame over the points within
# circle.
return msk_xy.sum() / N_tot
for _ in range(10):
# Random (x, y) limits of the frame
x0, y0 = np.random.uniform(0., 500., 2)
x1, y1 = np.random.uniform(500., 1000., 2)
# Random center coordinates *always* within the frame
cx = np.random.uniform(x0, x1)
cy = np.random.uniform(y0, y1)
# Random radius
rad = np.random.uniform(10., 500)
frac = circFrac(cx, cy, rad, x0, x1, y0, y1)
plt.xlim(x0, x1)
plt.ylim(y0, y1)
circle = plt.Circle((cx, cy), rad, fill=False)
plt.gca().add_artist(circle)
plt.scatter(
cx, cy, marker='x', c='r', label="({:.0f}, {:.0f}), r={:.0f}".format(
cx, cy, rad))
plt.legend()
plt.title("Fraction of circle inside frame: {:.2f}".format(frac))
plt.axes().set_aspect('equal')
plt.show()
You can use shapely for that:
import shapely.geometry as g
xr,yr,r = 0,0,5
circle = g.Point(xr,yr).buffer(r)
x1,y1,x2,y2 = -1,-2,3,5
rectangle = g.Polygon([(x1,y1),(x1,y2),(x2,y2),(x2,y1)])
intersection = rectangle.intersection(circle)
intersection.area
This question already has answers here:
Best way to plot an angle between two lines in Matplotlib
(5 answers)
Closed 3 years ago.
This is my code for making lines on a graph in a xy plane. I want to show an arc for each line with angle representing on it.
sim_score =[0.993832,0.543218,0.234745 ,0.873513,0.234565,0.789212]
plt.figure()
for i in sim_score:
for j in sim_label:
a= math.acos(i)
b = a * 180 / math.pi
point=(0,0)
x,y = point
length=10
# find the end point
endy = length * math.sin(math.radians(b))
endx = length * math.cos(math.radians(b))
# plot the points
ax = plt.subplot(111)
# set the bounds to be 10, 10
ax.set_ylim([0, 10])
ax.set_xlim([0, 10])
ax.plot([x, endx], [y,endy] )
I want to make arc with angle representing on it as a label.
following this post, i have adapted the code source to have a good basis:
import matplotlib.pyplot as plt
from matplotlib.patches import Arc
from matplotlib.lines import Line2D
import math
def get_angle_text(angle_plot):
angle = angle_plot.get_label()[:-1] # Excluding the degree symbol
angle = "%0.2f" % float(angle) + u"\u00b0" # Display angle upto 2 decimal places
# Set the label position
x_width = angle_plot.width / 2
y_width = math.sin(math.radians(angle_plot.theta2))
return [x_width, y_width, angle]
def get_angle_plot(line1, offset=1, color=None, origin=[0, 0], len_x_axis=1, len_y_axis=1):
l1xy = line1.get_xydata()
# Angle between line1 and x-axis
slope = (l1xy[1][1] - l1xy[0][1]) / float(l1xy[1][0] - l1xy[0][0])
angle = abs(math.degrees(math.atan(slope))) # Taking only the positive angle
if color is None:
color = line1.get_color() # Uses the color of line 1 if color parameter is not passed.
return Arc(origin, len_x_axis * offset, len_y_axis * offset, 0, 0, angle, color=color,
label=str(angle) + u"\u00b0")
sim_score = [0.993832, 0.543218, 0.234745, 0.873513]
fig = plt.figure()
ax = fig.add_subplot(111)
offset = 0
for i in sim_score:
offset += 2 # you play with this value to draw arc spaced from the previous
a = math.acos(i)
b = a * 180 / math.pi
point = (0, 0)
x, y = point
length = 10
# find the end point
endy = length * math.sin(math.radians(b))
endx = length * math.cos(math.radians(b))
line = Line2D([x, endx], [y, endy], linewidth=1, linestyle="-", color="blue")
angle_plot = get_angle_plot(line, offset)
angle_text = get_angle_text(angle_plot)
ax.add_line(line )
ax.add_patch(angle_plot)
ax.text(*angle_text) # To display the angle value
ax.set_ylim([0, 10])
ax.set_xlim([0, 10])
plt.show()
you should adapt the program to place the label, i have just done a quick calculus of position
graph result:
I'm trying to plot a Chord diagram using Matplotlib. I am aware that already existing libraries, such as Plotly give me that functionality but I would really like to do it in matplotlib.
The code I have so far looks like this:
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig, ax = plt.subplots()
ax.axhline(0, color='black', linestyle='--')
ax.axvline(0, color='black', linestyle='--')
npoints = 3
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the arcs
numbers = [i for i in xrange(npoints)]
for i, j in itertools.product(numbers, repeat=2):
if i == j:
continue
x1y1 = x1, y1 = verts[i]
x2y2 = x2, y2 = verts[j]
# Calculate the centre of the Arc
mxmy = mx, my = [(x1 + x2) / 2, (y1 + y2) / 2]
r = np.sqrt((x1 - mx)**2 + (y1 - my)**2)
xy = [mx - r, my - r]
width = 2 * r
height = 2 * r
start_angle = np.arctan2(y1 - my, x1 - mx) * 180 / np.pi
end_angle = np.arctan2(y2 - my, x2 - mx) * 180 / np.pi
arc = patches.Arc(mxmy, width, height, start_angle, end_angle)
ax.add_patch(arc)
# Plot the points
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.annotate("1", (x[0], y[0]), xytext=(x[0] + .5, y[0] + .5))
ax.annotate("2", (x[1], y[1]), xytext=(x[1] - 1, y[1] + .5))
ax.annotate("3", (x[2], y[2]), xytext=(x[2] - 1, y[2] - 1))
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
Is anyone able to tell me why my plot looks like this?
I'm expecting something more like the following (image taken from Plotly)
Edit 1
I would like to draw arcs between the following points:
1 and 2
1 and 3
2 and 3
These arcs should ideally be on the inside.
Edit 2
After some further investigation I figured that the end_angle seems to be the root of the problem.
After #f5r5e5d pointing out the Bézier curve used in plotly, I've decided to give this one a go. It looks like this is the way to go in my case, too.
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
import sys
%matplotlib inline
fig, ax = plt.subplots()
npoints = 5
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the Bezier curves
numbers = [i for i in xrange(npoints)]
bezier_path = np.arange(0, 1.01, 0.01)
for a, b in itertools.product(numbers, repeat=2):
if a == b:
continue
x1y1 = x1, y1 = verts[a]
x2y2 = x2, y2 = verts[b]
xbyb = xb, yb = [0, 0]
# Compute and store the Bezier curve points
x = (1 - bezier_path)** 2 * x1 + 2 * (1 - bezier_path) * bezier_path * xb + bezier_path** 2 * x2
y = (1 - bezier_path)** 2 * y1 + 2 * (1 - bezier_path) * bezier_path * yb + bezier_path** 2 * y2
ax.plot(x, y, 'k-')
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
The code above plots what I wanted it do to. Some modifications on the style and it should be good to go.
Since the underlying problem was "how can I draw a chord diagram in matplotlib", I just want to let you know that there is now a python library to do that: mpl-chord-diagram.
You can just do pip install mpl-chord-diagram.
[disclaimer] I am the current maintainer [/disclaimer]
I asked earlier on the matplotlib-user mailing list so apologies for the cross-post.
Say I have a marker with a known size in points and I want to draw an arrow to this point. How can I get the ends points for the arrow? As you can see in the below, it overlaps the markers. I want to go to the edge. I can use shrinkA and shrinkB to do what I want, but I don't see how they're related to the points size**.5. Or should I somehow do the transformation using the known angle between the two points and the point itself. I don't know how to translate a point in data coordinates and the offset it in a certain direction by size**.5 points. Can anyone help clear this up?
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
point1 = (138.21, 19.5)
x1, y1 = point1
point2 = (67.0, 30.19)
x2, y2 = point2
size = 700
fig, ax = plt.subplots()
ax.scatter(*zip(point1, point2), marker='o', s=size)
# if I need to get and use the angles
dx = x2 - x1
dy = y2 - y1
d = np.sqrt(dx**2 + dy**2)
arrows = FancyArrowPatch(posA=(x1, y1), posB=(x2, y2),
color = 'k',
arrowstyle="-|>",
mutation_scale=700**.5,
connectionstyle="arc3")
ax.add_patch(arrows)
Edit: I made a little more progress. If I read the Translations Tutorial correctly, then this should give me a point on the radius of the markers. However, as soon as you resize the Axes then the transformation will be off. I'm stumped on what else to use.
from matplotlib.transforms import ScaledTranslation
# shift size points over and size points down so you should be on radius
# a point is 1/72 inches
dpi = ax.figure.get_dpi()
node_size = size**.5 / 2. # this is the radius of the marker
offset = ScaledTranslation(node_size/dpi, -node_size/dpi, fig.dpi_scale_trans)
shadow_transform = ax.transData + offset
ax.plot([x2], [y2], 'o', transform=shadow_transform, color='r')
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
from matplotlib.transforms import ScaledTranslation
point1 = (138.21, 19.5)
x1, y1 = point1
point2 = (67.0, 30.19)
x2, y2 = point2
size = 700
fig, ax = plt.subplots()
ax.scatter(*zip(point1, point2), marker='o', s=size)
# if I need to get and use the angles
dx = x2 - x1
dy = y2 - y1
d = np.sqrt(dx**2 + dy**2)
arrows = FancyArrowPatch(posA=(x1, y1), posB=(x2, y2),
color = 'k',
arrowstyle="-|>",
mutation_scale=700**.5,
connectionstyle="arc3")
ax.add_patch(arrows)
# shift size points over and size points down so you should be on radius
# a point is 1/72 inches
def trans_callback(event):
dpi = fig.get_dpi()
node_size = size**.5 / 2. # this is the radius of the marker
offset = ScaledTranslation(node_size/dpi, -node_size/dpi, fig.dpi_scale_trans)
shadow_transform = ax.transData + offset
arrows.set_transform(shadow_transform)
cid = fig.canvas.mpl_connect('resize_event', trans_callback)
You also need to include something about the aspect ratio of the axes get points on the rim of the point (because the shape of the marker in data units in an ellipse unless the aspect ratio = 1)