Skip to content
Advertisement

Bokeh pie chart show percentage labels upside down

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. enter image description here

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!

Advertisement

Answer

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:

enter image description here

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement