Esempio n. 1
0
def test_click_simple(dash_duo):
    call_count = Value("i", 0)

    app = Dash(__name__)
    app.layout = html.Div(
        [
            html.Div(id="container"),
            html.Button("Click", id="button", n_clicks=0),
            html.Iframe(id="video", allow="fullscreen", referrerPolicy="origin"),
        ]
    )

    @app.callback(Output("container", "children"), Input("button", "n_clicks"))
    def update_output(n_clicks):
        call_count.value += 1
        return "clicked {} times".format(n_clicks)

    dash_duo.start_server(app)

    dash_duo.find_element("#container")

    dash_duo.wait_for_text_to_equal("#container", "clicked 0 times")
    assert call_count.value == 1
    dash_duo.percy_snapshot("html button initialization")

    dash_duo.find_element("#button").click()

    dash_duo.wait_for_text_to_equal("#container", "clicked 1 times")
    assert call_count.value == 2
    dash_duo.percy_snapshot("html button click")

    assert not dash_duo.get_logs()

    assert dash_duo.find_element("#video").get_attribute("allow") == "fullscreen"
    assert dash_duo.find_element("#video").get_attribute("referrerpolicy") == "origin"
Esempio n. 2
0
def show_document(match: dict):
    url = f"/pdf/{match['pdf']}"
    iframe = dbc.Row(
        dbc.Col(html.Iframe(src=url, style={
            "width": "100%",
            "height": "100%"
        })),
        style={
            "resize": "vertical",
            "overflow-y": "hidden",
            "height": "1000px",
            "min-height": "100px",
        },
    )
    title = match["title"].replace("_", " ")
    title = " ".join([w.capitalize() for w in title.split()])
    title = dbc.Row(dbc.Col(html.H3(title)))
    date = html.A(
        match["date"],
        id={
            "type": "link_date",
            "date": match["date"]
        },
        href="#",
        n_clicks=0,
        style={
            "text-decoration": "none",
            "color": "inherit"
        },
    )
    tags = html.P([
        dbc.Badge(
            tag,
            id={
                "type": "link_tag",
                "tag": tag
            },
            href="#",
            n_clicks=0,
            color="primary",
            className="mr-1",
        ) for tag in match["tags"]
    ])
    data = dbc.Table(
        [
            html.Tbody([
                html.Tr([html.Td("Date"), html.Td(date)]),
                html.Tr([html.Td("Tags"), html.Td(tags)]),
            ])
        ],
        striped=True,
    )
    return dbc.Row([dbc.Col([title, data], width=4), dbc.Col(iframe)])
Esempio n. 3
0
def test_click_simple(dash_duo):
    call_count = Value("i", 0)

    app = Dash(__name__)
    app.layout = html.Div([
        html.Div(id="container"),
        html.Button("Click", id="button", n_clicks=0),
        html.Iframe(id="video", allow="fullscreen", referrerPolicy="origin"),
    ])

    @app.callback(
        Output("container", "children"),
        Input("button", "n_clicks"),
        # The new percy runner loads the page, so to get consistent behavior for
        # call_count we need to skip the initial call
        prevent_initial_call=True,
    )
    def update_output(n_clicks):
        call_count.value += 1
        return "clicked {} times".format(n_clicks)

    dash_duo.start_server(app)

    dash_duo.wait_for_text_to_equal("#container", "")

    assert call_count.value == 0

    dash_duo.find_element("#button").click()

    dash_duo.wait_for_text_to_equal("#container", "clicked 1 times")
    assert call_count.value == 1
    dash_duo.percy_snapshot("html button click")

    assert not dash_duo.get_logs()

    assert dash_duo.find_element("#video").get_attribute(
        "allow") == "fullscreen"
    assert dash_duo.find_element("#video").get_attribute(
        "referrerpolicy") == "origin"
