xarray 图的图例句柄
Legend handle to an xarray plot
我无法修改使用 xarray 绘图功能制作的数据集的图例。
下面的代码returnsNo handles with labels found to put in legend.
import xarray as xr
import matplotlib.pyplot as plt
air = xr.tutorial.open_dataset("air_temperature").air
air.isel(lon=10, lat=[19, 21, 22]).plot.line(x="time", add_legend=True)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
您可以使用 seaborn 的 sns.move_legend()
,然后是 plt.tight_layout()
。 sns.move_legend()
是 seaborn 0.11.2 中的新功能。
import xarray as xr
import matplotlib.pyplot as plt
import seaborn as sns
air = xr.tutorial.open_dataset("air_temperature").air
air.isel(lon=10, lat=[19, 21, 22]).plot.line(x="time", add_legend=True)
sns.move_legend(plt.gca(), loc='center left', bbox_to_anchor=(1, 0.5))
plt.tight_layout()
plt.show()
PS:如果你不想导入seaborn,你可以从its source复制函数。您需要删除对 sns.axisgrid.Grid
和 import matplotlib as mpl; import inspect
:
的引用
import matplotlib.pyplot as plt
import matplotlib as mpl
import inspect
import xarray as xr
def move_legend(obj, loc, **kwargs):
"""
Recreate a plot's legend at a new location.
Extracted from seaborn/utils.py
"""
if isinstance(obj, mpl.axes.Axes):
old_legend = obj.legend_
legend_func = obj.legend
elif isinstance(obj, mpl.figure.Figure):
if obj.legends:
old_legend = obj.legends[-1]
else:
old_legend = None
legend_func = obj.legend
else:
err = "`obj` must be a matplotlib Axes or Figure instance."
raise TypeError(err)
if old_legend is None:
err = f"{obj} has no legend attached."
raise ValueError(err)
# Extract the components of the legend we need to reuse
handles = old_legend.legendHandles
labels = [t.get_text() for t in old_legend.get_texts()]
# Extract legend properties that can be passed to the recreation method
# (Vexingly, these don't all round-trip)
legend_kws = inspect.signature(mpl.legend.Legend).parameters
props = {k: v for k, v in old_legend.properties().items() if k in legend_kws}
# Delegate default bbox_to_anchor rules to matplotlib
props.pop("bbox_to_anchor")
# Try to propagate the existing title and font properties; respect new ones too
title = props.pop("title")
if "title" in kwargs:
title.set_text(kwargs.pop("title"))
title_kwargs = {k: v for k, v in kwargs.items() if k.startswith("title_")}
for key, val in title_kwargs.items():
title.set(**{key[6:]: val})
kwargs.pop(key)
# Try to respect the frame visibility
kwargs.setdefault("frameon", old_legend.legendPatch.get_visible())
# Remove the old legend and create the new one
props.update(kwargs)
old_legend.remove()
new_legend = legend_func(handles, labels, loc=loc, **props)
new_legend.set_title(title.get_text(), title.get_fontproperties())
air = xr.tutorial.open_dataset("air_temperature").air
air.isel(lon=10, lat=[19, 21, 22]).plot.line(x="time", add_legend=True)
move_legend(plt.gca(), loc='center left', bbox_to_anchor=(1, 0.5))
plt.tight_layout()
plt.show()
我无法修改使用 xarray 绘图功能制作的数据集的图例。
下面的代码returnsNo handles with labels found to put in legend.
import xarray as xr
import matplotlib.pyplot as plt
air = xr.tutorial.open_dataset("air_temperature").air
air.isel(lon=10, lat=[19, 21, 22]).plot.line(x="time", add_legend=True)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
您可以使用 seaborn 的 sns.move_legend()
,然后是 plt.tight_layout()
。 sns.move_legend()
是 seaborn 0.11.2 中的新功能。
import xarray as xr
import matplotlib.pyplot as plt
import seaborn as sns
air = xr.tutorial.open_dataset("air_temperature").air
air.isel(lon=10, lat=[19, 21, 22]).plot.line(x="time", add_legend=True)
sns.move_legend(plt.gca(), loc='center left', bbox_to_anchor=(1, 0.5))
plt.tight_layout()
plt.show()
PS:如果你不想导入seaborn,你可以从its source复制函数。您需要删除对 sns.axisgrid.Grid
和 import matplotlib as mpl; import inspect
:
import matplotlib.pyplot as plt
import matplotlib as mpl
import inspect
import xarray as xr
def move_legend(obj, loc, **kwargs):
"""
Recreate a plot's legend at a new location.
Extracted from seaborn/utils.py
"""
if isinstance(obj, mpl.axes.Axes):
old_legend = obj.legend_
legend_func = obj.legend
elif isinstance(obj, mpl.figure.Figure):
if obj.legends:
old_legend = obj.legends[-1]
else:
old_legend = None
legend_func = obj.legend
else:
err = "`obj` must be a matplotlib Axes or Figure instance."
raise TypeError(err)
if old_legend is None:
err = f"{obj} has no legend attached."
raise ValueError(err)
# Extract the components of the legend we need to reuse
handles = old_legend.legendHandles
labels = [t.get_text() for t in old_legend.get_texts()]
# Extract legend properties that can be passed to the recreation method
# (Vexingly, these don't all round-trip)
legend_kws = inspect.signature(mpl.legend.Legend).parameters
props = {k: v for k, v in old_legend.properties().items() if k in legend_kws}
# Delegate default bbox_to_anchor rules to matplotlib
props.pop("bbox_to_anchor")
# Try to propagate the existing title and font properties; respect new ones too
title = props.pop("title")
if "title" in kwargs:
title.set_text(kwargs.pop("title"))
title_kwargs = {k: v for k, v in kwargs.items() if k.startswith("title_")}
for key, val in title_kwargs.items():
title.set(**{key[6:]: val})
kwargs.pop(key)
# Try to respect the frame visibility
kwargs.setdefault("frameon", old_legend.legendPatch.get_visible())
# Remove the old legend and create the new one
props.update(kwargs)
old_legend.remove()
new_legend = legend_func(handles, labels, loc=loc, **props)
new_legend.set_title(title.get_text(), title.get_fontproperties())
air = xr.tutorial.open_dataset("air_temperature").air
air.isel(lon=10, lat=[19, 21, 22]).plot.line(x="time", add_legend=True)
move_legend(plt.gca(), loc='center left', bbox_to_anchor=(1, 0.5))
plt.tight_layout()
plt.show()