File size: 8,223 Bytes
5c948de
448a580
 
 
 
5de0e74
448a580
b983e61
 
 
 
448a580
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5de0e74
e64ed76
 
 
 
5de0e74
 
e64ed76
5de0e74
 
e64ed76
5de0e74
448a580
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5c948de
448a580
5de0e74
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import streamlit as st
import pandas as pd
import plotly.express as px
from io import BytesIO
import base64
import os

import os
os.environ["STREAMLIT_RUNTIME_DIR"] = "/tmp"
os.environ["STREAMLIT_CACHE_DIR"] = "/tmp"

# PAGE CONFIGURATION
st.set_page_config(page_title="Telangana Minorities Residential Educational Institutions Society", layout="wide")

# Custom CSS for UI
st.markdown("""
    <style>
    .big-font {font-size:20px !important; font-weight:600;}
    .kpi-box {background-color:#f9f9f9; padding:15px; border-radius:10px; text-align:center; border: 1px solid #ddd;}
    </style>
""", unsafe_allow_html=True)

# DATA UPLOAD
st.title("Telangana Minorities Residential Educational Institutions Society Analysis Dashboard")
uploaded_file = st.file_uploader("Upload your dataset (Excel or CSV)", type=["xlsx", "csv"])

if uploaded_file:
    # βœ… Save uploaded file to /tmp to avoid permission error
    save_path = os.path.join("/tmp", uploaded_file.name)
    with open(save_path, "wb") as f:
        f.write(uploaded_file.getbuffer())

    # Read dataset
    if save_path.endswith(".xlsx"):
        df = pd.read_excel(save_path)
    else:
        df = pd.read_csv(save_path)

    st.success("Dataset uploaded successfully!")

    # Standardize column names
    df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
    df.fillna(0, inplace=True)

    # DYNAMIC COLUMN DETECTION
    def find_column(keyword):
        for col in df.columns:
            if keyword in col:
                return col
        return None

    columns = {
        "v_minority": {
            "sanctioned": find_column("vth_class_minority_sanction"),
            "admitted": find_column("vth_class_minority_admitted"),
            "vacancy": find_column("vth_class_minority_vacancies"),
            "attendance": find_column("total_school_attendance"),
        },
        "v_non_minority": {
            "sanctioned": find_column("vth_class_non_minority_sanction"),
            "admitted": find_column("vth_class_non_minority_admitted"),
            "vacancy": find_column("vth_class_non_minority_vacancies"),
            "attendance": find_column("total_school_attendance"),
        },
        "inter_minority": {
            "sanctioned": find_column("1st_year_minority_sanction"),
            "admitted": find_column("1st_year_minority_admitted"),
            "vacancy": find_column("1st_year_minority_vacancies"),
            "attendance": find_column("total_intermediate_attendance"),
        },
        "inter_non_minority": {
            "sanctioned": find_column("1st_year_non_minority_sanction"),
            "admitted": find_column("1st_year_non_minority_admitted"),
            "vacancy": find_column("1st_year_non_minority_vacancies"),
            "attendance": find_column("total_intermediate_attendance"),
        },
        "absentees": find_column("total_absentees"),
    }

    # FILTERS
    st.sidebar.header("Filters")
    level_filter = st.sidebar.radio("Select Level", ["V (School)", "Inter 1st Year"])
    category_filter = st.sidebar.radio("Select Category", ["Minority", "Non-Minority"])
    districts = st.sidebar.multiselect("Select District(s)", options=df["district"].unique(), default=df["district"].unique())
    search_college = st.sidebar.text_input("Search College Name (Optional)")

    df = df[df["district"].isin(districts)]
    if search_college:
        df = df[df["college_name"].str.contains(search_college, case=False, na=False)]

    # Map columns dynamically
    if level_filter == "V (School)":
        key = "v_minority" if category_filter == "Minority" else "v_non_minority"
    else:
        key = "inter_minority" if category_filter == "Minority" else "inter_non_minority"

    sanctioned_col = columns[key]["sanctioned"]
    admitted_col = columns[key]["admitted"]
    vacant_col = columns[key]["vacancy"]
    attendance_col = columns[key]["attendance"]
    absentees_col = columns["absentees"]

    # KPI CALCULATIONS
    total_sanctioned = df[sanctioned_col].sum()
    total_admitted = df[admitted_col].sum()
    total_vacant = df[vacant_col].sum()
    total_attendance = df[attendance_col].sum()
    total_absentees = df[absentees_col].sum()
    attendance_pct = round((total_attendance / (total_attendance + total_absentees)) * 100, 2) if (total_attendance + total_absentees) > 0 else 0

    # KPI DISPLAY
    col1, col2, col3, col4, col5, col6 = st.columns(6)
    col1.markdown(f"<div class='kpi-box'>🏫 <br><span class='big-font'>{total_sanctioned:,}</span><br>Total Sanctioned</div>", unsafe_allow_html=True)
    col2.markdown(f"<div class='kpi-box'>πŸŽ“ <br><span class='big-font'>{total_admitted:,}</span><br>Total Admitted</div>", unsafe_allow_html=True)
    col3.markdown(f"<div class='kpi-box'>πŸ“Œ <br><span class='big-font'>{total_vacant:,}</span><br>Total Vacant</div>", unsafe_allow_html=True)
    col4.markdown(f"<div class='kpi-box'>βœ… <br><span class='big-font'>{total_attendance:,}</span><br>Total Attendance</div>", unsafe_allow_html=True)
    col5.markdown(f"<div class='kpi-box'>❌ <br><span class='big-font'>{total_absentees:,}</span><br>Total Absentees</div>", unsafe_allow_html=True)
    col6.markdown(f"<div class='kpi-box'>πŸ“ˆ <br><span class='big-font'>{attendance_pct}%</span><br>Attendance %</div>", unsafe_allow_html=True)

    st.markdown("---")

    # VISUALIZATIONS
    df["admission_rate"] = (df[admitted_col] / df[sanctioned_col]) * 100
    df["vacancy_rate"] = (df[vacant_col] / df[sanctioned_col]) * 100
    df["attendance_%"] = (df[attendance_col] / (df[attendance_col] + df[absentees_col])) * 100

    # 1. Vacancy Rate vs Admission Rate (Bubble)
    st.plotly_chart(px.scatter(df, x="admission_rate", y="vacancy_rate", size="admission_rate",
                               color=attendance_col, hover_name="college_name",
                               title="Vacancy Rate vs Admission Rate"), use_container_width=True)

    # 2. Attendance Impact on Vacancies
    st.plotly_chart(px.scatter(df, x=attendance_col, y="vacancy_rate", title="Attendance Impact on Vacancy Rate", trendline="ols"), use_container_width=True)

    # 3. Top 10 Districts by Absenteeism
    absentee_summary = df.groupby("district")[absentees_col].sum().reset_index().sort_values(absentees_col, ascending=False).head(10)
    st.plotly_chart(px.bar(absentee_summary, x="district", y=absentees_col, title="Top 10 Districts by Absenteeism"), use_container_width=True)

    # 4. Vacancy Rate Distribution
    st.plotly_chart(px.box(df, y="vacancy_rate", x="district", title="Vacancy Rate Distribution by District"), use_container_width=True)

    # 5. Sanction vs Admission
    stacked = df.groupby("district")[[sanctioned_col, admitted_col]].sum().reset_index()
    stacked = stacked.melt(id_vars="district", value_vars=[sanctioned_col, admitted_col], var_name="Type", value_name="Seats")
    st.plotly_chart(px.bar(stacked, x="district", y="Seats", color="Type", title="Sanctioned vs Admitted Seats"), use_container_width=True)

    # 6. Top & Bottom 5 Institutes
    top_5 = df.nlargest(5, "attendance_%")[["college_name", "attendance_%"]]
    bottom_5 = df.nsmallest(5, "attendance_%")[["college_name", "attendance_%"]]
    col1, col2 = st.columns(2)
    with col1:
        st.subheader("Top 5 Institutes (Attendance %)")
        st.dataframe(top_5)
    with col2:
        st.subheader("Bottom 5 Institutes (Attendance %)")
        st.dataframe(bottom_5)

    # DRILL-DOWN: SELECT DISTRICT
    selected_district = st.selectbox("Search for a District for Detailed Institute View", df["district"].unique())
    drill_df = df[df["district"] == selected_district][["college_name", sanctioned_col, admitted_col, vacant_col, attendance_col, absentees_col, "attendance_%"]]
    st.dataframe(drill_df)

    # DOWNLOAD DATA
    def download_excel(dataframe):
        output = BytesIO()
        with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
            dataframe.to_excel(writer, index=False, sheet_name="Report")
        return output.getvalue()

    st.download_button("πŸ“₯ Download Excel Report", data=download_excel(df), file_name="education_dashboard_report.xlsx")

else:
    st.warning("Upload the merged dataset to start the analysis.")