简体   繁体   中英

Plotly traces not visible after updating menu

I'm plotting scattergeo plots on a US map (51 traces for 51 states including DC and 4 traces for 4 different years). I have updatemenus with 2 buttons that switch between one scattergeo with legend (51 traces) and another scattergeo with a slider at the bottom (4 traces). I initially set the 4 traces (years) visible = False because I wanted only the 51 traces to appear initially but when I click the button to switch to scattergeo with slider and set first 51 traces visible = False and final 4 traces visible = [True, False, False, False] none of my traces are visible on the map.

No sure why this is happening. When I set cities_year visible = True when first creating the scattergeo (ie they are visible initially) the traces appear but I don't want that because then I have the all my scatterpoints being plotted twice on top of each other.

Here is some code to create dataset:

data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2014_us_cities.csv')
data = data.iloc[:400] # Keep only first 400 samples
data.loc[:100, 'year'] = '1990'
data.loc[100:200, 'year'] = '1991'
data.loc[200:300, 'year'] = '1992'
data.loc[300:, 'year'] = '1993'

I am using plotly version 2.7.0 and the offline plotting Here is my plotly code:

cities = []
for state in data['name'].value_counts().index:
    data_sub = data.loc[data['name'] == state]
    city = dict(
        type = 'scattergeo',
        visible = True,
        locationmode = 'USA-states',
        lon = data_sub['lon'],
        lat = data_sub['lat'],
        mode = 'markers',
        marker = dict(
            size = 8,
            color = "rgb(255, 102, 102)",
            opacity = 0.4,
            line = dict(
                width=0.5,
                color='rgb(255, 102, 102)'
            )
        ),
        name = state
    )
    cities.append(city)

cities_year = []
for year in sorted(data.year.value_counts().index):
    data_sub = data.loc[data['year'] == year]
    city = dict(
        type = 'scattergeo',
        visible = False,
        locationmode = 'USA-states',
        lon = data_sub['lon'],
        lat = data_sub['lat'],
        mode = 'markers',
        marker = dict(
            size = 8,
            color = "rgb(255, 102, 102)",
            opacity = 0.4,
            line = dict(
                width=0.5,
                color='rgb(255, 102, 102)'
            )
        ),
        name = str(year)
    )
    cities_year.append(city)

slider = [dict(active = 0,
               pad = dict(t = 1),
               steps = [dict(args = ["visible", ([False] * len(cities)) + [True, False, False, False]], 
                             label = "1990",
                             method = "restyle"
                            ),
                        dict(args = ["visible", ([False] * len(cities)) + [False, True, False, False]],
                             label = "1991", 
                             method = "restyle"
                            ),
                        dict(args = ["visible", ([False] * len(cities)) + [False, False, True, False]],
                             label = "1992",
                             method = "restyle"
                            ),
                        dict(args = ["visible", ([False] * len(cities)) + [False, False, False, True]],
                             label = "1993",
                             method = "restyle"
                            )
                       ]
              )
         ]

updatemenus = list([
    dict(type="buttons",
         active=0,
         buttons=list([   
            dict(label = 'states',
                 method = 'update',
                 args = [dict(visible = ([True] * len(cities)) + ([False] * len(cities_year))),
                         dict(sliders = [],
                              showlegend = True)]),
            dict(label = 'years',
                 method = 'update',
                 args = [dict(visible = ([False] * len(cities)) + [True, False, False, False]),
                         dict(sliders = slider,
                              showlegend = False)])
        ]),
     )
])

layout = dict(
    title = 'myplot',
    geo = dict(
        scope='usa',
        projection=dict(type='albers usa'),
        showland=True,
        showlakes = True,
        landcolor = 'rgb(217, 217, 217)',
        subunitwidth=1,
        countrywidth=1,
        subunitcolor="rgb(255, 255, 255)",
        countrycolor="rgb(255, 255, 255)"
    ),
    updatemenus=updatemenus
)

