I have a dataframe with amounts grouped by categories and I want to generate a pie chart containing the percentages per category. I am using the Bokeh library in Python.
My problem is that some percetange labels are not displayed properly in the pie chart as shown in the following image.
Here is the code that I use to produce the pie chart:
df['angle'] = df['paymentAmount'] / df['paymentAmount'].sum() * 2 * pi
if len(df.index) > 2:
df["color"] = GnBu[len(df.index)]
elif len(df.index) == 2:
df["color"] = ["steelblue", "skyblue"]
else:
df["color"] = ["steelblue"]
df["percentage"] = df["paymentAmount"] / df["paymentAmount"].sum()
df['percentage'] = df['percentage'].astype(float).map(lambda n: '{:.2%}'.format(n))
df["percentage"] = df['percentage'].astype(str)
df["percentage"] = df["percentage"].str.pad(35, side="left")
source = ColumnDataSource(df)
p = figure(width=figsize[0], height=figsize[1], toolbar_location=None,
tooltips=[("percentage", "@percentage")],
tools="hover", x_range=(-0.5, 1.0))
pie_chart = p.wedge(x=0, y=1, radius=0.4,
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
line_color="white", fill_color='color', source=source)
labels = LabelSet(x=0, y=1, text='percentage', angle=cumsum('angle', include_zero=True), source=source,
render_mode='canvas')
p.add_layout(labels)
legend = Legend(items=[LegendItem(label=dict(field='category'), renderers=[pie_chart])],
location=(0, figsize[1] - 100))
p.add_layout(legend, 'right')
p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None
save(p)
Some data to reproduce the the pie chart above (tab separated)
category paymentAmount
Chemicals 52800.95001766206
Research 110878.70999269483
Construction 266189.2100121978
Any ideas how to solve this?
Thank you in advance!
I have found two useful StackOverflow posts to solve this:
Therefore, I have modified your code as follows:
df['angle'] = df['paymentAmount'] / df['paymentAmount'].sum() * 2 * pi
value = list(df["paymentAmount"])
df["cumulative_angle"] = [(sum(value[0:i + 1]) - (item / 2)) / sum(value) * 2 * pi for i, item in enumerate(value)]
df['cos'] = np.cos(df['cumulative_angle']) * 0.3
df['sin'] = np.sin(df['cumulative_angle']) * 0.3
if len(df.index) > 2:
df["color"] = GnBu[len(df.index)]
elif len(df.index) == 2:
df["color"] = ["steelblue", "skyblue"]
else:
df["color"] = ["steelblue"]
df["percentage"] = df["paymentAmount"] / df["paymentAmount"].sum()
df['percentage'] = df['percentage'].astype(float).map(lambda n: '{:.2%}'.format(n))
df["percentage"] = df['percentage'].astype(str)
df["percentage"] = df["percentage"].str.pad(35, side="left")
source = ColumnDataSource(df)
p = figure(width=figsize[0], height=figsize[1], toolbar_location=None, x_range=(-1.0, 1.0), y_range=(-1.0, 1.0),
tooltips=[("percentage", "@percentage")], tools="hover")
pie_chart = p.wedge(x=0, y=0, radius=0.5,
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
line_color="white", fill_color='color', source=source)
labels = LabelSet(x="cos", y="sin", y_offset=0, text='percentage', text_align="center", angle=0, source=source,
render_mode='canvas')
p.add_layout(labels)
legend = Legend(items=[LegendItem(label=dict(field="category"), renderers=[pie_chart])],
location=(0, figsize[1] - 100))
p.add_layout(legend, 'right')
p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None
save(p)
The produced pie chart is: