Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: apply theme globally #2

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 191 additions & 45 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,163 @@
"Orange": "#FFA500"
}

# Helper function to set theme
def set_theme(fig, ax):
# Helper function to set the UI theme
def set_theme():
theme = st.session_state.get('theme', 'Light')

if theme == "Dark":
background_color = "#1E1E1E" # Dark background
text_color = "white" # Text color for dark background
slider_handle_color = "#FF4500" # Handle color for dark theme
slider_track_color = "#444444" # Track color for dark theme
uploader_background_color = "#2E2E2E" # Uploader background in dark mode
uploader_text_color = "white" # Text color for dark mode
uploader_icon_color = "white" # Icon color for dark mode
uploader_button_background = "#333333" # Uploader button background in dark mode
uploader_button_text_color = "white" # Uploader button text in dark mode
dropdown_background_color = "#2E2E2E" # Dropdown background in dark mode
dropdown_text_color = "white" # Dropdown text color in dark mode
dropdown_border_color = "#444444" # Border color in dark mode
else:
background_color = "#F0F0F0" # Light background
text_color = "black" # Text color for light background
slider_handle_color = "#007bc2" # Handle color for light theme
slider_track_color = "#D3D3D3" # Track color for light theme
uploader_background_color = "white" # Uploader background in light mode
uploader_text_color = "black" # Text color in light mode
uploader_icon_color = "black" # Icon color in light mode
uploader_button_background = "#F0F0F0" # Uploader button background in light mode
uploader_button_text_color = "black" # Uploader button text in light mode
dropdown_background_color = "white" # Dropdown background in light mode
dropdown_text_color = "black" # Dropdown text color in light mode
dropdown_border_color = "#D3D3D3" # Border color in light mode

st.markdown(f"""
<style>
.stApp {{
background-color: {background_color};
color: {text_color};
}}

/* Apply text color to all elements */
body, [data-testid="stAppViewContainer"] * {{
color: {text_color} !important;
}}

/* Sidebar background and color */
[data-testid="stSidebar"] {{
background-color: {background_color};
color: {text_color};
}}

/* Input elements */
input, select, textarea {{
background-color: {background_color};
color: {text_color};
}}

/* Dropdown specific styling */
select, .stSelectbox > div > div, .stSelectbox div[role="combobox"] > div {{
background-color: {dropdown_background_color} !important;
color: {dropdown_text_color} !important;
border: 1px solid {dropdown_border_color} !important;
}}

/* File uploader specific styling */
[data-testid="stFileUploader"] {{
background-color: {uploader_background_color} !important;
color: {uploader_text_color} !important;
border: 1px solid {dropdown_border_color} !important;
}}

/* File uploader drag-and-drop area */
[data-testid="stFileUploader"] > div {{
background-color: {uploader_background_color} !important;
color: {uploader_text_color} !important;
}}

/* More precise targeting for file uploader text (Drag and Drop area) */
[data-testid="stFileUploader"] div div span {{
color: {uploader_text_color} !important;
}}

/* Targeting file uploader icon color */
[data-testid="stFileUploader"] div div svg {{
color: {uploader_icon_color} !important;
fill: {uploader_icon_color} !important;
}}

/* File uploader button styling */
[data-testid="stFileUploader"] button {{
background-color: {uploader_button_background} !important;
color: {uploader_button_text_color} !important;
border: none;
}}

/* File uploader button hover effect */
[data-testid="stFileUploader"] button:hover {{
background-color: {slider_handle_color} !important;
color: {text_color} !important;
}}

/* Slider styling */
[data-testid="stSlider"] {{
color: {text_color};
}}
[data-testid="stSlider"] > div {{
background-color: transparent !important;
}}
[data-testid="stSlider"] [role="slider"] {{
background-color: {slider_handle_color} !important;
}}
[data-testid="stSlider"] .stSliderTrack {{
background-color: {slider_track_color} !important;
}}

/* Button styling */
[data-testid="stButton"] > button {{
background-color: {slider_handle_color};
color: {text_color};
}}
</style>
""", unsafe_allow_html=True)




# Helper function to set plot themes
def set_plot_theme():
theme = st.session_state.get('theme', 'Light')
if theme == "Dark":
plt.style.use('dark_background')
fig.patch.set_facecolor('#2E2E2E')
ax.set_facecolor('#2E2E2E')
else:
plt.style.use('default')
fig.patch.set_facecolor('white')
ax.set_facecolor('white')

