Reputation: 69
I'm trying to find an intelligent solution to how text / annotations are placed into a matplotlib plt so they don't over lap with the data point being annotated. Code snip below. Apologies for long dict at the top. So far I've found adjustText which looks very promising, but I can't seem to get it working in this instance. The code below uses adjust_text(), but at the moment all text is being placed together in one part of the ax and I don't understand why. If you run without adjust_text() it places text roughly where it should be, but text is overlapping the data point in places, which I want to avoid. Grateful for any help.
fig, ax = plt.subplots(figsize=(10, 8))
dl_data = {
"Center": {
"axis": (0, 0),
"tp": (0, 0),
"r": 21.37311395187889,
"colour": "#ffffff",
"text": "Center",
"fill": "solid",
"ec": "#808080",
"alignment": ("center", "center"),
},
"First": {
"r": 6.758772077825972,
"wlc": 45.681000000000004,
"text": "First",
"colour": "#FFFFFF",
"fill": "dashed",
"ec": "#808080",
"alignment": ("center", "center"),
"axis": (-68.82111180215705, -1.2642233142341064e-14),
"tp": (-68.82111180215705, -1.2642233142341064e-14),
},
"Second": {
"r": 18.979199140111263,
"wlc": 360.21000000000004,
"text": "Second",
"colour": "#FFFFFF",
"fill": "dashed",
"ec": "#808080",
"alignment": ("center", "center"),
"axis": (-34.41055590107855, 59.600831137357034),
"tp": (-34.41055590107855, 59.600831137357034),
},
"P1": {
"r": 4.779173568725037,
"wlc": 2.6,
"colour": "#92a700",
"text": "P1, £3",
"fill": "solid",
"ec": "#92a700",
"axis": (-80.83697480558055, -1.4849511367261418e-14),
"alignment": ("right", "top"),
"tp": (-87.6161483743056, -1.6094825349031936e-14),
},
"P2": {
"r": 4.779173568725037,
"wlc": 0,
"colour": "#ffba00",
"text": "P2 has a long\nName, £0\n\n",
"fill": "solid",
"ec": "#ffba00",
"axis": (-13.031791598544089, 30.17548646933409),
"alignment": ("left", "top"),
"tp": (-9.047093352116576, 24.691019844418072),
},
"P3": {
"r": 4.779173568725037,
"wlc": 0.21,
"colour": "#92a700",
"text": "P3 has a very,\nlong long long,\nname, £0 \n",
"fill": "solid",
"ec": "#92a700",
"axis": (-55.78932020361301, 30.175486469334082),
"alignment": ("right", "top"),
"tp": (-59.77401845004052, 24.691019844418065),
},
"P4": {
"r": 15.811388300841896,
"wlc": 250,
"colour": "#e77200",
"text": "P4 also\nhas a longish\nname, £250\n",
"fill": "solid",
"ec": "#e77200",
"axis": (-34.41055590107855, 95.97255740839438),
"alignment": ("center", "center"),
"tp": (-34.41055590107855, 113.78394570923628),
},
"P5": {
"r": 4.779173568725037,
"wlc": 6.6,
"colour": "#92a700",
"text": "P5 is medium,\n£7\n\n",
"fill": "solid",
"ec": "#92a700",
"axis": (-69.00212318005225, 70.8403126698613),
"alignment": ("right", "top"),
"tp": (-75.44950037768407, 72.9351925104148),
},
"P6": {
"r": 10.16857905510893,
"wlc": 103.4,
"colour": "#92a700",
"text": "P6 is a very long name\nlike P4 is also,\n£100\n",
"fill": "solid",
"ec": "#92a700",
"axis": (0.181011377895139, 70.8403126698613),
"alignment": ("left", "top"),
"tp": (11.754017782309209, 74.600610395285),
},
}
ts = []
x_list = []
y_list = []
for c in dl_data.keys():
circle = plt.Circle(
dl_data[c]["axis"], # x, y position
radius=dl_data[c]["r"],
fc=dl_data[c]["colour"], # face colour
ec=dl_data[c]["ec"], # edge colour
zorder=2,
)
ax.add_patch(circle)
x = dl_data[c]["axis"][0]
y = dl_data[c]["axis"][1]
text = dl_data[c]["text"]
if c in ["Center", "First", "Second"]:
pass
else:
ts.append(ax.text(x, y, dl_data[c]["text"]))
x_list.append(x)
y_list.append(y)
adjust_text(
ts,
x=x_list,
y=y_list,
force_points=0.1,
arrowprops=dict(arrowstyle="->", color="red"),
)
plt.axis("scaled")
plt.axis("off")
plt.show()
Upvotes: 0
Views: 836
Reputation: 30639
There are two issues:
adjust_text
must called after all drawing is completed, i.e. plt.axis("scaled")
must come before adjust_text
, see docs:Call adjust_text the very last, after all plotting (especially anything that can change the axes limits) has been done.
add_objects=objects
ts = []
x_list = []
y_list = []
objects = []
for c in dl_data.keys():
circle = plt.Circle(
dl_data[c]["axis"], # x, y position
radius=dl_data[c]["r"],
fc=dl_data[c]["colour"], # face colour
ec=dl_data[c]["ec"], # edge colour
zorder=2,
)
objects.append(circle)
ax.add_patch(circle)
x = dl_data[c]["axis"][0]
y = dl_data[c]["axis"][1]
text = dl_data[c]["text"]
if c in ["Center", "First", "Second"]:
pass
else:
ts.append(ax.text(x, y, dl_data[c]["text"].strip()))
x_list.append(x)
y_list.append(y)
plt.axis("scaled")
plt.axis("off")
adjust_text(
ts,
add_objects=objects,
arrowprops=dict(arrowstyle="->", color="red"),
)
I couldn't manage to move the P6 text away from the green and orange circles, though.
Upvotes: 2