Skip to content

Commit

Permalink
Merge pull request #262 from ploomber/streamlit_postgres_example
Browse files Browse the repository at this point in the history
Add example for Streamlit app that uses PostgreSQL
  • Loading branch information
neelasha23 authored Aug 3, 2024
2 parents 8fb619a + 6e210c4 commit f34af85
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 0 deletions.
5 changes: 5 additions & 0 deletions doc/apps/streamlit.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,12 @@ By default applications run with Python 3.11. Refer to this [section](../faq/faq

:::{grid-item-card} Mirascope URL extractor
:link: https://github.com/ploomber/doc/tree/main/examples/streamlit/mirascope-url-extractor
![](https://github.com/ploomber/doc/raw/main/examples/streamlit/mirascope-url-extractor/screenshot.png)
:::

:::{grid-item-card} Iris Dashboard Using PostgreSQL
:link: https://github.com/ploomber/doc/tree/main/examples/streamlit/postgres-connection
![](https://github.com/ploomber/doc/raw/main/examples/streamlit/postgres-connection/app.png)
:::

::::
26 changes: 26 additions & 0 deletions examples/streamlit/postgres-connection/README.md
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.
Binary file added examples/streamlit/postgres-connection/app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions examples/streamlit/postgres-connection/app.py
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()
4 changes: 4 additions & 0 deletions examples/streamlit/postgres-connection/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
streamlit
SQLAlchemy
psycopg2-binary
ucimlrepo

0 comments on commit f34af85

Please sign in to comment.