|
82 | 82 | # A-b-c label string |
83 | 83 | ABC_STRING = "abcdefghijklmnopqrstuvwxyz" |
84 | 84 |
|
85 | | -# Legend align options |
86 | | -ALIGN_OPTS = { |
87 | | - None: { |
88 | | - "center": "center", |
89 | | - "left": "center left", |
90 | | - "right": "center right", |
91 | | - "top": "upper center", |
92 | | - "bottom": "lower center", |
93 | | - }, |
94 | | - "left": { |
95 | | - "top": "upper right", |
96 | | - "center": "center right", |
97 | | - "bottom": "lower right", |
98 | | - }, |
99 | | - "right": { |
100 | | - "top": "upper left", |
101 | | - "center": "center left", |
102 | | - "bottom": "lower left", |
103 | | - }, |
104 | | - "top": {"left": "lower left", "center": "lower center", "right": "lower right"}, |
105 | | - "bottom": {"left": "upper left", "center": "upper center", "right": "upper right"}, |
106 | | -} |
107 | | - |
108 | | - |
109 | 85 | # Projection docstring |
110 | 86 | _proj_docstring = """ |
111 | 87 | proj, projection : \\ |
@@ -1263,148 +1239,38 @@ def _add_legend( |
1263 | 1239 | cols: Optional[Union[int, Tuple[int, int]]] = None, |
1264 | 1240 | **kwargs, |
1265 | 1241 | ): |
1266 | | - """ |
1267 | | - The driver function for adding axes legends. |
1268 | | - """ |
1269 | | - # Parse input argument units |
1270 | | - ncol = _not_none(ncols=ncols, ncol=ncol) |
1271 | | - order = _not_none(order, "C") |
1272 | | - frameon = _not_none(frame=frame, frameon=frameon, default=rc["legend.frameon"]) |
1273 | | - fontsize = _not_none(fontsize, rc["legend.fontsize"]) |
1274 | | - titlefontsize = _not_none( |
1275 | | - title_fontsize=kwargs.pop("title_fontsize", None), |
1276 | | - titlefontsize=titlefontsize, |
1277 | | - default=rc["legend.title_fontsize"], |
1278 | | - ) |
1279 | | - fontsize = _fontsize_to_pt(fontsize) |
1280 | | - titlefontsize = _fontsize_to_pt(titlefontsize) |
1281 | | - if order not in ("F", "C"): |
1282 | | - raise ValueError( |
1283 | | - f"Invalid order {order!r}. Please choose from " |
1284 | | - "'C' (row-major, default) or 'F' (column-major)." |
1285 | | - ) |
1286 | | - |
1287 | | - # Convert relevant keys to em-widths |
1288 | | - for setting in rcsetup.EM_KEYS: # em-width keys |
1289 | | - pair = setting.split("legend.", 1) |
1290 | | - if len(pair) == 1: |
1291 | | - continue |
1292 | | - _, key = pair |
1293 | | - value = kwargs.pop(key, None) |
1294 | | - if isinstance(value, str): |
1295 | | - value = units(value, "em", fontsize=fontsize) |
1296 | | - if value is not None: |
1297 | | - kwargs[key] = value |
1298 | | - |
1299 | | - # Generate and prepare the legend axes |
1300 | | - if loc in ("fill", "left", "right", "top", "bottom"): |
1301 | | - lax = self._add_guide_panel( |
1302 | | - loc, |
1303 | | - align, |
1304 | | - width=width, |
1305 | | - space=space, |
1306 | | - pad=pad, |
1307 | | - span=span, |
1308 | | - row=row, |
1309 | | - col=col, |
1310 | | - rows=rows, |
1311 | | - cols=cols, |
1312 | | - ) |
1313 | | - kwargs.setdefault("borderaxespad", 0) |
1314 | | - if not frameon: |
1315 | | - kwargs.setdefault("borderpad", 0) |
1316 | | - try: |
1317 | | - kwargs["loc"] = ALIGN_OPTS[lax._panel_side][align] |
1318 | | - except KeyError: |
1319 | | - raise ValueError(f"Invalid align={align!r} for legend loc={loc!r}.") |
1320 | | - else: |
1321 | | - lax = self |
1322 | | - pad = kwargs.pop("borderaxespad", pad) |
1323 | | - kwargs["loc"] = loc # simply pass to legend |
1324 | | - kwargs["borderaxespad"] = units(pad, "em", fontsize=fontsize) |
1325 | | - |
1326 | | - # Handle and text properties that are applied after-the-fact |
1327 | | - # NOTE: Set solid_capstyle to 'butt' so line does not extend past error bounds |
1328 | | - # shading in legend entry. This change is not noticable in other situations. |
1329 | | - kw_frame, kwargs = lax._parse_frame("legend", **kwargs) |
1330 | | - kw_text = {} |
1331 | | - if fontcolor is not None: |
1332 | | - kw_text["color"] = fontcolor |
1333 | | - if fontweight is not None: |
1334 | | - kw_text["weight"] = fontweight |
1335 | | - kw_title = {} |
1336 | | - if titlefontcolor is not None: |
1337 | | - kw_title["color"] = titlefontcolor |
1338 | | - if titlefontweight is not None: |
1339 | | - kw_title["weight"] = titlefontweight |
1340 | | - kw_handle = _pop_props(kwargs, "line") |
1341 | | - kw_handle.setdefault("solid_capstyle", "butt") |
1342 | | - kw_handle.update(handle_kw or {}) |
1343 | | - |
1344 | | - # Parse the legend arguments using axes for auto-handle detection |
1345 | | - # TODO: Update this when we no longer use "filled panels" for outer legends |
1346 | | - pairs, multi = lax._parse_legend_handles( |
| 1242 | + return plegend.UltraLegend(self).add( |
1347 | 1243 | handles, |
1348 | 1244 | labels, |
| 1245 | + loc=loc, |
| 1246 | + align=align, |
| 1247 | + width=width, |
| 1248 | + pad=pad, |
| 1249 | + space=space, |
| 1250 | + frame=frame, |
| 1251 | + frameon=frameon, |
1349 | 1252 | ncol=ncol, |
1350 | | - order=order, |
1351 | | - center=center, |
| 1253 | + ncols=ncols, |
1352 | 1254 | alphabetize=alphabetize, |
| 1255 | + center=center, |
| 1256 | + order=order, |
| 1257 | + label=label, |
| 1258 | + title=title, |
| 1259 | + fontsize=fontsize, |
| 1260 | + fontweight=fontweight, |
| 1261 | + fontcolor=fontcolor, |
| 1262 | + titlefontsize=titlefontsize, |
| 1263 | + titlefontweight=titlefontweight, |
| 1264 | + titlefontcolor=titlefontcolor, |
| 1265 | + handle_kw=handle_kw, |
1353 | 1266 | handler_map=handler_map, |
| 1267 | + span=span, |
| 1268 | + row=row, |
| 1269 | + col=col, |
| 1270 | + rows=rows, |
| 1271 | + cols=cols, |
| 1272 | + **kwargs, |
1354 | 1273 | ) |
1355 | | - title = _not_none(label=label, title=title) |
1356 | | - kwargs.update( |
1357 | | - { |
1358 | | - "title": title, |
1359 | | - "frameon": frameon, |
1360 | | - "fontsize": fontsize, |
1361 | | - "handler_map": handler_map, |
1362 | | - "title_fontsize": titlefontsize, |
1363 | | - } |
1364 | | - ) |
1365 | | - |
1366 | | - # Add the legend and update patch properties |
1367 | | - # TODO: Add capacity for categorical labels in a single legend like seaborn |
1368 | | - # rather than manual handle overrides with multiple legends. |
1369 | | - if multi: |
1370 | | - objs = lax._parse_legend_centered(pairs, kw_frame=kw_frame, **kwargs) |
1371 | | - else: |
1372 | | - kwargs.update({key: kw_frame.pop(key) for key in ("shadow", "fancybox")}) |
1373 | | - objs = [lax._parse_legend_aligned(pairs, ncol=ncol, order=order, **kwargs)] |
1374 | | - objs[0].legendPatch.update(kw_frame) |
1375 | | - for obj in objs: |
1376 | | - if hasattr(lax, "legend_") and lax.legend_ is None: |
1377 | | - lax.legend_ = obj # make first legend accessible with get_legend() |
1378 | | - else: |
1379 | | - lax.add_artist(obj) |
1380 | | - |
1381 | | - # Update legend patch and elements |
1382 | | - # WARNING: legendHandles only contains the *first* artist per legend because |
1383 | | - # HandlerBase.legend_artist() called in Legend._init_legend_box() only |
1384 | | - # returns the first artist. Instead we try to iterate through offset boxes. |
1385 | | - for obj in objs: |
1386 | | - obj.set_clip_on(False) # needed for tight bounding box calculations |
1387 | | - box = getattr(obj, "_legend_handle_box", None) |
1388 | | - for obj in guides._iter_children(box): |
1389 | | - if isinstance(obj, mtext.Text): |
1390 | | - kw = kw_text |
1391 | | - else: |
1392 | | - kw = { |
1393 | | - key: val |
1394 | | - for key, val in kw_handle.items() |
1395 | | - if hasattr(obj, "set_" + key) |
1396 | | - } # noqa: E501 |
1397 | | - if hasattr(obj, "set_sizes") and "markersize" in kw_handle: |
1398 | | - kw["sizes"] = np.atleast_1d(kw_handle["markersize"]) |
1399 | | - obj.update(kw) |
1400 | | - |
1401 | | - # Register location and return |
1402 | | - if isinstance(objs[0], mpatches.FancyBboxPatch): |
1403 | | - objs = objs[1:] |
1404 | | - obj = objs[0] if len(objs) == 1 else tuple(objs) |
1405 | | - self._register_guide("legend", obj, (loc, align)) # possibly replace another |
1406 | | - |
1407 | | - return obj |
1408 | 1274 |
|
1409 | 1275 | def _apply_title_above(self): |
1410 | 1276 | """ |
|
0 commit comments