anemia_analysis / app.py
venkatl's picture
Upload folder using huggingface_hub
5a377cd verified
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import gradio as gr
from io import BytesIO
import base64
import random
import scipy.stats as ss
from PIL import Image
def fig_to_pil(fig):
buf = BytesIO()
fig.savefig(buf, format="png", bbox_inches="tight")
buf.seek(0)
return Image.open(buf)
# -----------------------------
# Load Data
# -----------------------------
url = "https://docs.google.com/spreadsheets/d/1SE2Q7nuL-xCp52V8w5onlzySU4udZoqNUY2kGT3WV2s/export?format=xlsx"
df = pd.read_excel(url, sheet_name="Final")
numeric_cols = df.select_dtypes(include=['number']).columns
categorical_cols = df.select_dtypes(include=['object', 'category']).columns
# ----------------------------------------------------
# 1. Descriptive Statistics
# ----------------------------------------------------
def get_descriptive_stats():
stats = df[numeric_cols].describe().T
stats = stats.reset_index().rename(columns={"index": "Feature"})
return stats
def download_keyword_counts(df):
r = random.randint(1,1000)
path = f"keyword_counts_{r}.csv"
df.to_csv(path, index=False)
return path
# ----------------------------------------------------
# 2. Keyword Frequency Table + Plots
# ----------------------------------------------------
def keyword_frequency(column):
series = df[column].dropna().astype(str).str.split(',').explode().str.strip()
counts = series.value_counts().reset_index()
counts.columns = ["Keyword", "Count"]
# --- BAR CHART (matplotlib → PIL) ---
fig_bar, ax_bar = plt.subplots(figsize=(8,4))
ax_bar.bar(counts["Keyword"].head(15), counts["Count"].head(15))
ax_bar.set_title(f"Top Keywords in {column}")
ax_bar.set_xticklabels(counts["Keyword"].head(15), rotation=45, ha='right')
bar_img = fig_to_pil(fig_bar)
plt.close(fig_bar)
# --- PIE CHART (matplotlib → PIL) ---
fig_pie, ax_pie = plt.subplots(figsize=(6,6))
ax_pie.pie(
counts["Count"].head(10),
labels=counts["Keyword"].head(10),
autopct="%1.1f%%"
)
ax_pie.set_title(f"Pie Chart {column} (Distribution)")
pie_img = fig_to_pil(fig_pie)
plt.close(fig_pie)
# --- HORIZONTAL BAR CHART ---
fig_hbar, ax_hbar = plt.subplots(figsize=(8,6))
ax_hbar.barh(counts["Keyword"].head(15), counts["Count"].head(15))
ax_hbar.set_title(f"Top Keywords in {column} (Horizontal Bar)")
plt.tight_layout()
hbar_img = fig_to_pil(fig_hbar)
plt.close(fig_hbar)
# --- PARETO CHART (80/20) ---
counts_sorted = counts.sort_values("Count", ascending=False)
cum_percentage = (counts_sorted["Count"].cumsum() / counts_sorted["Count"].sum()) * 100
fig_pareto, ax1 = plt.subplots(figsize=(8,4))
ax1.bar(counts_sorted["Keyword"].head(15), counts_sorted["Count"].head(15), color='skyblue')
ax2 = ax1.twinx()
ax2.plot(counts_sorted["Keyword"].head(15), cum_percentage.head(15), color='red', marker="o")
ax1.set_xticklabels(counts_sorted["Keyword"].head(15), rotation=45, ha='right')
ax1.set_title(f"Pareto Analysis of {column}")
pareto_img = fig_to_pil(fig_pareto)
plt.close(fig_pareto)
# --- SCATTER PLOT (Rank vs Frequency) ---
counts["Rank"] = range(1, len(counts) + 1)
fig_scatter, ax_scatter = plt.subplots(figsize=(6,4))
ax_scatter.scatter(counts["Rank"], counts["Count"])
ax_scatter.set_title(f"Rank vs Frequency for {column}")
ax_scatter.set_xlabel("Rank (1 = most common)")
ax_scatter.set_ylabel("Frequency")
scatter_img = fig_to_pil(fig_scatter)
plt.close(fig_scatter)
# --- CUMULATIVE DISTRIBUTION PLOT ---
fig_cum, ax_cum = plt.subplots(figsize=(6,4))
ax_cum.plot(cum_percentage.values)
ax_cum.set_title(f"Cumulative Distribution of {column}")
ax_cum.set_ylabel("Cumulative %")
ax_cum.set_xlabel("Keyword Rank")
cum_img = fig_to_pil(fig_cum)
plt.close(fig_cum)
return counts, bar_img, pie_img, hbar_img, pareto_img, scatter_img, cum_img
# ----------------------------------------------------
# 3. Correlation Explorer
# ----------------------------------------------------
def explore_two_columns(col1, col2):
c1 = df[col1]
c2 = df[col2]
images = []
result_text = ""
# NUMERIC vs NUMERIC
if col1 in numeric_cols and col2 in numeric_cols:
# Pearson
corr = c1.corr(c2)
result_text = f"Pearson Correlation = {corr:.4f}"
# Scatter
fig, ax = plt.subplots(figsize=(6,4))
ax.scatter(c1, c2)
ax.set_xlabel(col1)
ax.set_ylabel(col2)
ax.set_title(f"{col1} vs {col2} (Scatter)")
images.append(fig_to_pil(fig))
plt.close(fig)
# Regression
fig, ax = plt.subplots(figsize=(6,4))
sns.regplot(x=c1, y=c2, ax=ax)
ax.set_title("Regression Line")
images.append(fig_to_pil(fig))
plt.close(fig)
# Distributions
fig, ax = plt.subplots(figsize=(6,4))
sns.histplot(c1, color="blue", kde=True, label=col1)
sns.histplot(c2, color="orange", kde=True, label=col2)
ax.legend()
ax.set_title("Distribution Comparison")
images.append(fig_to_pil(fig))
plt.close(fig)
print(result_text)
return result_text, None, images[0], images[1], images[2]
# CATEGORICAL vs CATEGORICAL
if col1 in categorical_cols and col2 in categorical_cols:
confusion = pd.crosstab(c1, c2)
v = cramers_v(confusion)
result_text = f"Cramér’s V = {v:.4f}"
conf = pd.crosstab(c1,c2, margins=True, margins_name="Total")
conf_table = conf.reset_index()
conf_table.columns = ["Category_1"] + list(conf.columns)
# Heatmap
fig, ax = plt.subplots(figsize=(6,4))
sns.heatmap(confusion, cmap="Blues", annot=True, fmt="d")
ax.set_title("Crosstab Heatmap")
images.append(fig_to_pil(fig))
plt.close(fig)
# Bar chart
fig, ax = plt.subplots(figsize=(6,4))
confusion.sum(axis=1).plot(kind='bar', ax=ax)
ax.set_title(f"Correlation between {col1} and {col2}")
images.append(fig_to_pil(fig))
plt.close(fig)
print(result_text)
return result_text, conf_table, images[0], images[1], None
# MIXED TYPES (numeric + categorical)
# Ensure correct assignment
if col1 in categorical_cols and col2 in numeric_cols:
cat = col1; num = col2
else:
cat = col2; num = col1
result_text = f"Numeric vs Categorical Analysis ({num} by {cat})"
# Boxplot
fig, ax = plt.subplots(figsize=(6,4))
sns.boxplot(x=df[cat], y=df[num], ax=ax)
ax.set_title("Boxplot")
plt.xticks(rotation=45, ha='right')
images.append(fig_to_pil(fig))
plt.close(fig)
# Violin plot
fig, ax = plt.subplots(figsize=(6,4))
sns.violinplot(x=df[cat], y=df[num], ax=ax)
ax.set_title("Violin Plot")
plt.xticks(rotation=45, ha='right')
images.append(fig_to_pil(fig))
plt.close(fig)
print(result_text)
return result_text, None, images[0], images[1], None
def cramers_v(confusion_matrix):
""" Cramér's V for categorical correlation """
chi2 = ss.chi2_contingency(confusion_matrix)[0]
n = confusion_matrix.sum().sum()
r, k = confusion_matrix.shape
return np.sqrt(chi2 / (n * (min(r, k) - 1)))
def compute_correlation(col1, col2):
c1 = df[col1]
c2 = df[col2]
# Case 1: numeric vs numeric
if col1 in numeric_cols and col2 in numeric_cols:
corr = c1.corr(c2)
return f"Pearson Correlation = {corr:.4f}", None
# Case 2: categorical vs categorical → Cramér’s V
if col1 in categorical_cols and col2 in categorical_cols:
confusion = pd.crosstab(c1, c2)
v = cramers_v(confusion)
return f"Cramér’s V = {v:.4f}", confusion
# Case 3: keyword frequency vs numeric/categorical
# Convert col1 or col2 (if comma-separated) into frequency counts
def keyword_expand(col):
return df[col].dropna().astype(str).str.split(',').explode().str.strip()
if col1 in categorical_cols:
k = keyword_expand(col1)
k_counts = k.value_counts()
df_k = df.assign(**{f"{col1}_KEYWORD_COUNTS": df[col1].fillna("").apply(
lambda x: sum([k_counts.get(i.strip(), 0) for i in x.split(',') if i.strip()])
)})
c1 = df_k[f"{col1}_KEYWORD_COUNTS"]
if col2 in categorical_cols:
k = keyword_expand(col2)
k_counts = k.value_counts()
df_k = df.assign(**{f"{col2}_KEYWORD_COUNTS": df[col2].fillna("").apply(
lambda x: sum([k_counts.get(i.strip(), 0) for i in x.split(',') if i.strip()])
)})
c2 = df_k[f"{col2}_KEYWORD_COUNTS"]
corr = c1.corr(c2)
return f"Keyword-Frequency Based Correlation = {corr:.4f}", None
# ----------------------------------------------------
# Gradio UI
# ----------------------------------------------------
with gr.Blocks(title="DATA ANALYSIS APP") as app:
gr.Markdown("# 📊 Youth Nutritional Data Analysis System \nUpload → Analyse → Export\n Developed by Dr. Indira Priyadarsini")
with gr.Tab("ℹ️ About & Citation"):
from a import citation
gr.Markdown(citation)
with gr.Tab("1️⃣ Descriptive Statistics"):
btn_stats = gr.Button("Generate Stats")
stats_out = gr.Dataframe()
btn_stats.click(get_descriptive_stats, outputs=stats_out)
with gr.Tab("2️⃣ Keyword Frequency Explorer"):
col_select = gr.Dropdown(choices=list(categorical_cols), label="Select Column")
freq_table = gr.Dataframe(label="Keyword Counts")
bar_plot = gr.Image(label="Bar Chart")
pie_img = gr.Image(label="Pie Chart")
hbar_img = gr.Image(label="Horizontal Bar Chart")
pareto_img = gr.Image(label="Pareto Chart")
scatter_img = gr.Image(label="Rank vs Frequency Scatter")
cum_img = gr.Image(label="Cumulative Distribution")
download_btn = gr.Button("Download as CSV")
download_file = gr.File(label="Download File")
col_select.change(keyword_frequency,
inputs=col_select,
outputs=[freq_table, bar_plot, pie_img,hbar_img, pareto_img, scatter_img, cum_img])
download_btn.click(
download_keyword_counts,
inputs=freq_table,
outputs=download_file
)
with gr.Tab("4️⃣ Two-Column Relationship Explorer"):
colA = gr.Dropdown(choices=df.columns.tolist(), label="Column A")
colB = gr.Dropdown(choices=df.columns.tolist(), label="Column B")
btn_rel = gr.Button("Explore Relationship")
rel_text = gr.Textbox(label="Summary")
rel_table = gr.Dataframe(label="Crosstab (if categorical)")
rel_img1 = gr.Image()
rel_img2 = gr.Image()
rel_img3 = gr.Image()
btn_rel.click(
explore_two_columns,
inputs=[colA, colB],
outputs=[rel_text, rel_table, rel_img1, rel_img2, rel_img3]
)
with gr.Tab("3️⃣ Correlation Explorer"):
col_select = gr.Dropdown(choices=categorical_cols.tolist(), label="Select Column")
col1 = gr.Dropdown(choices=df.columns.tolist(), label="Column 1")
col2 = gr.Dropdown(choices=df.columns.tolist(), label="Column 2")
corr_btn = gr.Button("Compute Correlation")
corr_text = gr.Textbox(label="Correlation Result")
confusion_out = gr.Dataframe(label="Categorical Crosstab (if applicable)")
corr_btn.click(compute_correlation, inputs=[col1, col2], outputs=[corr_text, confusion_out])
app.launch(theme=gr.themes.Monochrome())