Another approach is to utilize the checkbox column of the data_editor’s column config. We use the data_editor because we allow the user to modify the checkbox.
Here is a sample app.
# Dataframe on the left side.
with cols[0]:
edited_df = st.data_editor(
df,
column_config={
'Question': st.column_config.TextColumn(
disabled=True, # do not allow the user to modify
),
'View': st.column_config.CheckboxColumn(width='small'),
'Pdf': None, # hide the column
},
use_container_width=True,
hide_index=False,
key='pdf',
on_change=change,
args=(df,)
)
Once the users selected a checkbox, it will trigger a pdf display in the right side.
This is done thru a callback in the editor.
def change(df):
"""A callback from data editor."""
delta = ss.pdf
# Save the index that has true value on the View column.
# 'edited_rows': {0: {'View': False}, 1: {'View': True}}
true_index = []
for k, v in delta['edited_rows'].items():
for k1, v1 in v.items():
if k1 == 'View' and v1:
true_index.append(k)
# Save the pdf file based on the index.
# If there are more than 1 true index, set the selected to None to
# not display any pdf.
if not true_index or len(true_index) > 1:
ss.selected_file = None
return
ss.selected_file = df.loc[true_index[0], 'Pdf']
If users selected more than 1 checkbox, don’t display any pdf.
You can actually program this such that the last selected checkbox will be displayed and deselect the others. But I am not doing this. The current implementation could be enough.
Full code
Just revise the entries in the data to suit your needs.
import base64
import streamlit as st
from streamlit import session_state as ss
import pandas as pd
st.set_page_config(layout='wide')
if 'selected_file' not in ss:
ss.selected_file = None
data = {
'Question': [
'Name an example of Bradley-Terry Model application?',
'Describe Split Finding Algorithm',
'What is solidjs?'
],
'Answer': ['', '', ''],
'Pdf': [
'./static/pdf/mm-bradley-terry-1079120141.pdf',
'./static/pdf/xgboost_arxiv.pdf',
'./static/pdf/solidjs_intro.pdf'
],
'View': [False, False, False]
}
def display_pdf(file, width=600, height=600):
try:
with open(file, "rb") as f:
base64_pdf = base64.b64encode(f.read()).decode('utf-8')
except Exception as err:
st.error(err)
else:
pdf_display = F'<embed src="data:application/pdf;base64,{base64_pdf}" width={width} height={height} type="application/pdf">'
st.markdown(pdf_display, unsafe_allow_html=True)
def change(df):
"""A callback from data editor."""
delta = ss.pdf
# Save the index that has true value on the View column.
# 'edited_rows': {0: {'View': False}, 1: {'View': True}}
true_index = []
for k, v in delta['edited_rows'].items():
for k1, v1 in v.items():
if k1 == 'View' and v1:
true_index.append(k)
# Save the pdf file based on the index.
# If there are more than 1 true index, set the selected to None to
# not display any pdf.
if not true_index or len(true_index) > 1:
ss.selected_file = None
return
ss.selected_file = df.loc[true_index[0], 'Pdf']
# Start
df = pd.DataFrame(data)
cols = st.columns([1, 1])
# Dataframe on the left side.
with cols[0]:
edited_df = st.data_editor(
df,
column_config={
'Question': st.column_config.TextColumn(
disabled=True, # do not allow the user to modify
),
'View': st.column_config.CheckboxColumn(width='small'),
'Pdf': None, # hide the column
},
use_container_width=True,
hide_index=False,
key='pdf',
on_change=change,
args=(df,)
)
# pdf view on the right side
with cols[1]:
if ss.selected_file:
display_pdf(ss.selected_file, width=700, height=700)
else:
st.info('Check a single checkbox under the View column on the dataframe in the left side.')