Esempio n. 4
0
if metrics_available:
    samples_layout += [
        dbc.Row([
            dbc.Col(
                html.Div(children='text diff'),
                width=2,
                class_name=
                'mt-1 bg-light font-monospace text-break small rounded border',
            ),
            dbc.Col(
                html.Iframe(
                    id='_diff',
                    sandbox='',
                    srcDoc='',
                    style={
                        'border': 'none',
                        'width': '100%',
                        'height': '100%'
                    },
                    className='bg-light font-monospace text-break small',
                ),
                class_name=
                'mt-1 bg-light font-monospace text-break small rounded border',
            ),
        ])
    ]
samples_layout += [
    dbc.Row(dbc.Col(html.Audio(id='player', controls=True), ),
            class_name='mt-3 '),
    dbc.Row(dbc.Col(dcc.Graph(id='signal-graph')), class_name='mt-3'),
]
Esempio n. 5
0
def get_map_map(tab, dataset_selection, traveler, centrality_index, label_size,
                node_size):

    map_graph = diogenetGraph("map", dataset_selection, dataset_selection,
                              'locations_data.csv', 'travels_blacklist.csv')

    if tab == "map_maps":
        data = None
        mapa = None

        map_graph.current_centrality_index = centrality_index
        if traveler == "All" or traveler == []:
            map_graph.edges_filter = []
        else:
            for m_filter in traveler:
                map_graph.set_edges_filter(m_filter)
            map_graph.create_subgraph()

        data = map_graph.get_map_data(min_weight=node_size[0],
                                      max_weight=node_size[1])
        df = pd.DataFrame(data)

        #Folium base map configurations
        url = 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}'
        attribution = '&copy; <a href="https://developers.arcgis.com/">ArcGIS</a> '

        base_map = folium.Map(location=[35, 30],
                              min_zoom=4,
                              max_zoom=7,
                              zoom_start=6,
                              tiles=None,
                              attr=attribution)

        folium.TileLayer(
            tiles=url,
            show=True,
            attr=attribution,
            min_zoom=3,
            max_zoom=8,
            name="USGS - The National Map",
        ).add_to(base_map)

        markers_source = folium.FeatureGroup(name='Source').add_to(base_map)
        markers_target = folium.FeatureGroup(name='Target').add_to(base_map)

        for i in range(len(df['Source'])):
            #source marker
            popup_source = folium.Popup(str(
                "{} \n (lat = {:.1f}, \n lon={:.1f})".format(
                    df['Source'][i], df["SourceLatitude"][i],
                    df["SourceLongitude"][i])),
                                        parse_html=True,
                                        max_width=450)
            tooltip_source = "{} (lat = {:.1f}, lon={:.1f})".format(
                df['Source'][i], df["SourceLatitude"][i],
                df["SourceLongitude"][i])

            markers_source.add_child(
                folium.CircleMarker(location=(float(df["SourceLatitude"][i]),
                                              float(df["SourceLongitude"][i])),
                                    popup=popup_source,
                                    tooltip=tooltip_source,
                                    fill=True,
                                    color=df["SourceColor"][i],
                                    fill_color=df["SourceColor"][i],
                                    radius=int(df["SourceSize"][i] * 1.3)))

            #target marker
            popup_target = folium.Popup(str(
                "{} \n (lat = {:.1f}, \n lon={:.1f})".format(
                    df['Destination'][i], df["DestLatitude"][i],
                    df["DestLongitude"][i])),
                                        parse_html=True,
                                        max_width=450)
            tooltip_target = "{} (lat = {:.1f}, lon={:.1f})".format(
                df['Destination'][i], df["DestLatitude"][i],
                df["DestLongitude"][i])

            markers_target.add_child(
                folium.CircleMarker(location=(float(df["DestLatitude"][i]),
                                              float(df["DestLongitude"][i])),
                                    popup=popup_target,
                                    tooltip=tooltip_target,
                                    fill=True,
                                    color=df["DestinationColor"][i],
                                    fill_color=df["DestinationColor"][i],
                                    radius=int(df["DestinationSize"][i] *
                                               1.3)))

            # travel info line
            folium.PolyLine(
                [[df["SourceLatitude"][i], df["SourceLongitude"][i]],
                 [df["DestLatitude"][i], df["DestLongitude"][i]]],
                popup=folium.Popup(str("{} travel from {} to  {}".format(
                    df['Philosopher'][i], df["Source"][i],
                    df["Destination"][i])),
                                   parse_html=True,
                                   max_width=450),
                tooltip="{} travel from {} to  {}".format(
                    df['Philosopher'][i], df["Source"][i],
                    df["Destination"][i]),
                color='#ced4da',
                weight=1.5,
            ).add_to(base_map)

        suffix = ".html"
        temp_file_name = next(tempfile._get_candidate_names()) + suffix
        full_filename = os.path.abspath(
            os.path.join(os.path.dirname(__file__), '.', 'assets',
                         temp_file_name))

        #saving folium .html file
        folium.LayerControl().add_to(base_map)
        base_map.save(full_filename)
        return [
            html.Iframe(src=app.get_asset_url(f'{temp_file_name}'),
                        style={
                            "height": "100%",
                            "width": "100%"
                        })
        ]

    if tab == "map_metrics":

        if traveler == "All":
            all_travelers = sorted(list(set(map_graph.get_edges_names())))
            map_graph.edges_filter = []
            for m_filter in all_travelers:
                map_graph.set_edges_filter(m_filter)
            map_graph.create_subgraph()
        elif traveler == []:
            all_travelers = sorted(list(set(map_graph.get_edges_names())))
            map_graph.edges_filter = []
            for m_filter in all_travelers:
                map_graph.set_edges_filter(m_filter)
            map_graph.create_subgraph()
        else:
            map_graph.edges_filter = []
            for m_filter in traveler:
                map_graph.set_edges_filter(m_filter)
            map_graph.create_subgraph()

        def round_list_values(list_in):
            return [round(value, 4) for value in list_in]

        calculated_network_betweenness = list(
            pd.DataFrame.from_dict(
                nx.betweenness_centrality(
                    map_graph.networkx_subgraph).items())[1])
        calculated_network_degree = list(
            pd.DataFrame.from_dict(
                nx.degree_centrality(map_graph.networkx_subgraph).items())[1])
        calculated_network_closeness = list(
            pd.DataFrame.from_dict(
                nx.closeness_centrality(
                    map_graph.networkx_subgraph).items())[1])
        calculated_network_eigenvector = list(
            pd.DataFrame.from_dict(
                nx.eigenvector_centrality(
                    map_graph.networkx_subgraph).items())[1])

        calculated_degree = [
            round(value) for value in map_graph.calculate_degree()
        ]
        calculated_betweenness = round_list_values(
            map_graph.calculate_betweenness())
        calculated_closeness = round_list_values(
            map_graph.calculate_closeness())
        calculated_eigenvector = round_list_values(
            map_graph.calculate_eigenvector())

        dict_map_data_tables = {
            "City": map_graph.get_vertex_names(),
            "Degree": round_list_values(calculated_network_degree),
            "Betweeness": round_list_values(calculated_network_eigenvector),
            "Closeness": round_list_values(calculated_network_closeness),
            "Eigenvector": round_list_values(calculated_network_eigenvector),
        }

        df_map_data_tables = pd.DataFrame(dict_map_data_tables)

        dt_map = dash_table.DataTable(id='table-map',
                                      columns=[{
                                          "name": i,
                                          "id": i,
                                          'deletable': True
                                      } for i in df_map_data_tables.columns],
                                      style_data_conditional=[{
                                          'if': {
                                              'row_index': 'odd'
                                          },
                                          'backgroundColor':
                                          'rgb(220, 220, 220)',
                                      }],
                                      style_cell={'textAlign': 'center'},
                                      style_header={'textAlign': 'center'},
                                      page_current=0,
                                      page_size=20,
                                      page_action='custom',
                                      sort_mode='single',
                                      sort_by=[{
                                          'column_id': 'Degree',
                                          'direction': 'asc'
                                      }])

        foot_note = html.Div(children=[
            html.Span('Metrics obtained using the algorithms of '),
            html.A('Networkx',
                   href='https://networkx.org/documentation/stable/',
                   target='_blank')
        ])
        return [
            html.H6('Centrality Scores', className="mt-1 mb-2"),
            html.Hr(className='py-0'), dt_map, foot_note
        ]

    if tab == "map_graphs":

        map_graph.current_centrality_index = centrality_index

        graph_layout = "fr"
        pvis_graph = None

        if traveler == "All" or traveler == []:
            #map_graph.edges_filter = []
            pvis_graph = map_graph.get_pyvis(
                min_weight=node_size[0],
                max_weight=node_size[1],
                min_label_size=label_size[0],
                max_label_size=label_size[1],
                layout=graph_layout,
            )
        else:
            for m_filter in traveler:
                map_graph.set_edges_filter(m_filter)
            map_graph.create_subgraph()
            pvis_graph = map_graph.get_pyvis()

        if pvis_graph:
            suffix = ".html"
            temp_file_name = next(tempfile._get_candidate_names()) + suffix
            full_filename = os.path.abspath(
                os.path.join(os.path.dirname(__file__), '.', 'assets',
                             temp_file_name))

            pvis_graph.write_html(full_filename)
            return [
                html.Iframe(src=app.get_asset_url(f'{temp_file_name}'),
                            style={
                                "height": "100%",
                                "width": "100%"
                            })
            ]