trace_data = cities + cities_year
fig = dict(data=trace_data, layout=layout)
iplot(fig, validate=False)

Problem: If I understand correctly, when the above code is run: The iplot() creates the scattergeo() plot with two buttons labeled ' states ' and ' years '. Of these two buttons namely the ' states ' button is active and showing its plot (with 'red dots' and legend ). The ' years ' button corresponds to a plot with a slider option ( years 1990 to 1993 ). Now, when this ' years ' button is clicked the expectation is that the 'red dots' should appear across the maps (for year 1990 ). However, this does not happen.

Plot when above code is run 运行上面的代码时绘制

Problem plot with no data points when 'years' button is clicked 在此处输入图片说明

Attempted solution:

When visible is set to True (below) in city dictionary for cities_year list of traces , then the problem is solved. That is after the code is run the plot appears with two buttons. Now when the ' years ' button is clicked , it shows the 'red dots' for the with slider at the year 1990 . Setting visible=True may be important because it could be for the very first instance when the plot is loaded or displayed. ( Jupyter Notebook 5.0.0 ; Python 3.6.6 )

cities_year = []
for year in sorted(data.year.value_counts().index):
    data_sub = data.loc[data['year'] == year]
    city = dict(
        type = 'scattergeo',
        visible = True,

Plot after code is run: 在此处输入图片说明

Now when the 'years' button is clicked the plot is: 在此处输入图片说明

Edit - 1 - - - - - - - - - - - - - - - -

The slider still does not work as expected. However found a work around using just the legends for selection of year .

    dict(label = 'years',
         method = 'restyle',
         args = [dict(visible = ([False] * len(cities)) + [True, True, True, True]),
                 dict(sliders = slider,
                      showlegend = False)])

在此处输入图片说明

Edit - 2 - - - - - - - - - - - - - - - -

Issue is still unresolved, but code below may help narrow down finding the bug. In the code below, there are two sample data sets for: (1) go.Scatter() and (2) go.Scattergeo() . There are only 5 rows in total in each dataframe to keep it simple. Note that although the code for generating the sample data set is different, following the code works to plot both of the above data sets. It shows that the go.Scatter() works fine, and go.Scattergeo() has the issue mentioned in the question.

Import libraries

import datetime
from datetime import date
import pandas as pd
import numpy as np
from plotly import __version__
%matplotlib inline

import cufflinks as cf
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot 
init_notebook_mode(connected=True)

init_notebook_mode(connected=True)
cf.go_offline()

import plotly.offline as pyo
import plotly.graph_objs as go
from plotly.tools import FigureFactory as FF

import json

Create data for go.Scatter()

# Create random numbers
x = np.random.randn(100)
y = 10 + np.random.randn(100)
z = np.linspace(-3,2,100)
df = pd.DataFrame({'x':x, 'y':y, 'z':z})
df.head(2)

# Create traces
trace1 = go.Scatter(visible = True, x=df.x, y=df.y, mode='markers', name='trace1', marker=dict(color='red'))
trace2 = go.Scatter(visible = True, x=df.x, y=df.z, mode='markers', name='trace2', marker=dict(color='black'))

trace3 = go.Scatter(visible = False, x=df.x, y=df.y*df.y, mode='markers', name='trace3', marker=dict(color='blue'))
trace4 = go.Scatter(visible = False, x=df.x, y=df.z*0.5, mode='markers', name='trace4', marker=dict(color='orange'))
trace5 = go.Scatter(visible = False, x=df.x, y=df.z*df.z, mode='markers', name='trace5', marker=dict(color='purple'))

# Create list of traces 
data = [trace1, trace2, trace3, trace4, trace5]

Create data for go.Scattergeo()

# Create dataframe for cities
df = pd.DataFrame({'name': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Philadelphia'],
                  'pop': [8287238, 3826423, 2705627, 2129784, 1539313],
                  'lat': [40.730599, 34.053717, 41.875555, 29.758938, 39.952335],
                  'lon': [-73.986581, -118.242727, -87.624421, -95.367697, -75.163789],
                   'year': [1990, 1991, 1992, 1993, 1991]
                })


# Create city traces manually without for-loop
trace1 = go.Scattergeo(visible=True,name = 'trace1',locationmode = 'USA-states',
                   lon = df[df['name']=='New York']['lon'], lat = df[df['name']=='New York']['lat'], 
                   mode = 'markers',marker = dict(size=10, symbol='circle-open', color = "red")) 
trace2 = go.Scattergeo(visible=True,name = 'trace2',locationmode = 'USA-states',
                   lon = df[df['name']=='Los Angeles']['lon'], lat = df[df['name']=='Los Angeles']['lat'], 
                   mode = 'markers',marker = dict(size=10, symbol='circle-open', color = "red")) 


trace3 = go.Scattergeo(visible=False, name = 'trace3', locationmode = 'USA-states',
                   lon = df[df['year']==1990]['lon'], lat = df[df['year']==1990]['lat'],
                   mode = 'markers',marker = dict(size=20, symbol='circle-open', color = "blue")
                  ) 
trace4 = go.Scattergeo(visible=False, name = 'trace4', locationmode = 'USA-states',
                   lon = df[df['year']==1991]['lon'], lat = df[df['year']==1991]['lat'],
                   mode = 'markers',marker = dict(size=20, symbol='circle-open', color = "blue")
                  )  
trace5 = go.Scattergeo(visible=False, name = 'trace5', locationmode = 'USA-states',
                   lon = df[df['year']==1992]['lon'], lat = df[df['year']==1992]['lat'],
                   mode = 'markers',marker = dict(size=20, symbol='circle-open', color = "blue")
                  ) 

# Create list of traces
data = [trace1, trace2, trace3, trace4, trace5]

Code below is common to above two data sets

# Create slider
sliders = [dict(active=-1,
               pad = {"t": 1},
               currentvalue = {"prefix": "Plot Number: "},
               execute=True, 
               steps = [
                        dict(args = ["visible", [False, False, True, False, False]],
                             label = "trace3", 
                             method = "restyle"
                            ),
                        dict(args = ["visible", [False, False, False,True, False]],
                             label = "trace4",
                             method = "restyle"
                            ),
                        dict(args = ["visible", [False, False, False, False, True]],
                             label = "trace5",
                             method = "restyle"
                            )
                       ],
                transition = 0
              )
         ]

# Create updatemenus
updatemenus = list([
    dict(
        buttons= list([
                        dict(
                             args = [
                                    {'visible': (True, False, False, False, False)},
                                    {'sliders':[], 'showlegend': True, 'title': 'Plots only'}
                                    ],
                             label = 'single_plot',
                             method = 'update'

                    ),
                         dict(
                             args = [
                                    {'visible': (False, False, True, False, False)},
                                    {'sliders':sliders, 'showlegend': True, 'title': 'Plots with slider'}
                                    ],
                             label = 'multi_plots',
                             method = 'update'

                    )
        ]),
        direction = 'left',
        pad = {'r': 10, 't': 10},
        showactive = True,
        type = 'buttons',
        x = 0.1,
        xanchor = 'left',
        y = 1,
        yanchor = 'top' 
    )])

# Create layout
layout = go.Layout(title='Chart') #, geo=dict(scope='usa')) #<--uncomment for Scattergeo() ... optional
layout['updatemenus'] = updatemenus

# Plot data
fig = go.Figure(data=data, layout=layout)
pyo.offline.plot(fig)

Plots with go.Scatter()

(Left: Plot for button ' single_plot '; Right: plot for button ' multi_plots ')

Note, here the plot on the right-side data points show correctly after pressing 'multi_points' button .

在此处输入图片说明

Plots with go.Scattergeo()

(Left: Plot for button ' single_plot '; Right: plot for button ' multi_plots ')

Note, here the data points are missing in the plot on the right-side after pressing ' multi_points ' button.

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM