jonboy
jonboy

Reputation: 372

Include legend for go.scattermapbox subplot figure - Plotly

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]

Upvotes: 0

Views: 1587

Answers (1)

r-beginners
r-beginners

Reputation: 35205

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

Upvotes: 2

Related Questions