Zoom box on line graph showing residual line

I’ve created a simple line plot using Plotly but when I zoom into any area of the plot, the original line doesn’t entirely vanish, leaving some data points showing from the original zoom, overplayed on the new zoom.
The plot is in a dash app and I’ve restarted the app multiple times and tried both chrome and safari with the same result.

Untitled

Any idea whats going on and how I can fix it?
Thanks in advance!

As an update to this, this doesn’t happen with a px.scatter plot, only the px.line. It also happens with a plotly.go figure
Also if its relevant this is in a multipage app with dash

Hi @dig , maybe you could add the code + data to enable us to reproduce this.

While recreating a simple example I came across something odd - I have a line to process my input data:

site_df = site_df.reindex(pd.date_range(start=site_df.index.min(),
                                                  end=site_df.index.max(),
                                                  freq='1D'))

This takes the time series data and reindexes it to fill in missing days with NaNs.
When I don’t have this line in the plot works perfectly in my app and the example one I was making. When I do include it, I get the zoom problem. Is this something to do with handling of NaNs?
I’ll post a minimal example shortly

Here is a simple recreation of my app:
app.py:

import dash
from dash import Dash, html, dcc
from flask import Flask

server = Flask(__name__)
app = Dash(name = __name__, server = server, use_pages=True)


intro_text = 'Example dash app'

app.layout = html.Div(children=[
    html.Div(className = 'header_container',
        children=[
    html.Div(id = 'sub_header',children=[html.P(intro_text)]),
    ]),
    html.Hr(),
    html.Div(
        [
            html.Div(
                dcc.Link(
                    f"{page['name']} - {page['path']}", href=page["relative_path"]
                )
            )
            for page in dash.page_registry.values()
        ]
    ),
    html.Hr(),
    html.Div(className = 'page_container', children = [
    dash.page_container
    ])
    ])


if __name__ == '__main__':
    app.run_server(debug=True)

pages/sub_page.py:

import dash
from dash import html, dcc, Input, Output
import plotly.express as px
import random
import pandas as pd
import numpy as np

dash.register_page(__name__, path = '/')

locs = {
    'Edinburgh':[],
    'Leicester':[],
    'Norwich':[],
    'Cardiff':[],
    'Aberdeen':[],
    'Belfast':[],
    'Execter':[],
    'Liverpool':[],
    'London':[]
}
locs = ['Edinburgh','Leicester','Norwich','Cardiff','Aberdeen','Belfast','Exeter','Liverpool','London']
lats = [55.923291,52.620781,52.623342,51.487850,57.154859,54.584325,50.737381,53.404520,51.524819]
lons = [-3.172652,-1.124332,1.239217,-3.177512,-2.128465,-5.934347,-3.534654,-2.965492,0.134019]
site_locs = pd.DataFrame({'SiteName':locs,'lats':lats, 'lons':lons})

fig = px.scatter_mapbox(site_locs, lat = 'lats',lon = 'lons',zoom = 5, hover_name = 'SiteName')
fig.update_layout(mapbox_style="open-street-map", margin=dict(l=0, r=0, t=0, b=0))
fig.update_layout(mapbox ={'center':{'lat':54.3,'lon':-2.2}})

fig.update_traces(marker=dict(size=12,color='darkcyan'),
                selector=dict(mode='markers'))

layout = html.Div([
    html.Div(className = 'main_map_page',children=[
    html.Div(id = 'map_holder', children=[
        dcc.Graph(id = 'location_map', figure = fig)
        ]),
    html.Div(className = 'info_container', children = [
        html.P(id = 'site_info',children = 'Site info here...'),
        html.Div(id = 'co2_line'),
        
    ])
])
])

@dash.callback(Output('site_info','children'),
                Output('co2_line','children'),
                Input('location_map', 'clickData'))
def get_site_info(clickdata):
    if clickdata:
        sitename = clickdata['points'][0]['hovertext']
    else:
        sitename = 'Leicester'

    date_range = pd.date_range('2022/01/01','2022/12/31')
    num_samples = random.randint(200,300)
    random_noise = np.random.uniform(-1,1,(len(date_range)))
    cycle = np.sin(np.linspace(-np.pi, 0, len(date_range))) * 10
    fake_data = cycle + random_noise 

    df = pd.DataFrame({'Data':fake_data}, index = date_range)
    # Randomly sample data to represent random missing data values 
    df = df.sample(frac=np.random.uniform(0.6,0.7))
    df.sort_index(inplace=True)
    df.index.name = 'Date'

    # This line seems to be the issue - 
    # commenting it out solves the zooming problem but the plot then fills in between the missing dates
    df = df.reindex(pd.date_range(start=df.index.min(),
                                                  end=df.index.max(),
                                                  freq='1D'))

    fig = px.line(df, x = df.index, y = 'Data')
    line_graph = dcc.Graph(figure = fig)

    return sitename, line_graph