You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Arrows disappear when using cartopy transformation #175
adjust_text works great in most situations. But I'm having a small problem using it with cartopy for mapping. The results are as expected, but the arrows linking labels to markers are missing.
A minimal example and resulting figure are below. I'm probably doing something wrong, but I notice that the cartopy example in the documentation may suffer from the same issue? Any thoughts or help are greatly appreciated. Thanks!
adjustText version 1.1.1 cartopy version 0.23.0
from adjustText import adjust_text
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
lons = [-98, -100]
lats = [40, 40]
labels = ['One', 'Two']
fig = plt.figure(figsize=(12,6))
ax = plt.axes(projection=ccrs.Robinson())
ax.set_extent([-175, 175, -60, 85], crs=ccrs.Geodetic())
plt.scatter(
x=lons,
y=lats,
transform=ccrs.Geodetic()
)
texts = []
for i, label in enumerate(labels):
texts.append(
ax.text(
lons[i],
lats[i],
label,
transform=ccrs.Geodetic()
)
)
adjust_text(texts, arrowprops=dict(arrowstyle="-", color='k'), ax=ax)
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.BORDERS)
fig.canvas.draw()
plt.show()
The issue seems to come from adding the transform=ccrs.Geodetic() line to the ax.text call. If I leave that out, I see proper arrows, but of course the labels and arrows are in the wrong place, since they aren't transformed to match the axes.
Here's an example of the actual figure I'm trying to produce, where the missing-arrow problem is clearer:
Thank you for reporting this issue. I tried having a look...
These cartopy transforms are weird, I have no experience working with them. Do you have an example how to even add an arrow here that would connect your desired coordinates?
You are using ax.annotate... The issue is that adjustText just changes the coordinate of the provided Text objects, and then adds an arrow, by creating a FancyArrowPatch and adding it to the axes. This object takes a transform argument, however using it in this context gives an error: AttributeError: 'Geodetic' object has no attribute 'quick_vertices_transform'
One could rewrite it using ax.annotate, but I think there were some minor issue with that solution.юю
So I am a little stumped as to how to fix this, and I suspect that without fixing this error in cartopy I can't fix this problem here in a reasonable way.
Ah, yeah, I see the problem. I can replicate the AttributeError when I try to do the same thing by hand. I can work around the error by calling the transform directly on the positions passed to FancyArrowPatch, but the result is the same: no arrows drawn in the output.
It does seem like the solution would be to substitute annotate for separate calls to text and FancyArrowPatch. That said, if annotate causes problems elsewhere, then I guess we're stuck, alas.
Thanks for your work on the package. It's been a great help to me on many occasions!
I think I could add an argument to change the behaviour... Not sure about the best naming. But it could simply use annotate to draw the arrow, and not touch the text. I had it like that in the past... I think the issue was aesthetic - the arrows would sometimes strike through the text for some reason. Maybe it could be solved somehow.
Thanks! Yes, the new version works as expected. As you note, I do see some strikethrough. I can mess about with horizontal and vertical alignment options to the text objects, which helps a bit. In any case, it's much better than no arrows at all!
Here's my world map showing the new output. Much more legible.
You probably get a warning when running it, as it suggests you can increase the shrinkA value in arrowprops to reduce the strikethrough... But in some of them the arrow might start some distance away from the text then.
Yes, that does help. As you say, it's tricky to find the right balance between minimizing both strikethrough and the gap between texts and arrows. When the label is vertically above/below the marker, a small shrinkA is enough. When the alignment is more horizontal (like richmond or holland or "the united states" on my map), then a very large shrinkA is necessary.
Activity
Phlya commentedon May 28, 2024
Thank you for reporting this issue. I tried having a look...
These cartopy transforms are weird, I have no experience working with them. Do you have an example how to even add an arrow here that would connect your desired coordinates?
wilkens commentedon May 28, 2024
Thanks for looking into this. I'm definitely no pro with cartopy myself.
Here's code that sets the labels and arrows by hand using
ax.annotate. Seems to work OK:I don't think the annotations need both
xycoordsandtextcoords. I see the same result if I supply justxycoords. But, belt and suspenders.Phlya commentedon May 28, 2024
You are using ax.annotate... The issue is that adjustText just changes the coordinate of the provided
Textobjects, and then adds an arrow, by creating aFancyArrowPatchand adding it to the axes. This object takes atransformargument, however using it in this context gives an error:AttributeError: 'Geodetic' object has no attribute 'quick_vertices_transform'One could rewrite it using ax.annotate, but I think there were some minor issue with that solution.юю
So I am a little stumped as to how to fix this, and I suspect that without fixing this error in cartopy I can't fix this problem here in a reasonable way.
wilkens commentedon May 28, 2024
Ah, yeah, I see the problem. I can replicate the
AttributeErrorwhen I try to do the same thing by hand. I can work around the error by calling the transform directly on the positions passed toFancyArrowPatch, but the result is the same: no arrows drawn in the output.It does seem like the solution would be to substitute
annotatefor separate calls totextandFancyArrowPatch. That said, ifannotatecauses problems elsewhere, then I guess we're stuck, alas.Thanks for your work on the package. It's been a great help to me on many occasions!
Phlya commentedon May 28, 2024
I think I could add an argument to change the behaviour... Not sure about the best naming. But it could simply use annotate to draw the arrow, and not touch the text. I had it like that in the past... I think the issue was aesthetic - the arrows would sometimes strike through the text for some reason. Maybe it could be solved somehow.
wilkens commentedon May 28, 2024
That would certainly be a help to me if you're up for it. In any case, I'm grateful for all your work on the package.
wilkens commentedon May 28, 2024
Oh, and happy to help test/debug ...
Phlya commentedon May 29, 2024
Can you try the latest commit? For me the arrows work, but they don't get clipped by the text, so can strike through it...
wilkens commentedon May 29, 2024
Thanks! Yes, the new version works as expected. As you note, I do see some strikethrough. I can mess about with horizontal and vertical alignment options to the
textobjects, which helps a bit. In any case, it's much better than no arrows at all!Here's my world map showing the new output. Much more legible.

Phlya commentedon May 29, 2024
You probably get a warning when running it, as it suggests you can increase the shrinkA value in arrowprops to reduce the strikethrough... But in some of them the arrow might start some distance away from the text then.
wilkens commentedon May 29, 2024
Yes, that does help. As you say, it's tricky to find the right balance between minimizing both strikethrough and the gap between texts and arrows. When the label is vertically above/below the marker, a small
shrinkAis enough. When the alignment is more horizontal (like richmond or holland or "the united states" on my map), then a very largeshrinkAis necessary.