Esempio n. 6
0
                  figure={
                      'data':
                      generate_flow_history_chart(),
                      'layout':
                      go.Layout(height=772, title='Nutrition Funding history')
                  })
    ],
             className='twelve columns'),
    html.Div([
        dcc.Graph(
            id='funding-chart-wfp-sankey',
            figure={
                'data': [generate_sankey_chart()],
                'layout':
                go.Layout(
                    height=772,
                    title='WFP Funding source and destination (15 largest)')
            })
    ],
             className='twelve columns'),
    html.Div([
        html.H4('WFP Market Prices Explorer'),
        html.Iframe(
            width=900,
            height=500,
            src=
            '//data.humdata.org/widget/WFP?type=WFP&datastore_id=bd88a565-bf6f-4827-b07b-fb3a65bbb01a&data_link_url=https%3A%2F%2Fdata.humdata.org%2Fdataset%2Fwfp-food-prices&embedded=true&title=Food+Market+Prices'
        )
    ])
])
Esempio n. 7
0
    def get_visuals(self):
        """Returns a diciontary with both dash and notebook ready visualization. 

        :return: Dash and notebook visuals
        :rtype: dict
        """
        D = self.D
        visuals = {"notebook":{},"dash":{}}
                
        r = self.r
        visuals["dash"]["D[r,r]"] = pyrplib.style.get_standard_data_table(self.D.loc[r.index,:].loc[:,r.index].reset_index(),"D_r_r")
        visuals["notebook"]["D[r,r]"] = self.D.loc[r.index,:].loc[:,r.index]
        
        Xstar_r_r = self.xstar_r_r
        visuals["dash"]["X*[r,r]"] = pyrplib.style.get_standard_data_table(Xstar_r_r.reset_index(),"X_r_r")
        visuals["notebook"]["X*[r,r]"] = Xstar_r_r
        
        # 'Red/Green plot':
        xstar_width_height = len(Xstar_r_r) * 10
        xstar_g=pyrankability.plot.show_single_xstar(Xstar_r_r)#centroid_x)
        xstar_g = xstar_g.properties(
            width=xstar_width_height,
            height=xstar_width_height
        )
        visuals["notebook"]["X* (red/green)"] = xstar_g
        plot_html = io.StringIO()
        xstar_g.save(plot_html, 'html')

        visuals["dash"]["X* (red/green)"] = html.Iframe(
            id='xstar_plot',
            height=str(xstar_width_height + 150),
            width=str(xstar_width_height + 150),
            sandbox='allow-scripts',
            srcDoc=plot_html.getvalue(),
            style={'border-width': '0px'}
        )
        
        # 'X*':
        xstar_width_height = len(Xstar_r_r) * 10
        xstar_g=pyrankability.plot.show_single_xstar(Xstar_r_r,red_green=False)
        xstar_g = xstar_g.properties(
            width=xstar_width_height,
            height=xstar_width_height
        )
        visuals["notebook"]["X* (greyscale)"] = xstar_g
        plot_html = io.StringIO()
        xstar_g.save(plot_html, 'html')

        visuals["dash"]["X* (greyscale)"] = html.Iframe(
            id='xstar2_plot',
            height=str(xstar_width_height + 150),
            width=str(xstar_width_height + 150),
            sandbox='allow-scripts',
            srcDoc=plot_html.getvalue(),
            style={'border-width': '0px'}
        )
        
        if len(self.solutions) > 1:
            # nearest and farthest
            outlier_solution = pd.Series(self.outlier_solution,
                                            index=D.index[np.array(self.outlier_solution)].astype(str),
                                            name="Farthest from Centroid")
            centroid_solution = pd.Series(self.centroid_solution,
                                            index=D.index[np.array(self.centroid_solution)].astype(str),
                                            name="Closest to Centroid")

            spider_g = pyrankability.plot.spider(outlier_solution,centroid_solution)
            spider_width = 700
            spider_height = 30 * len(outlier_solution)
            spider_g = spider_g.properties(
                width = spider_width,
                height = spider_height
            ).interactive()

            visuals["notebook"]["Nearest and Farthest"] = spider_g

            tmpfile = StringIO()
            spider_g.save(tmpfile, 'html')   
            visuals["dash"]["Nearest and Farthest"] = html.Iframe(
                id='nearest_farthest',
                height=str(spider_height + 100),
                width=str(spider_width + 400),
                sandbox='allow-scripts',
                # Once this function returns, tmpfile is garbage collected and may be 
                # the reason for 'view source' not working. 
                # TODO: Look into the return of getvalue() and implications that has on 'srcDoc'
                srcDoc=tmpfile.getvalue(), 
                style={'border-width': '0px'}
            )

            # Farthest pair
            #farthest_pair
            first,second = self.farthest_pair
            first_solution = pd.Series(first,
                                            index=D.index[np.array(first)].astype(str),
                                            name="Solution 1")
            second_solution = pd.Series(second,
                                            index=D.index[np.array(second)].astype(str),
                                            name="Solution 2")

            spider_g = pyrankability.plot.spider(first_solution,second_solution)
            spider_width = 500
            spider_height = 30 * len(second)
            spider_g = spider_g.properties(
                width = spider_width,
                height = spider_height
            ).interactive()

            visuals["notebook"]["Farthest Pair"] = spider_g

            tmpfile = StringIO()
            spider_g.save(tmpfile, 'html')   
            visuals["dash"]["Farthest Pair"] = html.Iframe(
                id='farthest_pair',
                height=str(spider_height + 100),
                width=str(spider_width + 600),
                sandbox='allow-scripts',
                # Once this function returns, tmpfile is garbage collected and may be 
                # the reason for 'view source' not working. 
                # TODO: Look into the return of getvalue() and implications that has on 'srcDoc'
                srcDoc=tmpfile.getvalue(), 
                style={'border-width': '0px'}
            )
        
        
        visuals["notebook"]["OBJECTIVE"] = self.obj
        visuals["dash"]["OBJECTIVE"] = self.obj
        visuals["notebook"]["BETA"] = self.beta
        visuals["dash"]["BETA"] = self.beta
        if len(self.solutions) > 1:        
            visuals["notebook"]["TAU Farthest Pair"] = self.tau_farthest_pair
            visuals["notebook"]["TAU Closest Pair"] = self.tau_closest_pair
            visuals["dash"]["TAU Farthest Pair"] = self.tau_farthest_pair
            visuals["dash"]["TAU Closest Pair"] = self.tau_closest_pair
        visuals["notebook"]["Number of optimal solutions found"] = len(self.solutions)
        visuals["dash"]["Number of optimal solutions found"] = len(self.solutions)
        
        return visuals
