gpt4 book ai didi

python - matplotlib 中是否有任何方法可以获取艺术家的值(value),这是实例化此类艺术家所必需的?

转载 作者:行者123 更新时间:2023-12-05 07:06:35 24 4
gpt4 key购买 nike

我的意思是:给定一个通用 matplotlib 的实例 Artist ,是否有一种通用的方法来获取该艺术家的位置参数值以实例化另一位相同类型的艺术家?我知道有 properties - 方法,但根据我的经验,这只返回关键字参数,而不返回位置参数。

我了解到 inspect模块,我设法用它至少获得了给定艺术家类型的位置参数的名称,但我没有得到比这更进一步的信息,因为艺术家的相应属性通常有不同的名称。

import inspect
from matplotlib.lines import Line2D


artist = Line2D([0, 1], [2, 3])
sig = inspect.signature(type(artist))
args = {}
for param in sig.parameters.values():
if (
param.default == param.empty
and param.kind != inspect.Parameter.VAR_KEYWORD
):
args[param.name] = getattr(artist, param.name)

new_artist = type(artist)(**args)

最佳答案

好吧,经过无数小时的研究,陷入各种兔子洞并在相同的想法中盘旋(其中一些记录在案 here ),我终于暂时放弃了。我在这里发布的最后一种方法实际上是手动硬编码可以检索相关信息的函数,具体取决于艺术家的类型。但即使这种方法最终也失败了,因为:

  1. 使用 convenience functions应该将属性从一位艺术家复制到下一位艺术家,例如 artist.update_from() 不幸的是:

    • 要么也复制不兼容的属性,即如果您在将新艺术家添加到其他轴后运行该方法,则会引发错误
    • 或者看起来根本不复制任何属性,例如 AxesImages 就是这种情况

    这意味着您还必须想出自己的方式来单独复制此信息。这又会非常麻烦,但更重要的是:

  2. 对于某些艺术家类型,根本不可能从实例中检索所有必要的argskwargs。例如 FancyArrows 就是这种情况。 . 实际上没有任何 kwargs,只有两个用于初始化此类的 args 可以从艺术家实例本身以任何方式再次访问。这太令人沮丧了。

无论如何,这是我对复制方法进行硬编码的尝试,也许它们对其他人有用。

复制.py

from matplotlib.patches import Ellipse, Rectangle, FancyArrow
from matplotlib.text import Annotation, Text
from matplotlib.lines import Line2D
from matplotlib.image import AxesImage
from matplotlib.artist import Artist
from matplotlib.axes import Axes
from matplotlib_scalebar.scalebar import ScaleBar
from typing import Callable


def _get_ellipse_args(ellipse: Ellipse) -> list:
return [ellipse.center, ellipse.width, ellipse.height]


def _get_rectangle_args(rectangle: Rectangle) -> list:
return [rectangle.get_xy(), rectangle.get_width(), rectangle.get_height()]


def _get_fancy_arroy_args(arrow: FancyArrow) -> list:
return [*arrow.xy, arrow.dx, arrow.dy]


def _get_scalebar_args(scalebar: ScaleBar) -> list:
return [scalebar.dx]


def _get_line2d_args(line: Line2D) -> list:
return line.get_data()


def _get_text_args(text: Text) -> list:
return []


def _get_annotation_args(text: Text) -> list:
return [text.get_text(), text.xy]


class Duplicator:
_arg_fetchers = {
Line2D: _get_line2d_args,
# Ellipse: _get_ellipse_args,
Rectangle: _get_rectangle_args,
Text: _get_text_args,
Annotation: _get_annotation_args,
ScaleBar: _get_scalebar_args,
AxesImage: lambda: None,
}

def args(self, artist):
return self._arg_fetchers[type(artist)](artist)

@classmethod
def duplicate(
cls, artist: Artist, other_ax: Axes,
duplication_method: Callable = None
) -> Artist:
if duplication_method is not None:
cls._arg_fetchers[type(artist)] = duplication_method
if type(artist) in cls._arg_fetchers:
if isinstance(artist, AxesImage):
duplicate = other_ax.imshow(artist.get_array())
# duplicate.update_from(artist) has no effect on AxesImage
# instances for some reason.
# duplicate.update(artist.properties()) causes an
# AttributeError for some other reason.
# Thus it seems kwargs need to be set individually for
# AxesImages.
duplicate.set_cmap(artist.get_cmap())
duplicate.set_clim(artist.get_clim())
else:
duplicate = type(artist)(*cls.args(cls, artist))
# this unfortunately copies properties that should not be
# copied, resulting in the artist being absent in the new axes
# duplicate.update_from(artist)
other_ax.add_artist(duplicate)

return duplicate
else:
raise TypeError(
'There is no duplication method for this type of artist',
type(artist)
)

@classmethod
def can_duplicate(cls, artist: Artist) -> bool:
return type(artist) in cls._arg_fetchers

duplicate_test.py

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib.text import Annotation
from matplotlib.lines import Line2D

from duplicate import Duplicator, _get_ellipse_args


fig, (ax1, ax2, ax3) = plt.subplots(1, 3)

# determine artists that were there before we manually added some
default_artists1 = set(ax1.get_children())
default_artists2 = set(ax2.get_children())

# add several artists to ax1
ax1.add_line(Line2D([0, 1], [2, 3], lw=4, color='red'))
ax1.add_patch(Ellipse((1, 1), 1, 1))
ax1.imshow(np.random.uniform(0, 1, (10, 10)))
ax2.add_patch(Ellipse((3, 5), 2, 4, fc='purple'))
ax2.add_artist(Annotation('text', (1, 1), fontsize=20))

# set axes limits, optional, but usually necessary
for ax in [ax1, ax2]:
ax.relim()
ax.autoscale_view()

ax2.axis('square')
for ax in [ax2, ax3]:
ax.set_xlim(ax1.get_xlim())
ax.set_ylim(ax1.get_ylim())

# determine artists that were added manually
new_artists1 = set(ax1.get_children()) - default_artists1
new_artists2 = set(ax2.get_children()) - default_artists2
new_artists = new_artists1 | new_artists2

# declare our own arg fetchers for artists types that may not be
# covered by the Duplicator class
arg_fetchers = {Ellipse: _get_ellipse_args}

# duplicate artists to ax3
for artist in new_artists:
if Duplicator.can_duplicate(artist):
Duplicator.duplicate(artist, ax3)
else:
Duplicator.duplicate(artist, ax3, arg_fetchers[type(artist)])

fig.show()

enter image description here

我真的不明白为什么,虽然 matplotlib 坚持不在不同的图形/轴上重复使用同一位艺术家(这可能有一个很好的技术原因),但他们同时做到了 impossible , 如果不是至少 very awkward/hacky移动或复制艺术家。

请Matplotlib大神们介绍一下复制艺术家的标准方法

关于python - matplotlib 中是否有任何方法可以获取艺术家的值(value),这是实例化此类艺术家所必需的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62417982/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com