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.