Search code examples
pythonplotlygeojson

Plotly - use trace marker labels as legend


geojson map downloaded from here: https://github.com/codeforgermany/click_that_hood/blob/main/public/data/ireland-counties.geojson

I want to create a legend which consists of the labels from the marker tract overlay. This is the code so far:

import geojson
import pandas as pd
import plotly.graph_objects as go

with open("data/ireland-with-counties_.geojson") as f:
    gj = geojson.load(f)
    
# example df    
metadata = pd.DataFrame({'ID':['AH1','AT10B','BA1','BC1','BG18'],
             'Site':['Athea','Athenry','Ballyhaise','Belcoo','Ballynagree'],
             'Latitude':[52.457079,53.287512,54.050665,54.280660,51.988472],
             'Longitude':[-9.309839,-8.768810,-7.324268,-7.684888,-8.926938]})
    
# generating random hex colours
import random
r = lambda: random.randint(0,255)
hex_codes = []
for x in range(0,len(metadata['Site'])):
    hex_codes.append('#%02X%02X%02X' % (r(),r(),r()))
colors = dict(zip(metadata['Site'].to_list(),hex_codes))
    
pts = []
for feature in gj['features']:
    if feature['geometry']['type'] == 'Polygon':
        pts.extend(feature['geometry']['coordinates'][0])    
        pts.append([None, None])#mark the end of a polygon   
        
    elif feature['geometry']['type'] == 'MultiPolygon':
        for polyg in feature['geometry']['coordinates']:
            pts.extend(polyg[0])
            pts.append([None, None])#end of polygon
    elif feature['geometry']['type'] == 'LineString': 
        points.extend(feature['geometry']['coordinates'])
        points.append([None, None])
    else: pass           
    #else: raise ValueError("geometry type irrelevant for map")

x, y = zip(*pts)    

fig = go.Figure()
fig.add_scatter(x=x, y=y, mode='lines', line_color='#999999', line_width=1.5)
fig.update_layout(width=600,  height=800)

fig.add_trace(
    go.Scatter(
        x=metadata['Longitude'],
        y=metadata['Latitude'],
        text = metadata['Site'],
        hoverinfo = 'text',
        mode = 'markers',
        name = "location",
        marker=dict(size=8, color='rgba(255,255,255,0)',
                    line=dict(color=metadata['Site'].map(colors),
                    colorscale='plasma', width=2)
                   ))
)

fig.show()

Current output

Currently the labels only show on hover - how can I get the marker labels to be in the legend? E.g:

enter image description here


Solution

  • In Plotly, by default, the labels for markers don't automatically appear in the legend. However, you can achieve this by creating "proxy" traces for each label/color combination that you want to display in the legend. These proxy traces are essentially dummy traces that don't add any visible elements to the plot but are used for creating the legend entries.

    Here's how you can modify your code to display marker labels in the legend:

    import geojson
    import pandas as pd
    import plotly.graph_objects as go
    
    # Your code for loading geojson and metadata...
    
    # Rest of your code...
    
    # Create the proxy traces for legend entries
    legend_traces = []
    for site, color in colors.items():
        legend_trace = go.Scatter(
            x=[None],
            y=[None],
            name=site,
            mode='markers',
            marker=dict(size=8, color=color, line=dict(color=color, width=2))
        )
        legend_traces.append(legend_trace)
    
    # Add the proxy traces to the figure
    for legend_trace in legend_traces:
        fig.add_trace(legend_trace)
    
    fig.show()
    

    In this code, you're creating a list of proxy traces (legend_traces) where each proxy trace corresponds to a label/color combination from your colors dictionary. These traces have no actual data points, but their settings for name, mode, and marker are used to create the legend entries with the specified label and color. Finally, you loop through the proxy traces and add them to your existing figure using fig.add_trace(legend_trace).

    When you run this code, the marker labels will appear in the legend along with the appropriate colors.