Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ After completing a milestone, create a pull request with your changes for review

- [x] Integrated evaluation metrics and plots into the Data Explorer page
- [x] Implemented modeling page with model selection, training, cross-validation, and export functionality
- [x] Added histogram, box plot, violin plot, and heatmap UI with export options

## PR17: Robust Error Handling

Expand Down
130 changes: 129 additions & 1 deletion pages/data_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,141 @@ def _corr(df):
with tempfile.NamedTemporaryFile(suffix=f".{export_fmt}") as tmp:
viz.export_figure(fig_pair, Path(tmp.name))
tmp.seek(0)
st.download_button(
st.download_button(
"Download Plot",
data=tmp.read(),
file_name=f"pair_plot.{export_fmt}",
mime=f"image/{export_fmt}",
)

st.subheader("Histogram")
with st.expander("Create Histogram"):
num_cols = data.select_dtypes(include="number").columns.tolist()
hist_col = st.selectbox(
"Column",
options=num_cols,
key="hist_col",
)
bins = st.slider(
"Bins",
5,
100,
20,
step=5,
key="hist_bins",
)
density = st.checkbox("Density", key="hist_density")
export_fmt_h = st.selectbox(
"Export Format",
["png", "jpg"],
key="hist_fmt",
)
if st.button("Generate Histogram") and hist_col:
fig_hist = viz.histogram(
data,
hist_col,
bins=bins,
density=density,
)
st.plotly_chart(fig_hist, use_container_width=True)
with tempfile.NamedTemporaryFile(suffix=f".{export_fmt_h}") as tmp:
viz.export_figure(fig_hist, Path(tmp.name))
tmp.seek(0)
st.download_button(
"Download Histogram",
data=tmp.read(),
file_name=f"histogram.{export_fmt_h}",
mime=f"image/{export_fmt_h}",
)

st.subheader("Box Plot")
with st.expander("Create Box Plot"):
x_col = st.selectbox(
"X Column",
options=data.columns.tolist(),
key="box_x",
)
num_cols = data.select_dtypes(include="number").columns.tolist()
y_col = st.selectbox(
"Y Column",
options=num_cols,
key="box_y",
)
export_fmt_b = st.selectbox(
"Export Format",
["png", "jpg"],
key="box_fmt",
)
if st.button("Generate Box Plot") and x_col and y_col:
fig_box = viz.box_plot(data, x=x_col, y=y_col)
st.plotly_chart(fig_box, use_container_width=True)
with tempfile.NamedTemporaryFile(suffix=f".{export_fmt_b}") as tmp:
viz.export_figure(fig_box, Path(tmp.name))
tmp.seek(0)
st.download_button(
"Download Box Plot",
data=tmp.read(),
file_name=f"box_plot.{export_fmt_b}",
mime=f"image/{export_fmt_b}",
)

st.subheader("Violin Plot")
with st.expander("Create Violin Plot"):
x_col_v = st.selectbox(
"X Column",
options=data.columns.tolist(),
key="violin_x",
)
num_cols = data.select_dtypes(include="number").columns.tolist()
y_col_v = st.selectbox(
"Y Column",
options=num_cols,
key="violin_y",
)
export_fmt_v = st.selectbox(
"Export Format",
["png", "jpg"],
key="violin_fmt",
)
if st.button("Generate Violin Plot") and x_col_v and y_col_v:
fig_violin = viz.violin_plot(data, x=x_col_v, y=y_col_v)
st.plotly_chart(fig_violin, use_container_width=True)
with tempfile.NamedTemporaryFile(suffix=f".{export_fmt_v}") as tmp:
viz.export_figure(fig_violin, Path(tmp.name))
tmp.seek(0)
st.download_button(
"Download Violin Plot",
data=tmp.read(),
file_name=f"violin_plot.{export_fmt_v}",
mime=f"image/{export_fmt_v}",
)

st.subheader("Heatmap")
with st.expander("Create Heatmap"):
heat_cols = st.multiselect(
"Columns",
options=data.select_dtypes(include="number").columns.tolist(),
default=data.select_dtypes(include="number").columns.tolist(),
key="heat_cols",
)
export_fmt_hm = st.selectbox(
"Export Format",
["png", "jpg"],
key="heat_fmt",
)
if st.button("Generate Heatmap") and heat_cols:
fig_heat = viz.heatmap(data[heat_cols])
st.plotly_chart(fig_heat, use_container_width=True)
with tempfile.NamedTemporaryFile(suffix=f".{export_fmt_hm}") as tmp:
viz.export_figure(fig_heat, Path(tmp.name))
tmp.seek(0)
st.download_button(
"Download Heatmap",
data=tmp.read(),
file_name=f"heatmap.{export_fmt_hm}",
mime=f"image/{export_fmt_hm}",
)

st.subheader("Insights")
for insight in eda.data_insights_summary(data):
st.write(f"- {insight}")
Expand Down
9 changes: 9 additions & 0 deletions tests/test_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ def test_modeling_page_widgets_exist():
assert "export_model" in content


def test_data_explorer_visualization_widgets_exist():
with open("pages/data_explorer.py", "r", encoding="utf-8") as f:
content = f.read()
assert "Generate Histogram" in content
assert "Generate Box Plot" in content
assert "Generate Violin Plot" in content
assert "Generate Heatmap" in content


def test_time_series_page_runs(monkeypatch):
import streamlit as st
from pages import time_series
Expand Down
13 changes: 9 additions & 4 deletions tests/test_viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,15 @@ def test_heatmap():

def test_export_figure(tmp_path):
df = sample_df()
fig = viz.bar_chart(df, 'cat', 'num1')
out = tmp_path / 'chart.html'
viz.export_figure(fig, out)
assert out.exists() and out.stat().st_size > 0
fig_bar = viz.bar_chart(df, 'cat', 'num1')
out_bar = tmp_path / 'chart.html'
viz.export_figure(fig_bar, out_bar)
assert out_bar.exists() and out_bar.stat().st_size > 0

fig_hist = viz.histogram(df, 'num1')
out_hist = tmp_path / 'hist.html'
viz.export_figure(fig_hist, out_hist)
assert out_hist.exists() and out_hist.stat().st_size > 0


def test_pair_plot_and_image_export(tmp_path):
Expand Down