5

I am displaying a section of a dim-reduced Word Embedding with Plotly in Python. I am using a 3D Scatter Plot, and everything is working fine so far, with this code (broken down):

fig = go.Figure()
trace = go.Scatter3d(
        x=df[0],
        y=df[1],
        z=df[2],
        text=df.index,
        mode="markers+text",
        textfont=dict(
            color=["crimson"]),
        marker=dict(
            size=3),
        hoverinfo="skip")

fig.add_trace(trace)

fig.show()

The only problem I am having is that some of the labels of the datapoints overlap, which results in them being unreadable at first glance.

Is there a possibility to specify the background colour of the text labels?

Edit:

The first 5 lines of my df look like this, and all the data is structured this way. The index is the word, and the three columns are its position in 3D-space.

                        0         1         2
chancellor       1.102989  0.416767  2.071260
abdicate         0.028073  1.156498  1.911484
overthrow        2.435294 -0.305266  0.998094
candidate        0.259697  0.648845  0.448700
elections        0.122355  0.815206  1.107913

However, my problem isn't really about the data, but about the possibilities one has to customize the visualization.

Edit2:

This is what my plot looks like.

enter image description here

As you can see with the cluster on the lower left, most of the labels overlap each other. I am now hoping that there is a hidden parameter I could use to make these labels better visible, and I instinctively looked for a way to add a white background to all of these labels, so that this would block the labels of the data points behind them.

backendboi
  • 131
  • 1
  • 6
  • https://stackoverflow.com/questions/38462844/how-to-set-background-color-title-in-plotly-python – bigbounty Jul 07 '20 at 17:06
  • @bigbounty Thank you, but this only talks about the background colour of the whole plot. I am looking for the background colour of only the data point labels. – backendboi Jul 07 '20 at 17:13
  • 1
    @backendboi do you mind to produce a [mcve](/help/mcve)? In particular a sample of `df` will be great. – rpanai Jul 07 '20 at 17:56
  • 1
    @rpanai Thanks for pointing this out, I've just added some more information. I'm not quite sure how to initialize the dataframe (concisely) in the code, as it is a product of more complex operations. – backendboi Jul 07 '20 at 18:15
  • 1
    It sounds like a bug to me. Have you tried to add text explicitly as [here](https://plotly.com/python/text-and-annotations/#3d-annotations) – rpanai Jul 07 '20 at 20:01
  • @rpanai I've added a picture to illustrate my challenge, and don't really think it is a bug, but maybe just a use case the library isn't made for ... – backendboi Jul 08 '20 at 07:25
  • @backendboi when I try to run your code I can see that some text is behind the 3d axes background. I feel that this is a bug. This doesn't happen with annotations as you are adding a layer on top of your plot. – rpanai Jul 08 '20 at 13:51

1 Answers1

5

I found a workaround, by not using the text-parameter in the trace definition, but by adding annotations for every datapoint. The code now looks like this:

trace = go.Scatter3d(
            x=df[0],
            y=df[1],
            z=df[2],
            mode="markers",
            marker=dict(size=3),
            hoverinfo="skip")
    
annos = []
first = True
for index, row in df.iterrows():
    if first:
        col = "black"
        first = False
    else:
        col = "black"
            
    anno = dict(x=row[0],
                y=row[1],
                z=row[2],
                text=index,
                showarrow=True,
                arrowhead=0,
                font=dict(color=col),
                ax=0,
                ay=-20,
                bgcolor="white",
                opacity=0.85)

    annos.append(anno)
        
fig = go.Figure()
fig.add_trace(trace)
fig.update_layout(scene=dict(annotations=annos)

The labels, implemented as annotations, now have a white background, that makes them able to be read even if there are more datapoints behind them. Sadly, the layering of these labels doesn't follow the perspective of the camera, but only the position on the y-axis. Therefore, the annotation with the lowest y-value is always behind all other annotations, even if the camera is located on the negative end of the y-axis.

enter image description here

backendboi
  • 131
  • 1
  • 6