简体   繁体   中英

Make pie chart with percentage readable in grayscale

I have a source code to generate pie chart

import matplotlib.pyplot as plt
from matplotlib.pyplot import savefig
import numpy as np
import matplotlib.gridspec as gridspec

plt.clf()
plt.cla()
plt.close()
labels_b = ["Negative",  "Positive"]
dev_sentences_b = [428, 444]
test_sentences_b = [912, 909]
train_sentences_b = [3310, 3610]

gs = gridspec.GridSpec(2, 2)
ax1= plt.subplot(gs[0, 0])
ax1.pie(train_sentences_b,  autopct='%1.1f%%',
        shadow=True, startangle=90)
ax1.axis('equal')
ax1.set_title("Train")

ax2= plt.subplot(gs[0, 1])
ax2.pie(dev_sentences_b, autopct='%1.1f%%',
        shadow=True, startangle=90)
ax2.axis('equal')
ax2.set_title("Dev")

ax3 = plt.subplot(gs[1, 1])
ax3.pie(test_sentences_b, autopct='%1.1f%%',
        shadow=True, startangle=90)
ax3.axis('equal')
ax3.set_title("Test")

ax3.legend(labels=labels_b, bbox_to_anchor=(-1,1), loc="upper left")

plt.savefig('sstbinary', format='pdf')

Result
Color picture
颜色饼图
and grayscale
灰阶

The grayscale version is a bit difficult to read. Is there any suggestion to make grayscale pie chart readable in black-and-white printing ?

It's not clear from the question whether you would like to create your chart in black and white already or produce it in color and later convert it. The strategy in both cases might be the same though: You can create a new color cycle using colors from a colormap. A reference for possible colormaps is given here . Of course you could also use your own list of colors.

Eg creating 5 colors from the gray colormap between 0.2 (dark gray) to 0.8 (lightgray):

from cycler import cycler
colors = plt.cm.gray(np.linspace(0.2,0.8,5))
plt.rcParams['axes.prop_cycle'] = cycler(color=colors)

在此输入图像描述

Similarly, you may use a colorful map (eg magma ) which would still look good, when converted to grayscale afterwards.

from cycler import cycler
colors = plt.cm.magma(np.linspace(0.2,0.8,5))
plt.rcParams['axes.prop_cycle'] = cycler(color=colors)

在此输入图像描述

Changing the range of colors, eg to between 0.4 and 0.95 gives a lighter colorrange,

from cycler import cycler
colors = plt.cm.magma(np.linspace(0.4,0.95,5))
plt.rcParams['axes.prop_cycle'] = cycler(color=colors)

在此输入图像描述

Note that you may, instead of defining a color cycle, also apply the colors directly to each pie chart,

ax.pie(..., colors=colors, ...)

Finally, to distinguish shapes in gray scale images, an often applied technique is to use hatching. See eg this example .

pie = ax.pie(..., autopct='%1.1f%%', pctdistance=1.3,
              colors=colors, ...)
for patch, hatch in zip(pie[0],hatches):
    patch.set_hatch(hatch)

在此输入图像描述

Assuming you are saving as a colour figure, and later converting to grayscale, you could do the following:

  1. Define your colours in a list from your favourite colormap. [It's also worth noting here that using one of the new 4 colormaps (available since matplotlib 1.5: viridis, magma, plasma, inferno) means that the colours will still be distinguishable when the image is converted to grayscale].

     colors = plt.cm.plasma(np.linspace(0., 1., 5)) 
  2. Then, we can define a function to convert those colors to their equivalent grayscale value:

     rgb2gray = lambda rgb: np.dot(rgb[...,:3], [0.299, 0.587, 0.114]) 
  3. If that value is greater than 0.5, the colour is a light shade, and thus we can use black text, otherwise, change the text to a light colour. We can save those text colours in a list using the following list comprehension:

     textcol = ['k' if rgb2gray(color) > 0.5 else 'w' for color in colors ] 
  4. When you plot the pie chart, use the colors=colors kwarg to use the colours you defined earlier. matplotlib returns three things from ax.pie : the patches that make up the pie chart, the text labels, and the autopct labels. The latter are the ones we want to modify.

     p, t, at = ax1.pie(train_sentences_b, autopct='%1.1f%%', shadow=True, startangle=90, colors=colors) 
  5. Lets define a function to loop through the text labels, and set their colours depending on the list we made earlier:

     def fix_colors(textlabels, textcolors): for text, color in zip(textlabels, textcolors): text.set_color(color) 
  6. We then call this after each pie chart is plotted using:

     fix_colors(at, textcol) 

Putting that all together in your script (I added some extra data to get all 5 catagories on the pie chart):

import matplotlib.pyplot as plt
from matplotlib.pyplot import savefig
import numpy as np
import matplotlib.gridspec as gridspec

colors = plt.cm.plasma(np.linspace(0., 1., 5))

rgb2gray = lambda rgb: np.dot(rgb[...,:3], [0.299, 0.587, 0.114])

textcol = ['k' if rgb2gray(color) > 0.5 else 'w' for color in colors ]

def fix_colors(textlabels, textcolors):
    for text, color in zip(textlabels, textcolors):
        text.set_color(color)

plt.clf()
plt.cla()
plt.close()

labels_b = ["Very Negative", "Negative",  "Neutral", "Positive", "Very Positive"]
dev_sentences_b = [428, 444, 430, 500, 320]
test_sentences_b = [912, 909, 890, 900, 900]
train_sentences_b = [3310, 3610, 3200, 3500, 3321]

gs = gridspec.GridSpec(2, 2)
ax1= plt.subplot(gs[0, 0])
p, t, at = ax1.pie(train_sentences_b,  autopct='%1.1f%%',
        shadow=True, startangle=90, colors=colors)
fix_colors(at, textcol)

ax1.axis('equal')
ax1.set_title("Train")

ax2= plt.subplot(gs[0, 1])
p, t, at = ax2.pie(dev_sentences_b, autopct='%1.1f%%',
        shadow=True, startangle=90, colors=colors)
ax2.axis('equal')
ax2.set_title("Dev")
fix_colors(at, textcol)

ax3 = plt.subplot(gs[1, 1])
p, t, at = ax3.pie(test_sentences_b, autopct='%1.1f%%',
        shadow=True, startangle=90, colors=colors)
ax3.axis('equal')
ax3.set_title("Test")
fix_colors(at, textcol)

ax3.legend(labels=labels_b, bbox_to_anchor=(-1,1), loc="upper left")

plt.savefig('sstbinary', format='pdf')

Which gives the following image:

在此输入图像描述

And after converting to grayscale:

在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM