“Clean” way to use words as markers in matplotlib? And make font size and color differ?

前端 未结 2 589
逝去的感伤
逝去的感伤 2021-01-05 15:35

Suppose I have the 3x3 matrix below:

[apples 19 3.5]

[oranges 07 2.2]

[grapes 23 7.8]

Only in real life the matrix has dozens of rows, not ju

相关标签:
2条回答
  • 2021-01-05 16:13

    While looking around for a solution to the same problem, I've found one that seems a bit cleaner (or at least more in spirit to what the original question asked), namely to use TextPath:

    from matplotlib import pyplot as plt
    from matplotlib.text import TextPath
    
    data = [["peach", 1.0, 1.0], 
            ["apples", 19, 3.5], 
            ["oranges", 7, 2.2], 
            ["grapes", 23, 7.8]]
    
    max_d2 = max([d[2] for d in data]) + 1e-3
    max_d1 = max([d[1] for d in data]) + 1e-3
    
    cmap = plt.get_cmap('RdBu')
    for d in data:
        path = TextPath((0,0), d[0])
    
        # These dots are to display the weakness below, remove for the actual question
        plt.plot(d[1],d[2],'.',color='k')
    
        plt.plot(d[1],d[2],marker=path,markersize=100, color=cmap(d[2]/max_d2))
    plt.xlim([0,max_d1+5])
    plt.ylim([0,max_d2+0.5])
    

    This solution has some advantages and disadvantages of its own:

    • Main disadvantage: as the dots show, I wasn't able to properly center the text as I wanted. Instead, the required value is the bottom left of the picture.
    • Main advantage: this has no latex issue and uses a "real" marker path, which means that it can easily be used to e.g. mark line plots (not the original question, though)

    Code:

    import numpy as np
    x = np.cumsum(np.random.randn(100,5), axis=0)
    
    plt.figure(figsize=(15,5))
    for i in range(5):
        label = TextPath((0,0), str(i), linewidth=1)
        plt.plot(x[:,i], color='k')
        plt.plot(np.arange(0,len(x),5),x[::5,i], color='k', marker=label, markersize=15, linewidth=0)
    

    Doing the above via a naive loop over "text" or "annotate" would be very slow if you had many lines / markers, while this scales better.

    0 讨论(0)
  • 2021-01-05 16:20

    As you did not want to use annotate or text the next best thing is py.scatter which will accept a marker

    ``'$...$'``                    render the string using mathtext.
    

    For example

    import pylab as py
    
    data = [["peach", 1.0, 1.0], 
            ["apples", 19, 3.5], 
            ["oranges", 7, 2.2], 
            ["grapes", 23, 7.8]]
    
    for item in data:
        py.scatter(item[1], item[2], s=700*item[1], 
               c=(item[2]/10.0, 0, 1 - item[2]/10.0), 
               marker=r"$ {} $".format(item[0]), edgecolors='none' )
    
    py.show()
    

    Example

    This method has several issues

    • Using \textrm{} in the math text so that it is not italic appears to break matplotlib
    • The letters sizes need to be adjusted by hand (hence the factor of 700)

    It would probably be better to use a colormap rather than simply defining the RGB color value.

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