Including local javascript within a tab

I’m trying to embed a javascript genome browser (https://jbrowse.org/docs/embedding.html#embedding-in-a-div-with-dynamic-configs) within a tab.

I’ve read the section on running local js in https://dash.plot.ly/external-resources. As best I can tell, that executes a piece of javascript when you first enter the app.

If I have the following app layout:

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div(children=[
    
    html.Tr([
        html.Td(children=[ generateColumns(tier0df)]),
        html.Td([
            dcc.Tabs(id="tabs", value='tab-1',   children=[
            dcc.Tab(label='Tier 1', value="tab-1"),
            dcc.Tab(label='Tier 2', value='tab-2'),
            dcc.Tab(label='Genome Browser', value='tab-3')
            ],style=tabs_styles),
            html.Div(id='tabs-content'),
            ], style={"width":80}),
    ])
    ], className='row' )

app.css.append_css({
    'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'
})

This executes the js file found in assets directory, as the external resources pages suggests it should - but only when the the app is first entered. I’ve got the following callback,

def render_content(tab, selectedColumns):
    if tab == 'tab-1':
        return html.Div([
            generate_table(tier0df, selectedColumns)
        ])
    elif tab == 'tab-2':
        return html.Div([
            generate_table(tier1df,selectedColumns)
        ])
    elif tab == 'tab-3':
        return html.Div([
         *<something something something call js here>*   
        ])

How does one call the relevant piece of javascript code only when the 3rd tab is selected and embed the results in that tab?

Thanks
Ben.

If clicking on the tab is the only action that changes the tab then your request seems unnecessary since it can be pre-computed.

If you want to ignore that piece of wisdom then use a client side callback https://dash.plot.ly/performance

I’m missing something that to you, I think is obvious. The javascript generates an app that user can then use, if that piece of code runs when I’m on tab1 (i.e. the entry point), what to do I do so that it’s not visible on tab 1 but visible on tab3?

The jbrowse docs you link mentions a few methods.

iFrame

app.layout = html.Div(children=[

app.layout = html.Div(children=[
    dcc.Tabs(id="tabs", value='tab-1', children=[
        dcc.Tab(label='Tier 1', value="tab-1"),
        dcc.Tab(label='Tier 2', value='tab-2'),
        dcc.Tab(label='Genome Browser', value='tab-3', children=[
            html.Iframe(src="URL TO THE GENOME BROWSER GOES HERE")
        ]),
    ])
])

directly in a div

For this you need to setup files to be served out of the dist directory either with your external web server or via flask.

app = dash.Dash(
    __name__,
    external_scripts=["/dist/main.bundle.js"]
)

app.layout = html.Div(children=[
    dcc.Tabs(id="tabs", value='tab-1', children=[
        dcc.Tab(label='Tier 1', value="tab-1"),
        dcc.Tab(label='Tier 2', value='tab-2'),
        dcc.Tab(label='Genome Browser', value='tab-3', children=[
            html.Div(
                className="jbrowse",
                id="GenomeBrowser",
                **{'data-config': '"baseUrl": "../",'
                                  '"dataRoot": "sample_data/json/volvox",'
                                    '"show_nav": false,'
                                    '"show_tracklist": false,'
                                    '"show_overview": false,'
                                    '"update_browser_title": false,'
                                    '"updateBrowserURL": false'}
            )
        ]),
    ])
])

embedding a div

Similar to before you need to setup files to be served out of the dist directory either with your external web server or via flask.

app.layout = html.Div(children=[
    dcc.Tabs(id="tabs", value='tab-1', children=[
        dcc.Tab(label='Tier 1', value="tab-1"),
        dcc.Tab(label='Tier 2', value='tab-2'),
        dcc.Tab(id="genome", label='Genome Browser', value='tab-3', children=[
            html.Div(id="GenomeBrowser", className="jbrowse")
        ]),
    ])
])

app.clientside_callback(
    ClientsideFunction("clientside", "tab_children"),
    Output(component_id="GenomeBrowser", component_property="children"),
    [Input("genome", "value")],
)

You also need to add a corresponding javascript file in /assets called clientside.js with something like

if (!window.dash_clientside) {
     window.dash_clientside = {}
 }

window.dash_clientside.clientside = {

    tab_children: function (tab_value) {

        var features = []
        // Add some features

        var config = {
          containerID: 'GenomeBrowser',
          baseUrl: '../',
          refSeqs: {
            url: 'https://s3.amazonaws.com/1000genomes/technical/reference/GRCh38_reference_genome/GRCh38_full_analysis_set_plus_decoy_hla.fa.fai',
          },
          tracks: [
            {
              key: 'GRCH38 Reference Sequence',
              label: 'GRCH38 Reference Sequence',
              urlTemplate: 'https://s3.amazonaws.com/1000genomes/technical/reference/GRCh38_reference_genome/GRCh38_full_analysis_set_plus_decoy_hla.fa'
            },
            {
              key: 'MyTrack',
              label: 'MyTrack',
              storeClass: 'JBrowse/Store/SeqFeature/FromConfig',
              features: features,
              type: 'CanvasVariants'
            }
          ]
        };

        // Add to the config or tracks

        // Instantiate JBrowse
        window.addEventListener('load', () => {
          window.JBrowse = new window.Browser( config );
        })

    },

}