Search code examples
pythonmatplotlibfarsi

Using Persian numbers in pie charts of matplotlib


I have a pie chart that I created with matplotlib, and I've used Persian text for the labels:

In [1]: import matplotlib.pyplot as plt                                              
In [2]: from bidi.algorithm import get_display                                      
In [3]: from arabic_reshaper import reshape                                         
In [4]: labels = ["گروه اول", "گروه دوم", "گروه سوم", "گروه چهارم"]                 
In [5]: persian_labels = [get_display(reshape(l)) for l in labels]                  
In [6]: sizes = [1, 2, 3, 4]                                                        
In [7]: plt.rcParams['font.family'] = 'Sahel'                                       
In [8]: plt.pie(sizes, labels=persian_labels, autopct='%1.1f%%')    
In [9]: plt.savefig("pie.png", dpi=200)                                             

And the result is as I expected:

Pie chart in Persian

Now I want to change the percentage numbers to Persian as well. So instead of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], it must use [۰, ۱, ۲, ۳, ۴, ۵, ۶, ۷, ۸, ۹].

I can convert English digits to Persian quite easily with a function like this:

def en_to_fa(text):
    import re
    mapping = {
        '0': '۰',
        '1': '۱',
        '2': '۲',
        '3': '۳',
        '4': '۴',
        '5': '۵',
        '6': '۶',
        '7': '۷',
        '8': '۸',
        '9': '۹',
        '.': '.',
    }
    pattern = "|".join(map(re.escape, mapping.keys()))
    return re.sub(pattern, lambda m: mapping[m.group()], str(text))

But I don't know how I can apply this function to the percentages produced by matplotlib. Is it even possible?


Solution

  • You can pass in a function for autopct, not just a string formatter. So basically, you can just pass your en_to_fa to autopct, with a few minor modifications: you just need to first convert your number to a string with the appropriate number formatting, then do the language conversion. My machine is not setup for Farsi, but the following demonstrates the approach (mapping digits to the first 10 letters of the alphabet):

    import matplotlib.pyplot as plt
    
    def num_to_char(num, formatter='%1.1f%%'):
        num_as_string = formatter % num
        mapping = dict(list(zip('0123456789.%', 'abcdefghij.%')))
        return ''.join(mapping[digit] for digit in num_as_string)
    
    sizes = range(1, 5)
    plt.pie(sizes, autopct=num_to_char)
    plt.savefig("pie.png", dpi=200)
    

    enter image description here