简体   繁体   中英

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. Is there any way to use plt.annotate to plot on a 3d diagram? 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. Therefore, ax.annotate() get's called as an Axes method. Therefore, it does not have the appropriate conversions for 3d plots. One way to get around this is by following this post's instructions 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.

  • It exposes Annotation3D.xy for public access; following Annotation.xy 's nature.

  • annotateND returns 2D or 3D annotation based on type of ax


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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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