Как использовать маркер cutom в Matplotlib с текстом внутри формы? - PullRequest
1 голос
/ 19 июня 2020

Фон

В Matplotlib мы можем визуализировать строку, используя математический текст в качестве маркера, используя $ ..... $ ( Ссылка 1 )

Вопрос

Есть ли способ заключить этот текст в круглую или прямоугольную рамку angular или любую другую форму? Подобно зарегистрированному символу, как показано здесь

Я хочу использовать этот маркер на графике, как показано ниже: Text '$T$' is used in this plot, I want the text to be enclosed in a circle or rectangle

Text ' В этом графике используется $ T $ ', я хочу, чтобы текст был заключен в круг или прямоугольник.

Решение

Как было предложено в комментариях к ответу, я нарисовал квадрат маркер немного большего размера перед текстовым маркером. Это решило проблему. Окончательное значение показано ниже:

1 Ответ

2 голосов
/ 19 июня 2020

Редактировать: Самый простой способ - просто разместить патчи, которые будут желаемыми «рамками», в том же месте, что и маркеры. Просто убедитесь, что у них меньше zorder, чтобы они не покрывали точки данных.

Более сложные способы ниже:

Вы можете вносить исправления. Вот пример, который я использовал для создания собственного вопросительного знака:

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.markers as m

fig, ax = plt.subplots()
lim = -5.8, 5.7
ax.set(xlim = lim, ylim = lim)

marker_obj = m.MarkerStyle('$?$') #Here you place your letter
path = marker_obj.get_path().transformed(marker_obj.get_transform())

path._vertices = np.array(path._vertices)*8 #To make it larger
patch = mpl.patches.PathPatch(path, facecolor="cornflowerblue", lw=2)
ax.add_patch(patch)

def translate_verts(patch, i=0, j=0, z=None):
    patch._path._vertices = patch._path._vertices + [i, j]

def rescale_verts(patch, factor = 1):
    patch._path._vertices = patch._path._vertices * factor

#translate_verts(patch, i=-0.7, j=-0.1)

circ = mpl.patches.Arc([0,0], 11, 11,
                       angle=0.0, theta1=0.0, theta2=360.0,
                       lw=10, facecolor = "cornflowerblue",
                       edgecolor = "black")
ax.add_patch(circ)#One of the rings around the questionmark

circ = mpl.patches.Arc([0,0], 10.5, 10.5,
                       angle=0.0, theta1=0.0, theta2=360.0,
                       lw=10, edgecolor = "cornflowerblue")
ax.add_patch(circ)#Another one of the rings around the question mark

circ = mpl.patches.Arc([0,0], 10, 10,
                       angle=0.0, theta1=0.0, theta2=360.0,
                       lw=10, edgecolor = "black")
ax.add_patch(circ)



if __name__ == "__main__":
    ax.axis("off")
    ax.set_position([0, 0, 1, 1])
    fig.canvas.draw()
    #plt.savefig("question.png", dpi=40)
    plt.show()

Example after some more work

Редактировать, второй ответ: создание собственного патча из других патчей :

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import mpl_toolkits.mplot3d.art3d as art3d


class PlanetPatch(mpl.patches.Circle):
    """
        This class combines many patches to make a custom patch
        The best way to reproduce such a thing is to read the
        source code for all patches you plan on combining.
        Also make use of ratios as often as possible to maintain
        proportionality between patches of different sizes"""
    cz = 0
    def __init__(self, xy, radius,
                 color = None, linewidth = 20,
                 edgecolor = "black", ringcolor = "white",
                 *args, **kwargs):
        ratio = radius/6
        mpl.patches.Circle.__init__(self, xy, radius,
                                    linewidth = linewidth*ratio,
                                    color = color,
                                    zorder = PlanetPatch.cz,
                                    *args, **kwargs)
        self.set_edgecolor(edgecolor)
        xy_ringcontour = np.array(xy)+[0, radius*-0.2/6]
        self.xy_ringcontour = xy_ringcontour - np.array(xy)
        self.ring_contour = mpl.patches.Arc(xy_ringcontour,
                                15*radius/6, 4*radius/6,
                                angle =10, theta1 = 165,
                                theta2 = 14.5,
                                fill = False, 
                                linewidth = 65*linewidth*ratio/20,
                                zorder = 1+PlanetPatch.cz)

        self.ring_inner = mpl.patches.Arc(xy_ringcontour,
                                 15*radius/6, 4*radius/6,
                                 angle = 10, theta1 = 165 ,
                                 theta2 = 14.5,fill = False,
                                 linewidth = 36*linewidth*ratio/20,
                                 zorder = 2+PlanetPatch.cz)

        self.top = mpl.patches.Wedge([0,0], radius, theta1 = 8,
                                     theta2 = 192,
                                     zorder=3+PlanetPatch.cz)
        self.xy_init = xy
        self.top._path._vertices=self.top._path._vertices+xy

        self.ring_contour._edgecolor = self._edgecolor
        self.ring_inner.set_edgecolor(ringcolor)
        self.top._facecolor = self._facecolor

    def add_to_ax(self, ax):
        ax.add_patch(self)
        ax.add_patch(self.ring_contour)
        ax.add_patch(self.ring_inner)
        ax.add_patch(self.top)


    def translate(self, dx, dy):
        self._center = self.center + [dx,dy]
        self.ring_inner._center = self.ring_inner._center +[dx, dy]
        self.ring_contour._center = self.ring_contour._center + [dx,dy]
        self.top._path._vertices = self.top._path._vertices + [dx,dy]

    def set_xy(self, new_xy):
        """As you can see all patches have different ways
            to have their positions updated"""
        new_xy = np.array(new_xy)
        self._center = new_xy
        self.ring_inner._center = self.xy_ringcontour + new_xy
        self.ring_contour._center = self.xy_ringcontour + new_xy
        self.top._path._vertices += new_xy - self.xy_init 

fig  = plt.figure(figsize=(6, 6))
ax = fig.add_subplot()
lim = -8.5, 8.6
ax.set(xlim = lim, ylim = lim,
       facecolor = "black")
planets = []
colors = mpl.colors.cnames
colors = [c for c in colors]
for x in range(100):
    xy = np.random.randint(-7, 7, 2)
    r = np.random.randint(1, 15)/30
    color = np.random.choice(colors)
    planet = PlanetPatch(xy, r, linewidth = 20,
                         color = color,
                         ringcolor = np.random.choice(colors),
                         edgecolor = np.random.choice(colors))
    planet.add_to_ax(ax)
    planets.append(planet)


fig.canvas.draw()
#plt.savefig("planet.png", dpi=10)
plt.show()

enter image description here

...