Matplotlib, adding text with more than one line. Adding text that can follow the curve

前端 未结 1 798
傲寒
傲寒 2021-01-06 02:06

I have added text to a plot, coded in each line, and then adjusted it look decent, increase or decrease the width, or change the placement. However, is there a way to have

1条回答
  •  难免孤独
    2021-01-06 02:57

    You can use line separators \n:

     pylab.text(1, 1.5, '$r_1 = 1.0$ AU\n' +\
                        '$r_2 = 1.524$ AU\n' +\
                        '$\\Delta \\nu = 75^{\\circ}$', fontsize = 11, color = 'r')
    

    pylab.text() uses data coordinates by default, but you can use relative positions (0,0) to the lower-left and (1,1) to the upper-right, passing the parameter transform. See this example:

    pylab.text(0.6, 0.75, 'using axis coords', transform=ax.transAxes)
    

    The parameters: verticalalignment and horizontalalignment can also help you tremendously. Suppose you want to place a texts at the very corners:

    pylab.text(1.,1.,'top-right', transform=ax.transAxes,
               horizontalalignment='right', verticalalignment='top')
    
    pylab.text(0.,0.,'bottom-left', transform=ax.transAxes,
               horizontalalignment='left', verticalalignment='bottom')
    

    enter image description here

    To automatically calculate an angle to the text depending on your data you can do the following approach:

    • detect the data closest point
    • find the a sequence near the closest point and fit a curve using this sequence (the example below uses a fourth order curve)
    • calculate the derivative at the point where you want the text placed
    • correct the direvative with ax.get_data_ratio() OBS: not needed if ax.axis('scaled') is used, for example

    This algorithm can be implemented as follows:

    def rtext(line,x,y,s, **kwargs):
        from scipy.optimize import curve_fit
        xdata,ydata = line.get_data()
        dist = np.sqrt((x-xdata)**2 + (y-ydata)**2)
        dmin = dist.min()
        TOL_to_avoid_rotation = 0.3
        if dmin > TOL_to_avoid_rotation:
            r = 0.
        else:
            index = dist.argmin()
            xs = xdata[ [index-2,index-1,index,index+1,index+2] ]
            ys = ydata[ [index-2,index-1,index,index+1,index+2] ]
            def f(x,a0,a1,a2,a3):
                return a0 + a1*x + a2*x**2 + a3*x**3
            popt, pcov = curve_fit(f, xs, ys, p0=(1,1,1,1))
            a0,a1,a2,a3 = popt
            ax = pylab.gca()
            derivative = (a1 + 2*a2*x + 3*a3*x**2)
            derivative /= ax.get_data_ratio()
            r = np.arctan( derivative )
        return pylab.text(x, y, s, rotation=np.rad2deg(r), **kwargs)
    

    The following test example shows how to use it:

    ax = pylab.subplot(111)
    thetas = np.linspace(0,6*np.pi,1000)
    i = np.arange(len(thetas))
    xdata = (1. + (3.-1.)*i/len(thetas))*np.cos(thetas)
    ydata = (1. + (3.-1.)*i/len(thetas))*np.sin(thetas)
    ax.plot(xdata, ydata, color = 'b')
    pylab.xlabel('x')
    pylab.ylabel('y')
    for x, y in zip(xdata,ydata)[::25]:
        rtext(ax.lines[0], x, y,
              '$\\alpha = \\alpha_0$', fontsize = 14, color = 'r',
              horizontalalignment='center', verticalalignment='center')
    

    enter image description here

    Changing verticalalignment='bottom'

    enter image description here

    0 讨论(0)
提交回复
热议问题