Skip to content

Write a Streamlit app with Ibis

Streamlit + Ibis = ❤

Ibis supports the streamlit experimental_connection interface, making it easier than ever to combine the powers of both tools!

Check out the example application below that shows the top N ingredients from a corpus of recipes using the ClickHouse backend!

And here's the source code for the application:

Source code
example_streamlit_app.py
from __future__ import annotations

import requests
import streamlit as st

from ibis import _
from ibis.streamlit import IbisConnection

st.set_page_config(page_title="Yummy Data", layout="wide")
st.title("Yummy Data :bacon:")


@st.cache_data
def get_emoji():
    resp = requests.get(
        "https://raw.githubusercontent.com/omnidan/node-emoji/master/lib/emoji.json"
    )
    resp.raise_for_status()
    emojis = resp.json()
    return emojis


options = [1, 5, 10, 25, 50, 100]


@st.cache_data
def query():
    return (
        con.tables.recipes.relabel("snake_case")
        .mutate(ner=_.ner.map(lambda n: n.lower()).unnest())
        .ner.topk(max(options))
        .relabel(dict(ner="ingredient"))
        .to_pandas()
        .assign(
            emoji=lambda df: df.ingredient.map(
                lambda emoji: f"{emojis.get(emoji, '-')}"
            )
        )
        .set_index("ingredient")
    )


emojis = get_emoji()

con = st.experimental_connection("ch", type=IbisConnection)

if n := st.radio("Ingredients", options, index=1, horizontal=True):
    table, whole = st.columns((2, 1))
    idx = options.index(n)
    k = 0
    base = query()
    for m in options[: idx + 1]:
        df = base.iloc[k:m]
        if not k:
            word = "first"
        elif m < n:
            word = "next"
        else:
            word = "last"

        uniq_emojis = " ".join(df.emoji[df.emoji != "-"].unique())
        table.header(f"{word.title()} {m - k:d}")
        table.subheader(uniq_emojis)

        table.dataframe(df, use_container_width=True)
        k = m

    b = base.iloc[:n]
    uniq_emojis = " ".join(b.emoji[b.emoji != "-"].unique())
    whole.header(f"Top {n:d}")
    whole.subheader(uniq_emojis)
    whole.dataframe(b, use_container_width=True)

Last update: July 28, 2023