St.form getting displayed before st.title

Summary

After clicking the st.form button, the title of the page shifts down and the table is displayed at the top

Steps to reproduce

Code snippet:


import streamlit as st 
import base64
import os 
import openai
import pandas as pd
import numpy as np
from dotenv import load_dotenv

def header(url):
     st.markdown(
         f'<p style="color:#00308F;font-size:60px;font-weight: bold; font-family: fantasy; font-stretch: extra-expanded; font-style: italic">{url}</p>', unsafe_allow_html=True)

def configure():
    load_dotenv()

@st.cache_data
def get_img_as_base64(file):
    with open(file, "rb") as f:
        data = f.read()
    return base64.b64encode(data).decode()

def style_df(df):
    
    df['Rating'] = df['Rating'].astype(float)
    df_pred['Rating'] = df_pred['Rating'].map("{:,.1f}".format)                
    #df_pred.set_index('Strain',inplace=True)
               
       # style
    th_props = [
         ('font-size', '20px'),
         ('text-align', 'center'),
         ('font-weight', 'bold'),
         ('color', '#FF0000'),
         ('background-color', '#f7ffff'),
         ]
                                      
    td_props = [
         ('font-size', '16x'),
    #                 ('font-weight', 'bold'),
         ('color', '#FF0000'),
         ]
    table_hover = [
         ('background-color', 'yellow')
         ]
    table_size = [
         ('width','150%')
           ]
    styles = [
         dict(selector="th", props=th_props),
         dict(selector="td", props=td_props),
         dict(selector='tr:hover',props=table_hover),
         dict(selector='tr:hover',props=table_size)
         ]
       # table
    df2=df_pred.style.set_properties(**{'text-align':'left'}).set_table_styles(styles)
    return df2



openai.api_key=os.getenv('API_KEY')

st.set_page_config(page_title='Cannabis Strain Selector')
header("Cannabis Strain Recommendation System")

df = pd.read_csv(os.path.join(os.getcwd(),"cannabis.csv"))
df.replace(to_replace=['None'], value=np.nan, inplace=True)
df['Strain'] = df['Strain'].str.replace("-"," ")

flavor = (
    df['Flavor'].str.get_dummies(',').sum()
        .rename('Unique Flavors')
        .reset_index(name='count')
        .sort_values('count', ascending=False, ignore_index=True)
)

effects = (
    df['Effects'].str.get_dummies(',').sum()
        .rename('Unique Effects')
        .reset_index(name='count')
        .sort_values('count', ascending=False, ignore_index=True)
)

flavor = list(flavor['index'])
effects = list(effects['index'])





img = get_img_as_base64("image.png")
side = get_img_as_base64("side.png")
page_bg_img = f"""
<style>
[data-testid="stAppViewContainer"] > .main {{
background-image: url("data:image/png;base64,{img}");;
background-position: center; 
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
}}
</style>
"""
st.markdown(page_bg_img, unsafe_allow_html=True)

sidebar_bg_img = f"""
<style>
[data-testid="stSidebar"] > .css-6qob1r.e1fqkh3o3  {{
    background-image: url("data:image/png;base64,{side}");;
    background-position: 10% 80%;    
    }}
</style>
"""
st.markdown(sidebar_bg_img, unsafe_allow_html=True)




def both_val_not_provided(url):
    st.markdown(
        f'<p style="color:#FF0000;font-size:30px;font-weight: bold; font-family: fantasy; font-stretch: extra-expanded; font-style: italic">{url}</p>', unsafe_allow_html=True)

button_with_flav_eff = st.button("Recommend top 3 strains",key='flav_eff')

df_pred = pd.DataFrame(columns=['Strain','Type','Rating','Description'],index=range(3))



def generate_response(prompt):
    response = openai.Completion.create(
        engine="text-davinci-002",
        prompt=prompt,
        max_tokens=1024,
        n=1,
        stop=None,
        temperature=0.7,
        )
    return response.choices[0].text

