Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing matplotlib Text: manipulate properties of child artist

I am working on an implementation of a class for inline labeling of line objects. For this purpose I have made a subclass of the Text class which as a Line2D object as an attribute. The code in my previous post was maybe a bit lengthy, so I have isolated the problem here:

from matplotlib.text import Text
from matplotlib import pyplot as plt
import numpy as np


class LineText(Text):
    def __init__(self,line,*args,**kwargs):
        x_pos = line.get_xdata().mean()
        y_pos = line.get_ydata().mean()
        Text.__init__(self,x=x_pos,y=y_pos,*args,**kwargs)
        self.line = line
    def draw(self,renderer):
        self.line.set_color(self.get_color())
        self.line.draw(renderer = renderer)
        Text.draw(self,renderer)



if __name__ == '__main__':

    x = np.linspace(0,1,20)
    y = np.linspace(0,1,20)
    ax = plt.subplot(1,1,1)
    line = plt.plot(x,y,color = 'r')[0]
    linetext = LineText(line,text = 'abc')
    ax.add_artist(linetext)
    plt.show()

The class takes the handle of a Line2D as returned from the plot function and in the .draw method, it makes some changes to the line. For illustration purposes I have here simply tried to change its colour.

After changing the colour of the line, I call the lines draw. This does however not have the expected effect. When the figure is first drawn, there seems to be a superposition of a red and a black line. As soon as the figure is resized or otherwise forced to redraw, the line changes its colour as expected. The only way I have found so far to force the figure to be drawn correctly upon opening was to add a plt.draw() before the show(). This does however feel clumsy.

Can I somehow force only the line object to be redrawn? Or am I doing it completely wrong?

Thanks in advance.

like image 566
thomas Avatar asked Nov 27 '15 15:11

thomas


1 Answers

The issue is that you're not updating the line until it is redrawn, I think this should work:

class LineText(Text):
    def __init__(self,line,*args,**kwargs):
    x_pos = line.get_xdata().mean()
    y_pos = line.get_ydata().mean()
    Text.__init__(self,x=x_pos,y=y_pos,*args,**kwargs)
    self.line = line
    self.line.set_color(self.get_color())
    plt.gca().add_artist(self.line)   # You could also pass `ax` instead of calling `plt.gca()`
    plt.gca().add_artist(self)


if __name__ == '__main__':

    x = np.linspace(0,1,20)
    y = np.linspace(0,1,20)
    ax = plt.subplot(1,1,1)
    line = plt.plot(x,y, 'r--', alpha=0.5)[0]
    linetext = LineText(line,text = 'abc')
    # ax.add_artist(linetext)     # Artist is being added in `__init__` instead                                                                                                                                                                         
    plt.show(block=False)
like image 144
DilithiumMatrix Avatar answered Nov 03 '22 00:11

DilithiumMatrix