# Set page config
st.set_page_config(
page_title="Learning Data Visualization",
page_icon="📊",
layout="wide",
initial_sidebar_state="expanded",
menu_items=None
)

# Initialize session state for theme if not already set
if 'theme' not in st.session_state:
st.session_state['theme'] = 'Light'

# Apply theme immediately
set_theme()

# Sidebar for user input
st.sidebar.title("Settings")
theme = st.sidebar.selectbox("Theme:", ["Light", "Dark"])
st.session_state['theme'] = theme
new_theme = st.sidebar.selectbox("Theme:", ["Light", "Dark"], key="theme_select")

# Update theme when changed
if new_theme != st.session_state['theme']:
st.session_state['theme'] = new_theme
set_theme()
st.rerun()

# Sliders to adjust figure size (now in the sidebar)
fig_width = st.sidebar.slider("Figure width", min_value=5, max_value=15, value=10)
Expand All @@ -43,52 +184,46 @@ def set_theme(fig, ax):
# Main content
st.title("Learning Data Visualization with MAIDR")


# Tabs for different plots
tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs([
"Practice", "Histogram", "Box Plot", "Scatter Plot", "Bar Plot", "Line Plot", "Heatmap"
])

# Function to render plots using Maidr
def render_maidr_plot(plot):
# Render the plot using maidr and display it in Streamlit
components.html(
maidr.render(
plot
).get_html_string(),
maidr.render(plot).get_html_string(),
scrolling=True,
height=fig_height * 100,
width=fig_width * 100,
)

# Practice tab: Allows users to upload a CSV and generate plots
# Practice tab: Allows users to upload a CSV and generate plots
# Practice tab
with tab1:
st.header("Practice with your own data")

# Upload CSV file
uploaded_file = st.file_uploader("Upload a CSV file", type=["csv"])

if uploaded_file is not None:
df = pd.read_csv(uploaded_file)
st.write("Data preview:", df.head())

# Select the plot type
plot_type = st.selectbox("Select plot type:", [
"Histogram", "Box Plot", "Scatter Plot", "Bar Plot", "Line Plot", "Heatmap"
])

# Color palette selection
plot_color = st.selectbox("Select plot color:", list(color_palettes.keys()))

# Select columns from uploaded data for plots
numeric_columns = df.select_dtypes(include=['float64', 'int64']).columns.tolist()
categorical_columns = df.select_dtypes(include=['object']).columns.tolist()

if plot_type == "Histogram":
var = st.selectbox("Select numeric variable for histogram:", numeric_columns)
if var:
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.histplot(data=df, x=var, kde=True, color=color_palettes[plot_color], ax=ax)
ax.set_title(f"{var}")
ax.set_xlabel(var)
Expand All @@ -98,8 +233,9 @@ def render_maidr_plot(plot):
var_x = st.selectbox("Select numerical variable for X-axis:", numeric_columns)
var_y = st.selectbox("Select categorical variable for Y-axis (optional):", [""] + categorical_columns)
if var_x:
fig, ax = plt.subplots(figsize=(10, 6))
set_theme(fig, ax)
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
# set_theme(fig, ax)
set_plot_theme()
if var_y:
sns.boxplot(x=var_y, y=var_x, data=df, palette=[color_palettes[plot_color]], ax=ax)
ax.set_title(f"{var_x} grouped by {var_y}")
Expand All @@ -116,7 +252,8 @@ def render_maidr_plot(plot):
y_var = st.selectbox("Select Y variable:", [col for col in numeric_columns if col != x_var])
if x_var and y_var:
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.scatterplot(data=df, x=x_var, y=y_var, color=color_palettes[plot_color], ax=ax)
ax.set_title(f"{x_var} vs {y_var}")
render_maidr_plot(ax)
Expand All @@ -125,7 +262,8 @@ def render_maidr_plot(plot):
var = st.selectbox("Select categorical variable for bar plot:", categorical_columns)
if var:
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.countplot(x=var, data=df, color=color_palettes[plot_color], ax=ax)
ax.set_title(f"{var}")
render_maidr_plot(ax)
Expand All @@ -135,19 +273,25 @@ def render_maidr_plot(plot):
y_var = st.selectbox("Select Y variable:", [col for col in numeric_columns if col != x_var])
if x_var and y_var:
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.lineplot(data=df, x=x_var, y=y_var, color=color_palettes[plot_color], ax=ax)
ax.set_title(f"{x_var} vs {y_var}")
render_maidr_plot(ax)

