Display order of widgets when using callbacks

I’ve made a very simple app that:

  1. Uses the file uploader widget to read in an Excel file
  2. Gets the user to choose a worksheet they’re interested in previewing using a selectbox dropdown
  3. Displays a preview of the worksheet

I’m using a callback from st.selectbox to display the preview, so that it only displays after the user has actively chosen a worksheet they’re interested in. But in order to do so I need to have defined my callback function before calling st.selectbox - and that’s leading the preview to appear above the file uploader and selectbox widgets in the app, rather than where I want it, below those widgets.

This is my code (Streamlit 1.3.1) and a screengrab of my output.

import streamlit as st
import pandas as pd

# CREATE APP
# Add file_uploader
uploaded_file = st.file_uploader(
    label='Upload a file', type=['xls', 'xlsx', 'xlsm'],
    key='file-uploader',
    help='''
        Upload an Excel file. The file must be
        closed in order for you to upload it.
    '''
)


# Define function that loads sheet preview
def load_sheet_preview():
    st.dataframe(df[st.session_state.selectbox_sheet])


# Add selectbox
if uploaded_file is not None:
    df = pd.read_excel(uploaded_file, sheet_name=None)      # sheet_name=None needs explicitly including - it isn't the default        # noqa: E501

    st.selectbox(
        key='selectbox_sheet',
        label='Select worksheet',
        options=df.keys(),
        on_change=load_sheet_preview
    )

I suspect I’ll kick myself when I hear the solution but I can’t think how to get around this. Wrapping the code that produces the file uploader and the selectbox in functions, ordered as I want them to appear in the app, doesn’t do it.

Thank you.

when you callback the load_sheet_preview function, you write to the page with st.dataframe. Since the callback function is written to the page before anything else during the streamlit reload, it means that the dataframe is written to the page before moving to the if uploaded_file is not None: statement.

I would need to thing about the solution some more, but maybe this helps you get there first.