简体   繁体   English

如何在 Matplotlib 上注释 3d plot?

[英]How to annotate 3d plot on Matplotlib?

I am trying to annotate a word text on my 3d plot diagram, I know ax.text is able to plot the text on my 3d plot however, the plt.annotate does a better job at that as it arrows the text to the coordinate which is what I need. I am trying to annotate a word text on my 3d plot diagram, I know ax.text is able to plot the text on my 3d plot however, the plt.annotate does a better job at that as it arrows the text to the coordinate which是我需要的。 Is there any way to use plt.annotate to plot on a 3d diagram?有没有办法在 3d 图上使用 plt.annotate 到 plot ? I only know that it works on 2d.我只知道它适用于二维。 Do let me know of a solution.请让我知道解决方案。

plt.annotate(s='pppppp', xy=(1.5,0), xytext=(1.5,0)) //doesnt work on 3d
ax.text(1.5,0,0,'pppppp')

If you look the source code: https://matplotlib.org/3.1.1/_modules/mpl_toolkits/mplot3d/axes3d.html#Axes3D andhttps://matplotlib.org/_modules/matplotlib/axes/_axes.html#Axes , you will see that there is no ax.annotate() method for 3d plots.如果查看源代码: https://matplotlib.org/3.1.1/_modules/mpl_toolkits/mplot3d/axes3d.html#Axes3Dhttps://matplotlib.org/_modules/matxeslib/_axes. ,您将看到 3d 图没有ax.annotate()方法。 Therefore, ax.annotate() get's called as an Axes method.因此, ax.annotate() get 被称为Axes方法。 Therefore, it does not have the appropriate conversions for 3d plots.因此,它没有适合 3d 图的转换。 One way to get around this is by following this post's instructions Matplotlib: Annotating a 3D scatter plot .解决这个问题的一种方法是按照这篇文章的说明Matplotlib: Annotating a 3D scatter plot

Follows an example using the post's solutions:以下是使用帖子解决方案的示例:

from mpl_toolkits.mplot3d.proj3d import proj_transform
from matplotlib.text import Annotation
import matplotlib as mpl
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(projection="3d")

class Annotation3D(Annotation):
    '''Annotate the point xyz with text s'''

    def __init__(self, s, xyz, *args, **kwargs):
        Annotation.__init__(self,s, xy=(0,0), *args, **kwargs)
        self._verts3d = xyz        

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.xy=(xs,ys)
        Annotation.draw(self, renderer)

def annotate3D(ax, s, *args, **kwargs):
    '''add anotation text s to to Axes3d ax'''

    tag = Annotation3D(s, *args, **kwargs)
    ax.add_artist(tag)
    return tag

annotate3D(ax, "HEllo world", [1, 1, 1])
plt.show()

Here is my modification of p479h's answer.这是我对 p479h 答案的修改。

  • It exposes Annotation3D.xy for public access;它公开Annotation3D.xy以供公众访问; following Annotation.xy 's nature.遵循Annotation.xy的性质。

  • annotateND returns 2D or 3D annotation based on type of ax annotateND根据ax的类型返回 2D 或 3D 注释


from typing import Optional, Tuple, Union

from matplotlib.text import Annotation
from matplotlib import pyplot as plt
from mpl_toolkits import mplot3d as plt3d

class Annotation3D(Annotation):
    """
    Annotation for 3D axes

    Args:
        text: text to display as annotation
        xyz: annotation co-ordinates
        *args: passed to `matplotlib.text.Annotation`
        **kwargs: passed to `matplotlib.text.Annotation`
    """
    def __init__(self, text: str, xyz: Tuple[float, float, float], *args,
                 **kwargs):
        Annotation.__init__(self, text, xy=(0, 0), *args, **kwargs)

        # 3D position
        self._xyz = xyz

        # Hard-set 2D projection
        self._xy: Optional[Tuple[float, float]] = None

    @property
    def xy(self):
        if self._xy is not None:
            return self._xy
        *xy2d, _ = plt3d.proj3d.proj_transform(*self._xyz, self.axes.M)
        return xy2d

    @xy.setter
    def xy(self, val):
        # publicly set
        self._xy = val

    @xy.deleter
    def xy(self):
        self._xy = None

# replace ax.annotate(*args, **kwargs) by annotateND(ax, *args, **kwargs)
def annotateND(ax: Union[plt.Axes, plt3d.axes3d.Axes3D], text: str,
               xy: Tuple[float, ...], *args, **kwargs) -> Union[Annotation3D, Annotation]:
    """
    Add annotation to 3D axes

    Args:
        ax: target (parent) axes
        text: Annotation text
        xy: annotation co-ordinates
        *args: passed to `matplotlib.text.Annotation`
        **kwargs: passed to `matplotlib.text.Annotation`

    Returns:
        AnnotationD
    """

    if isinstance(ax, plt3d.axes3d.Axes3D):
        a = Annotation3D(text, xy, *args, **kwargs)
        ax.add_artist(a)
        return a
    return ax.annotate(text, xy, *args, **kwargs)


A step towards seamlessly replacing all ax.annotate(*args, **kwargs) with annotateND(ax, *args, **kwargs) for 2D or 3D axes.向 2D 或 3D 轴的annotateND(ax, *args, **kwargs)无缝替换所有ax.annotate(*args, **kwargs)迈出了一步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM