-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #262 from ploomber/streamlit_postgres_example
Add example for Streamlit app that uses PostgreSQL
- Loading branch information
Showing
5 changed files
with
127 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Streamlit App Connected to Postgres | ||
To showcase the power of using a database with Streamlit apps to display live data, this app enables users to insert their own data into a table on their database. The new data is then automatically displayed and used in the app. | ||
|
||
![](app.png) | ||
|
||
You can try out the app [here](https://twilight-fog-4463.ploomberapp.io/). | ||
|
||
You can find the corresponding blog post [here](https://ploomber.io/blog/streamlit-postgres/). | ||
|
||
## Running the App | ||
In app.py, you will find this line of code. If you are deploying on the Ploomber Cloud, set this to True. | ||
|
||
```Python | ||
cloud = False | ||
``` | ||
|
||
To run this app locally ensure you replace `YOUR_URI` in | ||
```Python | ||
DB_URI = environ["DB_URI"] if cloud else "YOUR_URI" | ||
``` | ||
to your personal database URI and that you have installed all the packages listed in requirements.txt. Then, execute `streamlit run app.py` in your command line. | ||
|
||
## Deployment | ||
When deploying this app on Ploomber Cloud you should omit your personal DB URI from your `app.py` file so it doesn't get exposed. You can do this by setting `cloud = True` and leaving "YOUR_URI" unmodified in the code above. | ||
|
||
To access our URI, we instead need to set the `DB_URI` as a secret in the deployment environment. Refer to the [documentation](https://docs.cloud.ploomber.io/en/latest/user-guide/secrets.html) or [blog post](https://ploomber.io/blog/streamlit-postgres/) to learn more. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import streamlit as st | ||
from sqlalchemy import text, create_engine | ||
from os import environ | ||
from ucimlrepo import fetch_ucirepo | ||
|
||
|
||
# Updates iris table with the original dataset | ||
def upload_data(DB_URI): | ||
# Loading in iris dataset | ||
iris = fetch_ucirepo(name="Iris") | ||
iris_df = iris.data.original | ||
iris_df.reset_index(drop=True) | ||
|
||
engine = create_engine(DB_URI) | ||
with engine.connect() as engine_conn: | ||
iris_df.to_sql(name="iris", con=engine_conn, if_exists='replace', index=False) | ||
print("Data successfully uploaded.") | ||
engine.dispose() | ||
|
||
cloud = False | ||
DB_URI = environ["DB_URI"] if cloud else "YOUR DB_URI" | ||
conn_st = st.connection(name="postgres", type='sql', url = DB_URI) | ||
iris_data = conn_st.query("SELECT * FROM iris") | ||
|
||
st.title("Streamlit with Postgres Demo") | ||
|
||
# Display Metrics | ||
col1, col2, col3, col4 = st.columns(4) | ||
|
||
with col1: | ||
st.metric("Average Sepal Length (cm)", round(iris_data["sepal length"].mean(), 2)) | ||
with col2: | ||
st.metric("Average Sepal Width (cm)", round(iris_data["sepal width"].mean(), 2)) | ||
with col3: | ||
st.metric("Average Petal Length (cm)", round(iris_data["petal length"].mean(), 2)) | ||
with col4: | ||
st.metric("Average Petal Width (cm)", round(iris_data["petal width"].mean(), 2)) | ||
|
||
# Displays Scatterplot | ||
st.header("Scatter Plot") | ||
|
||
c1, c2 = st.columns(2) | ||
|
||
with c1: | ||
x = st.selectbox("Select X-Variable", options=iris_data.select_dtypes("number").columns, index=0) | ||
with c2: | ||
y = st.selectbox("Select Y-Variable", options=iris_data.select_dtypes("number").columns, index=1) | ||
|
||
scatter_chart = st.scatter_chart(iris_data, x=x, y=y, size=40, color='class') | ||
|
||
# Displays Dataframe | ||
st.dataframe(iris_data, use_container_width=True) | ||
|
||
# Creates sidebar to add data | ||
with st.sidebar: | ||
reset = st.button("Reset Data") | ||
st.header("Add Iris Data") | ||
st.subheader("After submitting, a query is executed that inserts a new datapoint to the 'iris' table in our database.") | ||
with st.form(key='new_data'): | ||
sepal_length = st.text_input(label="Sepal Length (cm)", key=1) | ||
sepal_width = st.text_input(label="Sepal Width (cm)", key=2) | ||
petal_length = st.text_input(label="Petal Length (cm)", key=3) | ||
petal_width = st.text_input(label="Petal Width (cm)", key=4) | ||
iris_class = st.selectbox(label="Iris Class (cm)", key=5, options=iris_data["class"].unique()) | ||
submit = st.form_submit_button('Add') | ||
st.subheader("After filling in the data fields and pressing 'Add', you should see the metrics, scatterplot, and dataframe update to represent the new point.") | ||
|
||
# Replaces dataset in database with original | ||
if reset: | ||
upload_data(DB_URI) | ||
st.cache_data.clear() | ||
st.rerun() | ||
|
||
# Inserts data into table | ||
if submit: | ||
with conn_st.session as s: | ||
new_data = (sepal_length, sepal_width, petal_length, petal_width, iris_class) | ||
q = """ | ||
INSERT INTO iris ("sepal length", "sepal width", "petal length", "petal width", "class") | ||
VALUES (:sepal_length, :sepal_width, :petal_length, :petal_width, :iris_class) | ||
""" | ||
s.execute(text(q), { | ||
'sepal_length': sepal_length, | ||
'sepal_width': sepal_width, | ||
'petal_length': petal_length, | ||
'petal_width': petal_width, | ||
'iris_class': iris_class | ||
}) | ||
s.commit() | ||
# Clears the cached data so that Streamlit fetches new data when updated. | ||
st.cache_data.clear() | ||
st.rerun() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
streamlit | ||
SQLAlchemy | ||
psycopg2-binary | ||
ucimlrepo |