2

I have to plot a string and transform its height without changing the width. I do find a Scale class here which does the trick. But, I found there are difference in heights among different letters (see the figure: G, O, C are taller than T, H, A, and exceed the bottom limit).

How can I make all letters with exactly the same height and starting y_axis?

I tried to use txt1.get_window_extent() to get the coordinates of the string bbox, but the bbox is not scaled (gray rectangles) after the affine transformation.

    import matplotlib
    matplotlib.use('Agg')
    import matplotlib.pyplot as plt
    from matplotlib.font_manager import FontProperties
    import matplotlib.patheffects
    # import matplotlib.patches as patches

    #-----------------------------------------------------------

    class Scale(matplotlib.patheffects.RendererBase):
        def __init__(self, sx, sy = None):
            self._sx = sx
            self._sy = sy

        def draw_path(self, renderer, gc, tpath, affine, rgbFace):
            affine = affine.identity().scale(self._sx, self._sy) + affine
            renderer.draw_path(gc, tpath, affine, rgbFace)

    #-----------------------------------------------------------

    N=12
    fig = plt.figure(figsize = (N+1, 4))
    ax = fig.add_subplot(111)

    font = FontProperties()
    font.set_size(80)
    font.set_weight('bold')
    font.set_family('monospace')

    bbox_props = dict(boxstyle = "square, pad = 0.0", fill = 0, lw = 1, alpha = 0.5)

    ax.plot((0.0, 1.0), (0.1, 0.1), linestyle = '--') # dashed line
    ax.plot((0.0, 1.0), (0.9, 0.9), linestyle = '--')

    txt1 = ax.text(0.3, 0.1, 'GOTCHA', 
                    fontproperties = font,
                    ha = 'center',
                    va = 'baseline', 
                    bbox = bbox_props)
    txt2 = ax.text(0.8, 0.1, 'GOTCHA', 
                    fontproperties = font,
                    ha = 'center',
                    va = 'baseline',
                    color = 'blue', 
                    bbox = bbox_props)

    txt1.set_path_effects([Scale(1.0, 3.0)]) # 3X in height
    ax.set_ylim(0.0, 1.0)
    plt.savefig('test.png')

Black 'GOTCHA' is the scaled one

taras
  • 6,566
  • 10
  • 39
  • 50
Fei-man Hsu
  • 165
  • 8
  • What exactly is the problem? It seems all letters are indeed the same size, or not? – ImportanceOfBeingErnest Jul 07 '18 at 10:51
  • @ImportanceOfBeingErnest The red and blue dashed lines mark the top and baseline. The scaled 'GOTCHA' in black exceeds the dashed lines in letter 'G', 'O, and 'C', while 'T', 'H' and 'A' are in exact height. – Fei-man Hsu Jul 07 '18 at 10:55
  • 4
    Uh.. so you may of course adapt the scaling (and translation) for each letter individually. But maybe a more sustainable solution would be to find a font where letters have the same height. – ImportanceOfBeingErnest Jul 07 '18 at 10:58
  • 1
    I actually find this an interesting question, so I asked about it [on the graphics design site](https://graphicdesign.stackexchange.com/questions/111439/is-there-a-font-that-has-the-same-height-for-every-character). – ImportanceOfBeingErnest Jul 07 '18 at 18:21
  • [This question](https://stackoverflow.com/questions/42615527/sequence-logos-in-matplotlib-aligning-xticks) may be in some way related. – ImportanceOfBeingErnest Jul 07 '18 at 19:23
  • @ImportanceOfBeingErnest Thanks for your help. I looked into the post and it seems that round characters are originally designed a bit larger for visualization. Perhaps I should scale each letter individually... – Fei-man Hsu Jul 08 '18 at 04:12
  • Also I have another question... when I set the bbox padding region to be 0, why there is still space in the bottom? – Fei-man Hsu Jul 08 '18 at 04:14
  • 1
    The space at the bottom is the space needed for letters which exceed the baseline, like `Q, y, j, p, q, g`. – ImportanceOfBeingErnest Jul 09 '18 at 14:17

0 Answers0