Streamlit selectbox is reseting the webpage - python

I am currently trying to use the selectbox to allow the users to pick a name of a column to run a model with. When I put a selectbox in the sidebar I didn’t have an issue, but when I put the selectbox on the main page as soon as the user selects a option the wepage resets. the code is below. I am still new to streamlit, so I am not sure if I am using this properly. I appreciate the help!
#add a blank space in the columnName section
columnNames = [" "]
#grab the column names of the dataframe
for column in df.columns:
columnNames.append(column)
#place the selectboxe in the col1 slot
with col1:
#display the column names to the user
#So that they can select the columns they want to use
columnValue = st.multiselect("Select the column:", columnNames)
#place a button in col2 slot
with col2:
#a button to add the selected column to a list of want to use columns
addButtonList = st.button("Add to select list: ")
#when 'addButtonList' is selected take the value from
#'columnValue' and place it on the screen.
if(addButtonList):
st.write(columnValue)

There seems to be a way by setting the session_state to the button. Check this https://discuss.streamlit.io/t/the-button-inside-a-button-seems-to-reset-the-whole-app-why/1051 OR https://gist.github.com/tvst/faf057abbedaccaa70b48216a1866cdd for the detailed explanation.

Related

pandas groupby multiple columns with python and streamlit

I have a groupby function that i want to group multiple columns in order to plot a chart later.
The dataframe's columns are dynamic where user select it from a selectbox and multiselect widgets
The problem is that i am able now just to take the first or the last item from the multiselect widget like so:
some_columns_df = df.loc[:,['gender','country','city','hoby','company','status']]
some_collumns = some_columns_df.columns.tolist()
select_box_var= st.selectbox("Choose X Column",some_collumns)
multiselect_var= st.multiselect("Select Columns To GroupBy",some_collumns)
test_g3 = df.groupby([select_box_var,multiselect_var[0]]).size().reset_index(name='count')
if user select more than 1 item from the multiselect let say he choose 4 item it becomes like below:
test_g3 = df.groupby([select_box_var,multiselect_var[0,1,2,3]]).size().reset_index(name='count')
is this possible ?
multiselect_var is a list while select_box_var is a single variable. Put it inside a list and add both lists together.
Try this:
test_g3 = df.groupby([select_box_var] + multiselect_var).size().reset_index(name='count')
From streamlit docs for multiselect here, the api returns a list always. And your selectbox returns a string as you have a list of strings as option.
So your code can be modified to,
df.groupby([select_box_var] + multiselect_var).size().reset_index(name='count')

Python PyQt - deleting selected table rows, and deletes wrong rows if row isn't selected

