Include legend for go.scattermapbox subplot figure – Plotly

Question:

The following figure produces two subplots using scattermapbox in Plotly. I’ve included a function that assigns a specific color to each unique category. This all works fine but I’m hoping to include a legend that describes each color and category.

Using below, there are two subplots that are taken from Type. Each unique value in Category has an assigned color. The colors for each point works well for both subplots.

But the legend displays the same color for each Category. I’m aiming to include the correct color in the legend.

df = pd.DataFrame({'Type' : ['1','1','1','1','1','2','2','2','2','2'],
                   'Category' : ['A','B','C','D','E','A','B','C','D','E']
                  })

df['Color'] = df['Category'].map(dict(zip(df['Category'].unique(),
                        px.colors.qualitative.Alphabet[:len(df['Category'].unique())])))

df = pd.concat([df]*10, ignore_index = True)

df['Lat'] = np.random.randint(0, 20, 100)
df['Lon'] = np.random.randint(0, 20, 100)

Color = df['Color']
Category = df['Category']

cats = {k:str(v) for k,v in zip(set(Color),set(Category))}

df_type_1 = df[df['Type'] == '1'].copy()
df_type_2 = df[df['Type'] == '2'].copy()

fig = make_subplots(
    rows = 1, 
    cols = 2,
    specs = [[{"type": "scattermapbox"}, {"type": "scattermapbox"}]],
    vertical_spacing = 0.05,
    horizontal_spacing = 0.05
    )

for c in df_type_1['Color'].unique():
    df_color = df_type_1[df_type_1['Color'] == c]
    fig.add_trace(go.Scattermapbox(
                        lat = df_type_1['Lat'],
                        lon = df_type_1['Lon'],
                        mode = 'markers',
                        name = cats[c],
                        marker = dict(color = df_type_1['Color']),
                        opacity = 0.5,
                        ),
              row = 1,
              col = 1
             )

for c in df_type_2['Color'].unique():
    df_color = df_type_2[df_type_2['Color'] == c]
    fig.add_trace(go.Scattermapbox(
                        lat = df_type_2['Lat'],
                        lon = df_type_2['Lon'],
                        mode = 'markers',
                        name = cats[c],
                        marker = dict(color = df_type_2['Color']),
                        opacity = 0.5,
                        ),
              row = 1,
              col = 2
             )    

fig.update_layout(height = 600, width = 800, margin = dict(l = 10, r = 10, t = 30, b = 10));

fig.update_layout(mapbox1 = dict(zoom = 2, style = 'carto-positron'),
                  mapbox2 = dict(zoom = 2, style = 'carto-positron'),
                  )

fig.show()

[![enter image description here][1]][1]

Asked By: jonboy

||

Answers:

I think the cause was simply that the color specified for the marker was not the color specification used in the loop process. And as to your additional question, although I have not actually created the data and experimented with it, if it is already slow, I think the only way to improve it is to reduce the number of data items. If you don’t need the map display, there are some possible solutions in the references. There is also another library of plotly that compresses the number of data.

import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots

df = pd.DataFrame({'Type' : ['1','1','1','1','1','2','2','2','2','2'],
                   'Category' : ['A','B','C','D','E','A','B','C','D','E']
                  })

df['Color'] = df['Category'].map(dict(zip(df['Category'].unique(),
                        px.colors.qualitative.Alphabet[:len(df['Category'].unique())])))

df = pd.concat([df]*10, ignore_index = True)

df['Lat'] = np.random.randint(0, 20, 100)
df['Lon'] = np.random.randint(0, 20, 100)

Color = df['Color']
Category = df['Category']

cats = {k:str(v) for k,v in zip(set(Color),set(Category))}

df_type_1 = df[df['Type'] == '1'].copy()
df_type_2 = df[df['Type'] == '2'].copy()

fig = make_subplots(
    rows = 1, 
    cols = 2,
    specs = [[{"type": "scattermapbox"}, {"type": "scattermapbox"}]],
    vertical_spacing = 0.05,
    horizontal_spacing = 0.05
    )

for c in df_type_1['Color'].unique():
    df_color = df_type_1[df_type_1['Color'] == c]
    #print('type1',c)
    fig.add_trace(go.Scattermapbox(
                        lat = df_color['Lat'],
                        lon = df_color['Lon'],
                        mode = 'markers',
                        name = cats[c],
                        marker = dict(color = c),#df_type_1['Color']
                        opacity = 0.5,
                        ),
              row = 1,
              col = 1
             )

for c in df_type_2['Color'].unique():
    df_color = df_type_2[df_type_2['Color'] == c]
    #print('type2',c)
    fig.add_trace(go.Scattermapbox(
                        lat = df_color['Lat'],
                        lon = df_color['Lon'],
                        mode = 'markers',
                        name = cats[c],
                        marker = dict(color = c),#df_type_2['Color']
                        opacity = 0.5,
                        showlegend=False,
                        ),
              row = 1,
              col = 2
             )    

fig.update_layout(height = 600, width = 800, margin = dict(l = 10, r = 10, t = 30, b = 10));

fig.update_layout(mapbox1 = dict(zoom = 2, style = 'carto-positron'),
                  mapbox2 = dict(zoom = 2, style = 'carto-positron'),
                  )

fig.show()

enter image description here

Answered By: r-beginners
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.