Esempio n. 8
0
                      value='Mitte',
                      clearable=False,
                      options=[{
                          'label': x,
                          'value': x
                      } for x in sorted(df.District.unique())])
     ],
             width=6),
 ]),
 dbc.Row([
     dbc.Col(
         [
             html.Iframe(
                 id='scatter-plot',
                 srcDoc=None,  # here is where we will put the graph we make
                 style={
                     'border-width': '5',
                     'width': '100%',
                     'height': '500px'
                 }),
         ],
         width=6),
     dbc.Col(
         [
             html.Iframe(
                 id='bar-plot',
                 srcDoc=None,  # here is where we will put the graph we make
                 style={
                     'border-width': '5',
                     'width': '100%',
                     'height': '500px'
                 }),
Esempio n. 9
0
        html.Div(
            [
                html.Div([
                    dcc.Graph(id='bar_chart',
                              style={'height': '650px'},
                              figure=bargraph)
                ]),  # , className = "fourteen columns"
            ],
            className="row"),
        html.Div(
            [
                html.Div([dcc.Graph(id='pie_chart', figure=piechart)
                          ]),  # , className = "eleven columns"
            ],
            className="row"),
        html.Div([
            html.Iframe(height='800px', width='100%', srcDoc=df_to_html(df)),
        ]),
    ],
    style={'backgroundColor': '#0091C7'})  # #70E3A0

# end = time.time()
# t_time = end - start
# print(t_time)

if __name__ == '__main__':

    app.run_server(debug=False)
    # from waitress import serve
    # serve(app, host="0.0.0.0", port=8080)
Esempio n. 10
0
                           className='mr-4',
                           style={'width': '15rem'})
        ], ),
        dbc.Row([
            dbc.Col(rows, width=12, lg=4, style={'margin-top': '2rem'}),
            dbc.Col(id='result-col', width=12, lg=8),
        ],
                className='mt-4'),
    ],
                  id='simulation-container'),
    dbc.Container(
        [
            html.Iframe(
                src='/documentation/index.html',
                style={
                    'width': '100%',
                    'height': '100%'
                },
            )
        ],
        id='documentation-container',
        className='p-0',
    ),
    html.Footer([
        html.A("FMPy %s" % fmpy.__version__,
               href='https://github.com/CATIA-Systems/FMPy',
               className='d-block text-muted small'),
    ],
                className='my-4 pt-3 border-top')
])
Esempio n. 11
0
import pandas as pd
from dash import html, Dash
from folium import Map, Marker
from folium.plugins import MarkerCluster
from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output