So I have created a CSV database with PyQT5.The user Has the option to delete last row and selected row
So I have a problem with selecting and deleting selected row:
(I apologize if my problem is hard to understand I don't know how to explain it properly, so here is a small visual representation)
1.data1 1.data1
2.data2 -> user selects 2.data2 row and deletes it-> 2.data3
3.data3 3.data4
4.data4
-> but if the user decides to delete last row without selecting the row this is what happens
1.data1 1.data1
2.data3 2.data4
3.data4 -> user presses Delete row button, without selecting 3.data4 row ->
-> but the last row doesn't get deleted instead the index of previously selected row gets passed
and the last selected row gets deleted
I have managed to locate the problem somewhere in this block of code, My guess is the problem comes from the .currentIndex(), but I don't know how to set the currentIndex to be None or empty so that it doesn't carry a number.
def deleteSelectedRow(self):
self.chosenRow = self.table_Database.currentIndex().row()
print(self.chosenRow)
if self.chosenRow < 0:
return
else:
self.table_Database.removeRow(self.chosenRow)
I had tried setting it to a negative number but that caused the same effect the index of the selected row prevailed the same
The currentIndex() of an item view doesn't indicate a selected index: while normally using setCurrentIndex() also selects the index, you can have a current index even if none is selected.
When an index that was the current is removed from the view, Qt automatically sets (but does not select!) the new current to the previous row and/or column depending on what was removed, unless there is no available index (rowCount() or columnCount() return 0) or the deleted index was in the first row or column (in this case, it sets the first available row and/or column).
The simple solution is to check whether there's a selected index or not:
def deleteSelectedRow(self):
if self.table_Database.selectedIndexes():
row = self.table_Database.currentIndex().row()
else:
row = self.table_Database.rowCount() - 1
if row >= 0:
self.table_Database.removeRow(row)
Considering what explained above, you could also have extended selections which don't show what the "current index" is; if you're supporting selections upon more than one row, you should create a list of rows based on the selected indexes, and remove rows in reversed order:
def deleteSelectedRow(self):
selected = self.table_Database.selectedIndexes()
if selected:
# create a set of *unique* rows
rows = set(i.row() for i in selected)
else:
rows = [self.table_Database.rowCount() - 1]
for row in sorted(rows, reverse=True):
self.table_Database.removeRow(row)

Center Streamlit Button

How do I center a button with Streamlit so that the button is still clickable? Here is a small example for a button that returns random numbers:
import streamlit as st
import numpy as np
if st.button('Click'):
rand = np.random.standard_normal()
st.write(str(rand))
I've seen solutions with markdown for a title, but not for an interactive element like a button.
Right now that’s not supported in Streamlit, but we are working on it (see our Roadmap for more info).
Feel free to add your ideas to Customizable Layout for Streamlit discussion.
And thanks for using Streamlit!
col1, col2, col3 = st.beta_columns(3)
if col2.button('Click'):
st.write('hello')
As far as I know there is no standard way to align the button in the center. I have however found a quick fix. It's not the right way but does the job.
You can try out :
col1, col2, col3 , col4, col5 = st.beta_columns(5)
with col1:
pass
with col2:
pass
with col4:
pass
with col5:
pass
with col3 :
center_button = st.button('Button')
The following will create 5 columns and you can center your button in the third one while the other 4 remain empty. This is just a quick fix and not the correct way however it did the job for me.
Hope you liked it.
TL;DR;
import streamlit as st
st.markdown("----", unsafe_allow_html=True)
columns = st.columns((2, 1, 2))
button_pressed = columns[1].button('Click Me!')
st.markdown("----", unsafe_allow_html=True)
You will get the following result (if default: narrow streamlit page settings):
Streamlit columns
Streamlit docs defines columns() in the following way:
columns = st.columns(spec)
where specs are either int or a list (or a tuple). For example, st.columns([3, 1, 2]) creates 3 columns where the first column is 3 times the width of the second, and the last column is 2 times that width. Hence, you may play around with their relative width.
What is more useful, you will get a list of columns, so you may address them as consequent numbers. You may use that in case of flexible numbers of columns:
import streamlit as st
import random
column_qty = random.randint(1, 10) # random number of columns on each run
buttons_pressed = [] # here we will collect widgets
st.markdown("----", unsafe_allow_html=True)
# create all columns with arbitrary relative widths
columns = st.columns([random.randint(1, 3) for _ in range(column_qty)])
# Show widgets in them
for x, col in enumerate(columns):
# if you need a static widget, just use: `col.text("some text")`
buttons_pressed.append(col.checkbox(f'{x}')) # add widgets to the list
st.markdown("----", unsafe_allow_html=True)
st.text(f'Total columns: {column_qty}')
# Check each widget for its state
for x, btn in enumerate(buttons_pressed):
if btn:
st.write(f"{x}") # NOTE: some columns may be dropped next run!
A very useful thing for flex input forms.
Use:
_, _, _, col, _, _, _ = st.columns([1]*6+[1.18])
clicked = col.button('Button')
To create 3 columns, pick the center one and add a button to it, you can use:
import streamlit as st # 1.18.1
if st.columns(3)[1].button("click me"):
st.write("clicked")
This doesn't center the button within the column, though, so hacking the CSS seems to be a current option, but I suspect the classes aren't reliable:
style = "<style>.row-widget.stButton {text-align: center;}</style>"
st.markdown(style, unsafe_allow_html=True)
with st.empty():
if st.button("click me"):
st.button("clicked!")
Another centering approach, following existing answers, is to force the button's container to be smaller so it takes up most or all of the space in it, functionally centering it:
col = st.columns(7)[3] # use an odd number and pick the middle element
clicked = col.button("click me")
Better than that might be to keep 3 columns, but make the first and last large and fit the middle one roughly to the button size. Adjust to taste:
col = st.columns((3, 1, 3))[1] # adjust to taste, possibly using floats
clicked = col.button("click me")
Removing the flex property with custom CSS might help make this robust to different screen sizes so the button text doesn't squish when shrunk.
None of these approaches are entirely satisfactory, so I'm curious to hear any new developments.
See also How to center the title and an image in streamlit?.

PyQt Get cell from TableView with header label

I currently load the results of an SQL query into a TableView.
self.projectModel = QSqlQueryModel()
self.projectModel.setQuery(sql,db)
I then need to select a specific cell based on the header label (geometry). This column will move position depending on the different table that is search.
When the user clicks anywhere on the row (NOT the cell of geometry column) I would like to select the geometry column cell.
At the moment I have a this associated with the tableView
self.dlg.tableView.clicked.connect(self.cellClicked)
And in that function I have
row = self.projectModel.currentIndex()
If I use QTableView.model(row, column) to select the index, I have to speciify the row and column number. However, this would vary so I would want to do QTableView.model(row, 'geometry') however the model expects integers.
Any solutions?
thanks
So it seems all you need is a method to find a column from its header label, i.e. something like:
def columnFromLabel(self, label):
model = self.table.horizontalHeader().model()
for column in range(model.columnCount()):
if model.headerData(column, QtCore.Qt.Horizontal) == label:
return column
return -1

Python Tkinter : Assignment of A Matrix of Entry Boxes

I created a matrix of entry boxes using Tkinter and Python 2.3. What I want to do is to check the row of the entry box for a keyword and then insert a text into an entry box with the same row but of different column. For example, take a simple 3x3 entry box matrix:
Food Like Dislike
Apple Yes
Orange Yes
Let's say I have two lists that corresponds to each other as such:
1. [Apple, Orange]
2. [Dislike, Like]
I would like to check that if first element in list 1 is Apple and first element in list 2 is Dislike, then I want to insert a text "YES" into the entry box of 2nd row and 3rd column as shown in the above matrix.
I have appended the entry box indexes into two lists. First list contains the indices of the 1st column of entry boxes. Second list contains the 2nd and 3rd columns of the entry boxes. Problem is, how to determine the correspoding row and column of the entry box to insert the Yes???
Hope you can understand! This example is the most elementary one. My actual matrix consist of more rows and columns. An idea or sample code will help a lot.
Thank you Tkinter Gods.
Store references to the entry widgets in a dictionary of lists. Here's an example using the label as the key:
for item in list_of_things:
label = tk.Label(...)
column0 = tk.Entry(...)
column1 = tk.Entry(...)
matrix[label] = (column1, column2)
You can now get column1 of "Orange" with something like matrix["Orange"][1]

Categories