Put logo and title above/on top of page navigation in sidebar of streamlit multipage app
Question:
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:
Is there any way to do this? Any hints are welcome!
Best wishes,
Cord
Answers:
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:
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.
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!
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:
Is there any way to do this? Any hints are welcome!
Best wishes,
Cord
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:
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.
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!