from dashboard.components.box import box

layout = html.Div([
    html.Div(id="qtd_sem_latlon"),
    html.Iframe(
        id="map",
        srcDoc=Map(height="89%")._repr_html_(),
        width="100%",
        height="800px",
    ),
])


def init_app(app: Dash) -> Dash:
    @app.callback(
        Output(component_id="qtd_sem_latlon", component_property="children"),
        Output("map", "srcDoc"),
        Input("filtered_data", "data"),
    )
    def create_map(data):
        if not data:
            raise PreventUpdate

        df = pd.DataFrame(data)
Esempio n. 12
0
def serve_layout():
    global cached_layout
    if cached_layout is None:
        logger.debug("Create new layout")
        fig_filter = FigureFilter()
        try:
            range_slider = dcc.RangeSlider(
                id='date-slider',
                min=min_millis,
                max=max_millis,
                step=step,
                marks=marks,
                value=[min_millis, max_millis],
            )
            summary_tab = [
                dbc.Container(dbc.Row(id="summary-cards",
                                      children=create_card(
                                          figures.SUMMARY_CARDS)),
                              fluid=True),
                fig_filter.add_graph(dcc.Graph(id="consumption_fig"),
                                     "start_at", ["consumption_km"],
                                     figures.consumption_fig),
                fig_filter.add_graph(dcc.Graph(id="consumption_fig_by_speed"),
                                     "speed_average", ["consumption_km"] * 2,
                                     figures.consumption_fig_by_speed),
                fig_filter.add_graph(dcc.Graph(id="consumption_graph_by_temp"),
                                     "consumption_by_temp",
                                     ["consumption_km"] * 2,
                                     figures.consumption_fig_by_temp)
            ]
            maps = fig_filter.add_map(
                dcc.Graph(id="trips_map", style={"height": '90vh'}), "lat",
                ["long", "start_at"], figures.trips_map)
            fig_filter.add_table("trips", figures.table_fig)
            fig_filter.add_table("chargings", figures.battery_table)
            fig_filter.src = {
                "trips": trips.get_trips_as_dict(),
                "chargings": chargings
            }
            fig_filter.set_clientside_callback(dash_app)
            create_callback()
        except (IndexError, TypeError, NameError, AssertionError, NameError,
                AttributeError):
            summary_tab = figures.ERROR_DIV
            maps = figures.ERROR_DIV
            logger.warning(
                "Failed to generate figure, there is probably not enough data yet",
                exc_info_debug=True)
            range_slider = html.Div()
            figures.battery_table = figures.ERROR_DIV

        data_div = html.Div([
            *fig_filter.get_store(),
            html.Div([
                range_slider,
                dbc.Tabs([
                    dbc.Tab(label="Summary",
                            tab_id="summary",
                            children=summary_tab),
                    dbc.Tab(
                        label="Trips",
                        tab_id="trips",
                        id="tab_trips",
                        children=[
                            html.Div(id="tab_trips_fig",
                                     children=figures.table_fig),
                            dbc.Modal(
                                [
                                    dbc.ModalHeader("Altitude"),
                                    dbc.ModalBody(
                                        html.Div(id="tab_trips_popup_graph")),
                                    dbc.ModalFooter(
                                        dbc.Button("Close",
                                                   id="tab_trips_popup-close",
                                                   className="ml-auto")),
                                ],
                                id="tab_trips_popup",
                                size="xl",
                            )
                        ]),
                    dbc.Tab(label="Charge",
                            tab_id="charge",
                            id="tab_charge",
                            children=[
                                figures.battery_table,
                                dbc.Modal(
                                    [
                                        dbc.ModalHeader("Charging speed"),
                                        dbc.ModalBody(
                                            html.Div(
                                                id="tab_battery_popup_graph")),
                                        dbc.ModalFooter(
                                            dbc.Button(
                                                "Close",
                                                id="tab_battery_popup-close",
                                                className="ml-auto")),
                                    ],
                                    id="tab_battery_popup",
                                    size="xl",
                                )
                            ]),
                    dbc.Tab(label="Map", tab_id="map", children=[maps]),
                    dbc.Tab(label="Control",
                            tab_id="control",
                            children=html.Iframe(
                                src=request.url_root + "control?header=false",
                                style={
                                    "position": "absolute",
                                    "height": "100%",
                                    "width": "100%",
                                    "border": "none"
                                }))
                ],
                         id="tabs",
                         active_tab="summary",
                         persistence=True),
                html.Div(id=EMPTY_DIV)
            ])
        ])
        cached_layout = data_div
    return cached_layout