Put logo and title above/on top of page navigation in sidebar of streamlit multipage app
Asked Answered
S

4

8

I am using the new multipage feature and would like to style my multipage app and put a logo with a title on top of/before the page navigation.

Here's a small example tested on Python 3.9 with streamlit==1.11.1 in the following directory structure:

/Home.py
/pages/Page_1.py
/pages/Page_2.py

Home.py:

import streamlit as st


st.sidebar.markdown(
    "My Logo (sidebar) should be on top of the Navigation within the sidebar"
)

st.markdown("# Home")

Page_1.py:

import streamlit as st

st.markdown("Page 1")

Page_2.py:

import streamlit as st

st.markdown("Page 2")

which I can run using:

$ streamlit run Home.py

But this leads to the Text printed below and not above the navigation: enter image description here

Is there any way to do this? Any hints are welcome!

Best wishes, Cord

Seducer answered 5/8, 2022 at 14:3 Comment(0)
M
11

One option is to do it via CSS, with a function like this:

def add_logo():
    st.markdown(
        """
        <style>
            [data-testid="stSidebarNav"] {
                background-image: url(http://placekitten.com/200/200);
                background-repeat: no-repeat;
                padding-top: 120px;
                background-position: 20px 20px;
            }
            [data-testid="stSidebarNav"]::before {
                content: "My Company Name";
                margin-left: 20px;
                margin-top: 20px;
                font-size: 30px;
                position: relative;
                top: 100px;
            }
        </style>
        """,
        unsafe_allow_html=True,
    )

And then just call that function at the top of each page. That produces an effect like this: enter image description here

Maud answered 5/8, 2022 at 14:32 Comment(1)
This is now part of the python package streamlit-extras, which you can see in action here extras.streamlit.app/App%20logoMaud
S
7

Based on Zachary Blackwoods answer and an answer from the streamlit forum to also deliver local files encoded in a string, I came up with this solution in my Home.py:

import base64
import streamlit as st


@st.cache(allow_output_mutation=True)
def get_base64_of_bin_file(png_file):
    with open(png_file, "rb") as f:
        data = f.read()
    return base64.b64encode(data).decode()


def build_markup_for_logo(
    png_file,
    background_position="50% 10%",
    margin_top="10%",
    image_width="60%",
    image_height="",
):
    binary_string = get_base64_of_bin_file(png_file)
    return """
            <style>
                [data-testid="stSidebarNav"] {
                    background-image: url("data:image/png;base64,%s");
                    background-repeat: no-repeat;
                    background-position: %s;
                    margin-top: %s;
                    background-size: %s %s;
                }
            </style>
            """ % (
        binary_string,
        background_position,
        margin_top,
        image_width,
        image_height,
    )


def add_logo(png_file):
    logo_markup = build_markup_for_logo(png_file)
    st.markdown(
        logo_markup,
        unsafe_allow_html=True,
    )

add_logo("img/my_logo.png")

st.markdown("# Home")

@Zachary Blackwood: Feel free to put this in your answer and I will delete my one.

Hope it helps someone!

Seducer answered 8/8, 2022 at 13:39 Comment(0)
I
4

You can also achieve this result with PIL:

This function will enable you to take control of the logo size as well.

from PIL import Image
import streamlit as st

# You can always call this function where ever you want

def add_logo(logo_path, width, height):
    """Read and return a resized logo"""
    logo = Image.open(logo_path)
    modified_logo = logo.resize((width, height))
    return modified_logo

my_logo = add_logo(logo_path="your/logo/path", width=50, height=60)
st.sidebar.image(my_logo)

# OR

st.sidebar.image(add_logo(logo_path="your/logo/path", width=50, height=60)) 

You can call the function in your home page to display your logo, and should in case you have additional images to display in any of your pages.

Indigestion answered 5/8, 2022 at 15:3 Comment(3)
Thanks for your answer. But this does not solve the relevant issue of placing the logo on top of the multipage menu, or does it?Seducer
You are welcome, but it works by calling the function with st.image() before your home.Indigestion
Could you provide an example on how to use this in the Startpage (Home.py)? If I put this in a single module and call it as described, the logo is rendered below the page navigation and not on top of it.Seducer
S
0

I got a solution adding the image from a local file you...

import io
from PIL import Image
import base64

file = open("./LOGO.png", "rb")
contents = file.read()
img_str = base64.b64encode(contents).decode("utf-8")
buffer = io.BytesIO()
file.close()
img_data = base64.b64decode(img_str)
img = Image.open(io.BytesIO(img_data))
resized_img = img.resize((150, 60))  # x, y
resized_img.save(buffer, format="PNG")
img_b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")

st.markdown(
        f"""
        <style>
            [data-testid="stSidebarNav"] {{
                background-image: url('data:image/png;base64,{img_b64}');
                background-repeat: no-repeat;
                padding-top: 50px;
                background-position: 100px 50px;
            }}
        </style>
        """,
        unsafe_allow_html=True,
    )
Snooty answered 16/6, 2023 at 13:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.