def app():
    configure()
    flav = st.sidebar.multiselect(label = "Flavor",options = flavor,default=[])
    eff = st.sidebar.multiselect(label = "Effects", options = effects,default=[])
    if st.session_state.flav_eff==True:
        if flav==[] and eff==[]:
            both_val_not_provided("No option selected, select something")
            st.session_state.flav_eff==False
        if flav!=[] and eff==[]:
            both_val_not_provided("Select Effect as well")
            st.session_state.flav_eff==False
        if flav==[] and eff!=[]:
            both_val_not_provided("Select Flavor as well")
            st.session_state.flav_eff==False
        if flav!=[] and eff!=[]:
            prompt = f"Generate 3 cannabis strains that has {flav} flavors and {eff} effects."
            response = generate_response(prompt)
            response = response.strip()
            response = [y for y in (x.strip() for x in response.splitlines()) if y]
            
            bool_first_fail = True
            bool_second_fail = True
            bool_third_fail = True
            bool_fourth_fail = True
            
            #finding if chatgpt gives any response
            try:
                response[0] = response[0].split(':')[0]
                response[0] = response[0].split('1. ')[1]
            except Exception:
                st.subheader("No strain available, change inputs!")
                bool_first_fail = False
            
            #only executed if chatgpt gives response
            if bool_first_fail:
                #find if the chatgpt's strain exists in our database
                try:
                    x = list(df['Strain'].eq(response[0]))
                    y = x.index(True) 
                except Exception:
                    st.subheader("Strain doesn't exist in our database, but chatgpt gave response.")
                    bool_second_fail = False
                
                # executed if atleast one response from chatgpt exists in our database and can be displayed
                if bool_second_fail:
                    
                    #Saving the first reposnse in our database. 
                    df_pred.loc[df_pred.index[0], 'Strain'] = response[0]
                    df_pred.loc[df_pred.index[0], 'Type'] = df.iloc[y][1]
                    df_pred.loc[df_pred.index[0], 'Rating'] = df.iloc[y][2]
                    df_pred.loc[df_pred.index[0], 'Description'] = df.iloc[y][5]
                    
                    #check if second response is given by chatgpt or not
                    try:
                        
                        response[1] = response[1].split(':')[0]
                        response[1] = response[1].split('2. ')[1]
                        x = list(df['Strain'].eq(response[1]))
                        y = x.index(True)
                    except:
                        both_val_not_provided("I could find only 1 suggestion. Try again or just show one option ?")
                        st.write("before clicking")
                        st.write(st.session_state)
                        
                        def show_df():
                            df_pred.drop(index=[1,2],inplace=True)
                            df_pred.set_index('Strain',inplace=True)
                            df2 = style_df(df_pred)
                            return st.table(df2)
                        with st.form("Show what you have"):
                            submit = st.form_submit_button(on_click=show_df)

Expected behavior:

The title “Cannabis Recommendation System” should be at the top even after the prediction( after clicking the form button)

Actual behavior:

The table is displayed first and the title shifts down
after prediction

before prediction

Callback functions act as a prefix to the page run. If you render anything within a callback, it is going to get prepended to the next page load. If you don’t want this, then you can have your callback write information into session state and then retrieve it later on the page.

1 Like

Can u please modify my above code if possible?

@nikhiljha97

To fix this error, you need to initialize the flav_eff variable before using it in your code. You can do this by adding the following line of code at the beginning of your script:

st.session_state.flav_eff = False

didn’t work

Rather than writing the entire app for you (which isn’t a minimal reproducible example and not fun :wink:), we can give you pointers like the one below:

Here are two minimal examples that demonstrate the current undesired behavior, and how to fix it:

  1. The table is displayed at the top of the app :-1:
import streamlit as st
import pandas as pd

def show_df():
    # This callback is executed before the rest of the code
    # so the table is displayed before the subheader and so on
    st.table(pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}))

st.subheader("This is a subheader")

with st.form("Form"):
    text = st.text_input("Text input", key="text")
    btn = st.form_submit_button("Submit", on_click=show_df)

  1. Table is shown below the form submit button :+1:
import streamlit as st
import pandas as pd

def show_df():
    # Write dataframe to session state
    st.session_state.df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})

st.subheader("This is a subheader")

with st.form("Form"):
    text = st.text_input("Text input", key="text")
    btn = st.form_submit_button("Submit", on_click=show_df)

if btn:
    # display dataframe from session state upon submitting the form
    st.table(st.session_state.df)

You should be able to use the above concept and adapt it to your application. :balloon:

[edit] If I had to guess (and this may not work since your code isn’t reproducible), this could work:

def show_df():
    df_pred.drop(index=[1,2],inplace=True)
    df_pred.set_index('Strain',inplace=True)
    df2 = style_df(df_pred)
    st.session_state.df2 = df2
with st.form("Show what you have"):
    submit = st.form_submit_button(on_click=show_df)

if submit:
    st.table(st.session_state.df2)
1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.