How to avoid overlapping text in a plotly scatter plot?

Viewed 2811

I am looking for a solution to avoid overlapping text in the text-labels. I create the image with plotly scatter. Maybe there is an automation here.

from pandas import util
import plotly.express as px
import plotly.graph_objects as go

df = util.testing.makeDataFrame()
df_keyfigures_all = df[['A','B']]



fig = px.scatter(df_keyfigures_all, x="A", y="B",size_max=60,
                     text=df_keyfigures_all.index)

fig.update_traces(textposition='top center')
fig.layout = go.Layout(yaxis=dict(tickformat=".0%"), xaxis=dict(tickformat=".0%"),
                       yaxis_title="A", xaxis_title="B")


fig.update_layout(showlegend=False)
plotly.io.write_image(fig, file='keyfigures.png', format='png')

Points with overlapping labels

3 Answers

Unfortunately, there does not seem to be a direct way to do this. A little digging on the plotly community forum will show you that it has already been requested and that the developers are aware of the issue.

One solution is to alternate the text position like in this live demo:

import pandas as pd
from plotly import express as px, graph_objects as go

df = pd.DataFrame()
df['x'] = [0, 1, 1, 2, 3, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12]
df['y'] = [57, 55, 75, 23, 80, 66, 66, 23, 79, 79, 20, 71, 59, 74, 82, 77]
df['explainer_name'] = ['tree_shap_approximation', 'saabas', 'tree_shap', 'baseline_random', 'archipelago',
                        'shapley_taylor_interaction', 'partition', 'anova', 'permutation_partition', 'permutation',
                        'shap_interaction', 'sage', 'maple', 'lime', 'kernel_shap', 'exact_shapley_values']

fig = px.scatter(df,
                     x='x',
                     y='y',
                     # size='dot_size',
                     text='explainer_name',
                     # log_x=True,
                     labels={
                         "x": "Time",
                         "y": "Score",
                         # 'dot_size': 'Portability',
                         'explainer_name': 'Explainer '
                     },
                     title='No overlapping annotations',  # take some vertical space
                     )
def improve_text_position(x):
    """ it is more efficient if the x values are sorted """
positions = ['top center', 'bottom center']  # you can add more: left center ...
return [positions[i % len(positions)] for i in range(len(x))]

fig.update_traces(textposition=improve_text_position(df['x']))
fig.show()

Before: enter image description here

After: enter image description here

It is not the perfect solution, but one way is to hide the text in the hover text.

fig = px.scatter(df_keyfigures_all, x="A", y="B",size_max=60,
                 hover_name = df_keyfigures_all.index)
Related