Making a Matplot piechart in Plotly?

I want to have the percentage values shown ontop of the pie wedge and have the labels next to the wedge. In Matplot this is pretty easy

I can’t get the same thing in plotly though, despite my efforts, any suggestions?

import plotly.graph_objects as go
import numpy as np

Sample data

labels = [‘Apple’, ‘Banana’, ‘Cherry’, ‘Date’]
values = np.array([4500, 2500, 1050, 1500]) # Convert values to a NumPy array

Create the pie chart

fig = go.Figure(data=[go.Pie(labels=labels, values=values, textinfo=‘label’, insidetextorientation=‘horizontal’)])

Customize the trace for displaying labels outside

fig.update_traces(
textposition=‘outside’, # Display labels outside the pie
marker=dict(line=dict(color=‘#000000’, width=2)),
hoverinfo=‘label+percent’
)

Calculate midpoints for each slice for proper percentage placement

angle_sum = np.cumsum(values) - values / 2
total_sum = sum(values)
mid_angles = angle_sum / total_sum * 2 * np.pi # convert to radians

Add annotations for percentages directly on the slices

for angle, value in zip(mid_angles, values):
x = 0.5 + 0.5 * np.cos(angle) # X position
y = 0.5 + 0.5 * np.sin(angle) # Y position
percentage = f"{(value / total_sum * 100):.1f}%"

fig.add_annotation(
    x=x, y=y,
    xref="paper", yref="paper",
    text=percentage,  # The percentage value
    showarrow=False,
    font=dict(size=12, color="white"),  # Ensure text is visible on slices
    align='center'
)

Update layout to ensure everything fits

fig.update_layout(
title_text=‘Fruit Consumption’,
showlegend=False # Disable the legend
)

Show the figure

fig.show()

Hi @tdl ,

it seems pretty hard to separate the value and label into different position.
Annotation maybe the best approach to add percentage inside the pie chart.

unfortunately I have not found the best calculation to get location to text annotation.
so I use exactly hard coded coordinate to place annotation, and maybe this is useful for you.

Here is the output.

import plotly.graph_objects as go
import numpy as np

# Sample data
labels = ["Apple", "Banana", "Cherry", "Date"]
values = np.array([4500, 2500, 1050, 1500]) # Convert values to a NumPy array

# Create the pie chart
fig = go.Figure(data=[go.Pie(labels=labels, values=values, textinfo="label", insidetextorientation="horizontal")])

# Customize the trace for displaying labels outside
fig.update_traces(
	textposition="outside", # Display labels outside the pie
	marker=dict(line=dict(color="#000000", width=2)),
	hoverinfo="label+percent"
)

# Calculate midpoints for each slice for proper percentage placement
angle_sum = np.cumsum(values) - values / 2
total_sum = sum(values)
mid_angles = angle_sum / total_sum * 2 * np.pi # convert to radians

percentages = []
# Add annotations for percentages directly on the slices
for angle, value in zip(mid_angles, values):
	# x = 0.5 + 0.5 * np.cos(angle) # X position
	# y = 0.5 + 0.5 * np.sin(angle) # Y position
	percentage = f"{(value / total_sum * 100):.1f}%"
	percentages.append(percentage)

# list of the annottaion location
coordinate_text_list=[(0.65,0.5),(0.35,0.35),(0.45,0.15),(0.35, 0.65)]

for coord, percentage in zip(coordinate_text_list,percentages):
	x,y = coord
	fig.add_annotation(
	    x=x, y=y,
	    xref="x domain", yref="y domain", # using x and y domain to make esier get center of pie chart
	    text=percentage,  # The percentage value
	    showarrow=False,
	    font=dict(size=12, color="white"),  # Ensure text is visible on slices
	    align='center'
	)

# Update layout to ensure everything fits
fig.update_layout(
	title_text="Fruit Consumption",
	showlegend=False # Disable the legend
)

# Show the figure
fig.show()

Thanks for taking a shot! Hardcoded probably isn’t ideal so I’ll keep hunting. I appreciate the effort though @farispriadi !

Maybe overlaying the exact same trace again but tweaking the labels and making the markers invisible? Also skip the hoverinfo.

Just thinking aloud…

Yup, good thinking, that does it

import plotly.graph_objects as go
import numpy as np

# Sample data
labels = ['Apple', 'Banana', 'Cherry', 'Date']
values = np.array([4500, 2500, 1050, 1500])  # Convert values to a NumPy array

# Create the initial pie chart
fig = go.Figure(data=[go.Pie(
    labels=labels,
    values=values,
    textinfo='label',
    insidetextorientation='horizontal',
    textposition='outside',
    marker=dict(line=dict(color='#000000', width=2)),
    sort=False  # Ensure that the slices are in the same order for both traces
)])

# Overlay the same pie chart but with labels inside and invisible markers
fig.add_trace(go.Pie(
    labels=labels,
    values=values,
    textinfo='percent',
    insidetextorientation='horizontal',
    textposition='inside',
    marker=dict(line=dict(color='#000000', width=0)),  # Make the line invisible
    sort=False  # Ensure that the slices are in the same order
))

# Show the figure
fig.show()