elif plot_type == "Heatmap":
x_var = st.selectbox("Select X variable:", numeric_columns)
y_var = st.selectbox("Select Y variable:", [col for col in numeric_columns if col != x_var])
x_var = st.selectbox("Select X variable:", df.columns)
y_var = st.selectbox("Select Y variable:", [col for col in df.columns if col != x_var])
if x_var and y_var:
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
sns.heatmap(pd.crosstab(df[x_var], df[y_var]), ax=ax, cmap="YlGnBu", annot=True)
ax.set_title(f"{x_var} vs {y_var}")
# set_theme(fig, ax)
set_plot_theme()
if df[x_var].dtype.kind in 'biufc' and df[y_var].dtype.kind in 'biufc':
pivot_table = df.pivot_table(values=y_var, columns=x_var, aggfunc='mean')
else:
pivot_table = pd.crosstab(df[y_var], df[x_var], normalize='all')
sns.heatmap(pivot_table, ax=ax, cmap="YlGnBu", annot=True, fmt=".2f")
ax.set_title(f"{y_var} vs {x_var}")
render_maidr_plot(ax)

# Histogram tab
Expand All @@ -160,7 +304,6 @@ def render_maidr_plot(plot):
])
hist_color = st.selectbox("Select histogram color:", list(color_palettes.keys()), key="hist_color")

# Generate data based on user selection
def hist_data():
if hist_type == "Normal Distribution":
return np.random.normal(size=1000)
Expand All @@ -175,15 +318,14 @@ def hist_data():
elif hist_type == "Multimodal Distribution":
return np.concatenate([np.random.normal(-2, 0.5, size=300), np.random.normal(2, 0.5, size=300), np.random.normal(5, 0.5, size=400)])

# Plot the histogram using Matplotlib
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.histplot(hist_data(), kde=True, bins=20, color=color_palettes[hist_color], edgecolor="white", ax=ax)
ax.set_title(f"{hist_type}")
ax.set_xlabel(hist_type)
ax.set_xlabel("Value")
ax.set_ylabel("Count")

# Render using Maidr
render_maidr_plot(ax)

# Box Plot tab
Expand All @@ -207,13 +349,13 @@ def box_data():
data = np.random.normal(loc=0, scale=1, size=1000)
return data[(data > -1.5) & (data < 1.5)]

# Plot the box plot using Matplotlib
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.boxplot(x=box_data(), ax=ax, color=color_palettes[box_color])
ax.set_title(f"{box_type}")
ax.set_xlabel("Value")

# Render using Maidr
render_maidr_plot(ax)

# Scatter Plot tab
Expand Down Expand Up @@ -241,14 +383,15 @@ def scatter_data():
y = -0.9 * x + np.random.uniform(size=num_points) * 0.1
return x, y

# Plot the scatter plot using Matplotlib
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
data_x, data_y = scatter_data()
sns.scatterplot(x=data_x, y=data_y, ax=ax, color=color_palettes[scatter_color])
ax.set_title(f"{scatter_type}")
ax.set_xlabel("X")
ax.set_ylabel("Y")

# Render using Maidr
render_maidr_plot(ax)

# Bar Plot tab
Expand All @@ -262,14 +405,15 @@ def bar_data():
values = np.random.randint(10, 100, size=5)
return categories, values

# Plot the bar plot using Matplotlib
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
categories, values = bar_data()
sns.barplot(x=categories, y=values, ax=ax, color=color_palettes[bar_color])
ax.set_title("Plot of Categories")
ax.set_xlabel("Categories")
ax.set_ylabel("Values")

# Render using Maidr
render_maidr_plot(ax)

# Line Plot tab
Expand All @@ -295,7 +439,8 @@ def line_data():

# Plot the line plot using Matplotlib
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
data_x, data_y = line_data()
sns.lineplot(x=data_x, y=data_y, ax=ax, color=color_palettes[line_color])
ax.set_title(f"{line_type}")
Expand All @@ -321,7 +466,8 @@ def heatmap_data():

# Plot the heatmap using Matplotlib
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
set_theme(fig, ax)
# set_theme(fig, ax)
set_plot_theme()
sns.heatmap(heatmap_data(), ax=ax, cmap="YlGnBu", annot=True, fmt=".2f")
ax.set_title(f"{heatmap_type}")

Expand Down