1

I'm trying to add the curved text to the Gauge plot using matplotlib in python

import os, sys
import matplotlib
import seaborn as sns
from matplotlib import cm
# from matplotlib import pyplot as plt
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
from matplotlib.patches import Circle, Wedge, Rectangle


# below some functions to deal with some basic trigonometry that we'll be using 
# to draw the wedges (i.e. the sectors of the gauge) and to point the arrow to the right sector


def degree_range(n): 
    start = np.linspace(0,180,n+1, endpoint=True)[0:-1]
    end = np.linspace(0,180,n+1, endpoint=True)[1::]
    mid_points = start + ((end-start)/2.)
    return np.c_[start, end], mid_points

def rot_text(ang): 
    rotation = np.degrees(np.radians(ang) * np.pi / np.pi - np.radians(90))
    return rotation


def gauge(labels=['LOW','MEDIUM','HIGH','VERY HIGH','EXTREME'],
          colors='jet_r', 
          arrow=1, 
          title='',
          size = (6,3), 
          fname=False): 
    

    
    N = len(labels)
    
    if arrow > N: 
        raise Exception("\n\nThe category ({}) is greated than \
        the length\nof the labels ({})".format(arrow, N))
 
    
    """
    if colors is a string, we assume it's a matplotlib colormap
    and we discretize in N discrete colors 
    """
    
    if isinstance(colors, str):
        cmap = cm.get_cmap(colors, N)
        cmap = cmap(np.arange(N))
        colors = cmap[::-1,:].tolist()
    if isinstance(colors, list): 
        if len(colors) == N:
            colors = colors[::-1]
        else: 
            raise Exception("\n\nnumber of colors {} not equal \
            to number of categories{}\n".format(len(colors), N))

    """
    begins the plotting
    """
    
    fig, ax = plt.subplots(figsize=size, dpi=100) # figsize=(5,5)

    ang_range, mid_points = degree_range(N)

    labels = labels[::-1]
    
    """
    plots the sectors and the arcs
    """
    patches = []
    for ang, c in zip(ang_range, colors): 
        # sectors
        patches.append(Wedge((0.,0.), .4, *ang, facecolor='w', lw=2))
        # arcs
        patches.append(Wedge((0.,0.), .4, *ang, width=0.10, facecolor=c, lw=2, alpha=0.5))
    
    [ax.add_patch(p) for p in patches]

    
    """
    set the labels (e.g. 'LOW','MEDIUM',...)
    """

    for mid, lab in zip(mid_points, labels): 

        ax.text(0.35 * np.cos(np.radians(mid)), 
                0.35 * np.sin(np.radians(mid)), 
                lab,
                horizontalalignment='center', 
                verticalalignment='center', 
                fontsize=8,
                fontweight='bold', 
                rotation = rot_text(mid))

    """
    set the bottom banner and the title
    """
    r = Rectangle((-0.4,-0.1),0.8,0.1, facecolor='w', lw=2)
    ax.add_patch(r)
    
    ax.text(0, 
            -0.05, 
            title, 
            horizontalalignment='center',
            verticalalignment='center', 
            fontsize=14, 
            fontweight='bold')

    """
    plots the arrow now
    """
    
    pos = mid_points[abs(arrow - N)]
    
    ax.arrow(0, 
             0, 
             0.225 * np.cos(np.radians(pos)), 
             0.225 * np.sin(np.radians(pos)),
             width=0.04, 
             head_width=0.09, 
             head_length=0.1, 
             fc='k', 
             ec='k')
    
    ax.add_patch(Circle((0, 0), radius=0.02, facecolor='k'))
    ax.add_patch(Circle((0, 0), radius=0.01, facecolor='w', zorder=11))

    """
    removes frame and ticks, and makes axis equal and tight
    """
    
    ax.set_frame_on(False)
    ax.axes.set_xticks([])
    ax.axes.set_yticks([])
    ax.axis('equal')
    plt.tight_layout()
    if fname:
        fig.savefig(fname, dpi=200)




gauge(labels=['LOW','MEDIUM','HIGH','VERY HIGH','EXTREME','CRITICAL'], \
      colors=["#5F4690","#1D6996","#38A6A5","#0F8554","#73AF48","#EDAD08"], arrow=3, size=(5,3), title='drought severity index') 

enter image description here

Here the text is rotated but not following the arc curve

guageplot

How to annotate curved text in matplotlib figure?

Ailurophile
  • 2,552
  • 7
  • 21
  • 46
  • 3
    I find [this answer](https://stackoverflow.com/questions/19353576/curved-text-rendering-in-matplotlib) to be very helpful – r-beginners Oct 12 '21 at 08:54
  • Thank you for sharing @r-beginners, not sure how to add the `curvedtext` code to this gauge plot – Ailurophile Oct 12 '21 at 09:58
  • Failed to curve the text using the answer, is there any other working solution?? – Ailurophile Oct 28 '21 at 17:54
  • 1
    I can't comment on that, because I don't understand curvedtext myself, but the way I see it, you need to draw a semicircle to determine the baseline of the characters, and place the characters along that arc. Each character unit in that string needs to be placed along a line tangent to the semicircle (a line parallel to the center of the circle). The angle at which the line should be drawn needs to be calculated in advance. Next, we need to consider whether or not to take into account proportional character placement, which may or may not be necessary for visual appearance. – r-beginners Oct 29 '21 at 02:13
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/239348/discussion-between-pluviophile-and-r-beginners). – Ailurophile Nov 18 '21 at 09:30

0 Answers0