| import pandas as pd |
| import streamlit as st |
| import plotly.express as px |
| import numpy as np |
| import plotly.graph_objs as go |
| from function import ( |
| process_data, |
| predict_late_student, |
| predict_rank, |
| predict_one_student, |
| show_boxplot1, |
| ) |
| from datetime import datetime |
| from PIL import Image |
| import base64 |
| import re |
| import sqlite3 |
|
|
| df = pd.DataFrame() |
|
|
|
|
| def color_cell(val): |
| if val == "not late": |
| color = "green" |
| elif val == "may late": |
| color = "yellow" |
| elif val == "late": |
| color = "red" |
| else: |
| color = "black" |
|
|
| return f"color: {color};" |
|
|
|
|
| def clear_resources(): |
| """Clears all resources from the st.session_state.""" |
| for key in list(st.session_state.keys()): |
| if key.startswith("resource"): |
| del st.session_state[key] |
|
|
|
|
| def get_year(student_id): |
| year_str = "" |
| for char in student_id: |
| if char.isdigit(): |
| year_str += char |
| if len(year_str) == 2: |
| break |
| return int(year_str) |
|
|
|
|
| def generate_comment(median): |
| if median < 30: |
| comment = f"The median score for {course} is quite low at {median}. Students may need to work harder to improve their performance." |
| elif median < 50: |
| comment = f"The median score for {course} is below average at {median}. Students should work on improving their understanding of the material." |
| elif median < 80: |
| comment = f"The median score for {course} is solid at {median}. Students are making good progress but could still work on improving their skills." |
| else: |
| comment = f"The median score for {course} is outstanding at {median}. Students are doing an excellent job in this course." |
| return comment |
|
|
|
|
| favicon = "R.png" |
| hcm = "HCM.png" |
| intera = "Logo-iuoss-trans.png" |
| st.set_page_config( |
| page_title="Student System", |
| page_icon=favicon, |
| layout="wide", |
| ) |
| st.markdown( |
| '<div style="text-align: center; margin-top: 50px; color: #808080;">' |
| '© Copyright by Truong Quoc An' |
| '</div>', |
| unsafe_allow_html=True |
| ) |
| currentYear = datetime.now().year |
| im1 = Image.open("R.png") |
| im2 = Image.open("HCM.png") |
| im3 = Image.open("Logo-iuoss-trans.png") |
|
|
|
|
| col1, col2, col3 = st.columns([1, 3, 1]) |
|
|
|
|
| with col1: |
| st.image(im1, width=150) |
|
|
|
|
| with col2: |
| st.markdown( |
| "<h1 style='text-align: center;'>Student Performance Evaluation</h1>", |
| unsafe_allow_html=True, |
| ) |
|
|
|
|
| with col3: |
| st.image(im2, width=250) |
|
|
|
|
| @st.cache_data() |
| def score_table(): |
| |
| conn = sqlite3.connect("database.db") |
| cursor = conn.cursor() |
|
|
| |
| cursor.execute('''SELECT Students.MaSV, Enrollment.MaMH, Courses.TenMH, Enrollment.NHHK, Enrollment.DiemHP, Students.DTBTK |
| FROM Students |
| INNER JOIN Enrollment ON Students.MaSV = Enrollment.MaSV |
| INNER JOIN Courses ON Enrollment.MaMH = Courses.MaMH''') |
| data = cursor.fetchall() |
|
|
| |
| df = pd.DataFrame(data, columns=['MaSV', 'MaMH', 'TenMH', 'NHHK', 'DiemHP', 'DTBTK']) |
| df = df.drop_duplicates() |
|
|
| |
| conn.close() |
|
|
| return df |
|
|
| @st.cache_data() |
| def score_table_for_student(): |
| with sqlite3.connect("database.db") as conn: |
| cursor = conn.cursor() |
|
|
| cursor.execute(''' |
| SELECT DISTINCT Students.MaSV, Enrollment.MaMH, Courses.TenMH, Enrollment.NHHK, Enrollment.DiemHP, Students.DTBTK |
| FROM Students |
| INNER JOIN Enrollment ON Students.MaSV = Enrollment.MaSV |
| INNER JOIN Courses ON Enrollment.MaMH = Courses.MaMH |
| ''') |
| results = cursor.fetchall() |
| df = pd.DataFrame(results, columns=['MaSV', 'MaMH', 'TenMH', 'NHHK', 'DiemHP', 'DTBTK']) |
|
|
| cursor.execute(''' |
| SELECT MaSV, NHHK, SoTCDat |
| FROM Students |
| ''') |
| results = cursor.fetchall() |
| df1 = pd.DataFrame(results, columns=['MaSV', 'NHHK', 'SoTCDat']) |
| merged_df = pd.merge(df, df1, on=['MaSV', 'NHHK']) |
|
|
| return merged_df |
|
|
|
|
|
|
|
|
| st.sidebar.image(im3) |
| st.sidebar.title("Student Performance Prediction System") |
| option = ["Prediction Performance","Dashboard", "Grade Distribution Tables"] |
|
|
| tabs = st.sidebar.selectbox("Select an option", option) |
|
|
|
|
| def filter_dataframe(df, column, value): |
| if value == "All": |
| return df |
| else: |
| return df[df[column] == value] |
|
|
|
|
| if tabs == "Dashboard": |
| clear_resources() |
| raw_data = score_table() |
| df = process_data(raw_data) |
| additional_selection = " " |
| unique_values_major = df["Major"].unique() |
| unique_values_major = [ |
| "BA", |
| "BE", |
| "BT", |
| "CE", |
| "EE", |
| "EN", |
| "EV", |
| "IE", |
| "MA", |
| "SE", |
| "IT", |
| ] |
| unique_values_major = sorted(unique_values_major, key=lambda s: s) |
| major = st.selectbox("Select a school:", unique_values_major) |
| df = filter_dataframe(df, "Major", major) |
| dfa = filter_dataframe(df, "Major", major) |
|
|
| unique_values_school = df["MaSV_school"].unique() |
| all_values_school = np.concatenate([["All"], unique_values_school]) |
| no_numbers = [x for x in all_values_school if not re.search(r"\d", str(x))] |
|
|
| if len(no_numbers) == 2: |
| school = no_numbers[1] |
| else: |
| col1, col2 = st.columns(2) |
|
|
| with col1: |
| school = st.selectbox("Select a major:", no_numbers) |
|
|
| if school != "All": |
| values = [x for x in no_numbers if x != "All" and x != school] |
| values = np.concatenate([[" "], values]) |
|
|
| with col2: |
| additional_selection = st.selectbox( |
| "Select another major for comparisons:", values |
| ) |
| if additional_selection != " ": |
| dfa = filter_dataframe(dfa, "MaSV_school", additional_selection) |
|
|
| df = filter_dataframe(df, "MaSV_school", school) |
|
|
| unique_values_year = df["Year"].unique() |
| all_values_year = np.concatenate([["All"], unique_values_year]) |
|
|
| col1, col2 = st.columns(2) |
|
|
| with col1: |
| year = st.selectbox("Select a year:", all_values_year) |
|
|
| with col2: |
| if year != "All" and additional_selection == " ": |
| year_list = [x for x in all_values_year if x != "All" and x != year] |
| year_list = np.concatenate([[" "], year_list]) |
| year_a = st.selectbox("Select another year for comparisons:", year_list) |
| elif year == "All": |
| year_a = " " |
| elif year != "All" and additional_selection != " ": |
| year_a = year |
| if year_a != " ": |
| dfa = filter_dataframe(dfa, "Year", year_a) |
| dfa.dropna(axis=1, thresh=1, inplace=True) |
| else: |
| year_a = " " |
|
|
| df = filter_dataframe(df, "Year", year) |
| new1_df = df.DTBTK |
| new1_dfa = dfa.DTBTK |
| show_boxplot1( |
| new1_df, new1_dfa, major, school, year, additional_selection="", year_a="" |
| ) |
|
|
| df.dropna(axis=1, thresh=1, inplace=True) |
|
|
| new_df = df.iloc[:, :-4].dropna(axis=1, thresh=10).apply(pd.to_numeric) |
| new_dfa = dfa.iloc[:, :-4].dropna(axis=1, thresh=10).apply(pd.to_numeric) |
| list1 = new_df.columns.tolist() |
| list2 = new_dfa.columns.tolist() |
| if (year != "All" and year_a != " ") or ( |
| school != "All" and additional_selection != " " |
| ): |
| dfac = new_dfa.columns[:-4].tolist() |
| common_elements = np.intersect1d(list1, list2) |
|
|
| merged_array = np.concatenate((list1, list2), axis=None) |
|
|
| list3 = np.intersect1d(merged_array, common_elements) |
| new_df = new_df[list3] |
| new_dfa = new_dfa[list3] |
| if additional_selection != " ": |
| show_boxplot = st.checkbox("Show Boxplot for All Course", key="checkbox1") |
|
|
| if show_boxplot: |
| fig = px.box(new_df) |
| fig1 = px.box(new_dfa) |
| fig.update_layout( |
| title="Boxplot of " + major + school + " student in " + year |
| ) |
| fig1.update_layout( |
| title="Boxplot of " |
| + major |
| + additional_selection |
| + " student in " |
| + year |
| ) |
|
|
| st.plotly_chart(fig, use_container_width=True) |
| st.plotly_chart(fig1, use_container_width=True) |
|
|
| elif additional_selection == " " and year_a != " ": |
| show_boxplot = st.checkbox("Show Boxplot for All Course", key="checkbox1") |
|
|
| if show_boxplot: |
| fig = px.box(new_df) |
| fig1 = px.box(new_dfa) |
| fig.update_layout( |
| title="Boxplot of " + major + school + " student in " + year |
| ) |
| fig1.update_layout( |
| title="Boxplot of " + major + school + " student in " + year_a |
| ) |
|
|
| st.plotly_chart(fig, use_container_width=True) |
| st.plotly_chart(fig1, use_container_width=True) |
|
|
| elif additional_selection == " ": |
| show_boxplot = st.checkbox("Show Boxplot for All Course", key="checkbox1") |
|
|
| if show_boxplot: |
| fig = px.box(new_df) |
| fig.update_layout(title="Boxplot of " + major + " student in " + year) |
|
|
| st.plotly_chart(fig, use_container_width=True) |
|
|
| options = df.columns[:-4] |
|
|
| course_data_dict = {course: df[course].dropna() for course in options} |
| valid_courses = [ |
| course for course, data in course_data_dict.items() if len(data) > 1 |
| ] |
|
|
| if (year != "All" and year_a != " ") or ( |
| school != "All" and additional_selection != " " |
| ): |
| dfac = new_dfa.columns[:-4].tolist() |
| common_elements = np.intersect1d(valid_courses, dfac) |
|
|
| merged_array = np.concatenate((valid_courses, dfac), axis=None) |
|
|
| valid_courses = np.intersect1d(merged_array, common_elements) |
|
|
| if len(valid_courses) > 5: |
| course = st.selectbox("Select a course:", valid_courses) |
| elif len(valid_courses) == 1: |
| course = valid_courses[0] |
| else: |
| st.write("No valid course data found!") |
| st.stop() |
|
|
| course_data = course_data_dict[course] |
|
|
| if len(course_data) > 1: |
| if school == "All": |
| st.write("Course:", course, " of ", major, " student") |
| else: |
| st.write("Course:", course, " of ", major + school, " student") |
| st.write(generate_comment(course_data.median())) |
| else: |
| st.write("No data available for the selected course.") |
|
|
| col1, col2, col3, col4 = st.columns(4) |
|
|
| with col1: |
| counts, bins = np.histogram(course_data, bins=np.arange(0, 110, 10)) |
| total_count = len(course_data) |
| frequencies_percentage = (counts / total_count) * 100 |
| grade_bins = [f"{bins[i]}-{bins[i+1]}" for i in range(len(bins) - 1)] |
|
|
| df = pd.DataFrame( |
| {"Grade": grade_bins, "Grading percentage": frequencies_percentage} |
| ) |
| df["Grading percentage"] = df["Grading percentage"].map( |
| lambda x: "{:.2f}".format(x) |
| ) |
|
|
| st.table(df) |
|
|
| with col2: |
|
|
| fig = go.Figure() |
| fig.add_trace( |
| go.Scatter( |
| x=bins[:-1], y=frequencies_percentage, mode="lines", name="Frequency" |
| ) |
| ) |
|
|
| fig.update_layout( |
| title="Histogram of {}".format(course), |
| xaxis_title="Score", |
| yaxis_title="Percentage", |
| height=400, |
| width=400, |
| ) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col3: |
| fig = go.Figure() |
| fig.add_trace(go.Box(y=course_data, name="Box plot")) |
| fig.update_layout( |
| title="Box plot of Scores for {}".format(course), |
| yaxis_title="Score", |
| height=400, |
| width=400, |
| ) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col4: |
| raw_data1 = raw_data.copy() |
| raw_data1["major"] = raw_data1["MaSV"].str.slice(0, 2) |
| raw_data1.replace(["WH", "VT", "I"], np.nan, inplace=True) |
| raw_data1 = raw_data1[~raw_data1["DiemHP"].isin(["P", "F", "PC"])] |
| if major != "All": |
| raw_data1 = raw_data1[raw_data1["major"] == major] |
|
|
| raw_data1["MaSV_school"] = raw_data1["MaSV"].str.slice(2, 4) |
| if school != "All": |
| raw_data1 = raw_data1[raw_data1["MaSV_school"] == school] |
|
|
| df1 = raw_data1[["TenMH", "NHHK", "DiemHP"]].copy() |
| |
| df1["DiemHP"] = df1["DiemHP"].replace('', pd.NA).dropna().astype(float) |
| df1["NHHK"] = df1["NHHK"].apply(lambda x: str(x)[:4] + " S " + str(x)[4:]) |
|
|
| selected_TenMH = " " + course |
| filtered_df1 = df1[df1["TenMH"] == selected_TenMH] |
|
|
| mean_DiemHP = ( |
| filtered_df1.groupby("NHHK")["DiemHP"] |
| .mean() |
| .round(1) |
| .reset_index(name="Mean") |
| ) |
|
|
| if year != "All": |
| st.write("") |
| else: |
| fig = px.line( |
| mean_DiemHP, |
| x="NHHK", |
| y="Mean", |
| title=f"Mean Course Score for{selected_TenMH} through Semeters", |
| ) |
| fig.update_layout(xaxis_title="Semeters",height=400, width=400) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| if (year != "All" and year_a != " ") or ( |
| school != "All" and additional_selection != " " |
| ): |
| course_data_dict = {course: new_dfa[course]} |
| course_data = course_data_dict[course] |
|
|
| st.write( |
| "Course:", |
| course, |
| " of ", |
| major + additional_selection, |
| " student in ", |
| year_a, |
| ) |
| col1, col2, col3, col4 = st.columns(4) |
|
|
| with col1: |
| course_data_filtered = [x for x in course_data if not np.isnan(x)] |
| counts, bins = np.histogram( |
| course_data_filtered, bins=np.arange(0, 110, 10) |
| ) |
| total_count = len(course_data_filtered) |
| frequencies_percentage = (counts / total_count) * 100 |
| grade_bins = [f"{bins[i]}-{bins[i+1]}" for i in range(len(bins) - 1)] |
|
|
| df1 = pd.DataFrame( |
| {"Grade": grade_bins, "Grading percentage": frequencies_percentage} |
| ) |
| df1["Grading percentage"] = df1["Grading percentage"].map( |
| lambda x: "{:.2f}".format(x) |
| ) |
|
|
| st.table(df1) |
|
|
| with col2: |
|
|
| fig = go.Figure() |
| fig.add_trace( |
| go.Scatter( |
| x=bins[:-1], |
| y=frequencies_percentage, |
| mode="lines", |
| name="Frequency", |
| ) |
| ) |
|
|
| fig.update_layout( |
| title="Histogram of {}".format(course), |
| xaxis_title="Score", |
| yaxis_title="Percentage", |
| height=400, |
| width=400, |
| ) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col3: |
| fig = go.Figure() |
| fig.add_trace(go.Box(y=course_data, name="Box plot")) |
| fig.update_layout( |
| title="Box plot of Scores for {}".format(course), |
| yaxis_title="Score", |
| height=400, |
| width=400, |
| ) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col4: |
| raw_data["major"] = raw_data["MaSV"].str.slice(0, 2) |
| raw_data.replace(["WH", "VT", "I"], np.nan, inplace=True) |
| raw_data = raw_data[~raw_data["DiemHP"].isin(["P", "F", "PC"])] |
| if major != "All": |
| raw_data = raw_data[raw_data["major"] == major] |
|
|
| raw_data["MaSV_school"] = raw_data["MaSV"].str.slice(2, 4) |
| raw_data = raw_data[raw_data["MaSV_school"] == additional_selection] |
|
|
| df1 = raw_data[["TenMH", "NHHK", "DiemHP"]].copy() |
| df1["DiemHP"] = df1["DiemHP"].replace('', pd.NA).dropna().astype(float) |
| df1["NHHK"] = df1["NHHK"].apply(lambda x: str(x)[:4] + " S " + str(x)[4:]) |
|
|
| selected_TenMH = " " + course |
| filtered_df1 = df1[df1["TenMH"] == selected_TenMH] |
|
|
| mean_DiemHP = ( |
| filtered_df1.groupby("NHHK")["DiemHP"] |
| .mean() |
| .round(1) |
| .reset_index(name="Mean") |
| ) |
|
|
| if year != "All": |
| st.write("") |
| else: |
| fig = px.line( |
| mean_DiemHP, |
| x="NHHK", |
| y="Mean", |
| title=f"Mean Course Score for{selected_TenMH} through Semeters", |
| ) |
| fig.update_layout(xaxis_title="Semeters",height=400, width=400) |
| st.plotly_chart(fig, use_container_width=True) |
| variables_to_delete = [ |
| 'raw_data1', 'df1', 'filtered_df1', 'mean_DiemHP', 'counts', 'bins', |
| 'total_count', 'frequencies_percentage', 'grade_bins', 'fig1', |
| 'common_elements', 'merged_array', 'list3', 'dfac', 'fig', 'new_df', |
| 'new_dfa', 'new1_df', 'new1_dfa', 'course_data', |
| 'options', 'valid_courses', 'list2', 'list1' |
| ] |
|
|
| for variable in variables_to_delete: |
| if variable in locals(): |
| del locals()[variable] |
|
|
|
|
|
|
| elif tabs == "Prediction Performance": |
|
|
| clear_resources() |
|
|
| raw_data = score_table_for_student() |
| raw_data["DTBTKH4"] = raw_data["DTBTK"]/25 |
| df=raw_data.copy() |
| df["MaSV_school"] = df["MaSV"].str.slice(2, 4) |
| df["Major"] = df["MaSV"].str.slice(0, 2) |
| unique_values_major = df["Major"].unique() |
| unique_values_major = [ |
| "BA", |
| "BE", |
| "BT", |
| "CE", |
| "EE", |
| "EN", |
| "EV", |
| "IE", |
| "MA", |
| "SE", |
| "IT", |
| ] |
| unique_values_major = sorted(unique_values_major, key=lambda s: s) |
| col1, col2 = st.columns(2) |
| with col1: |
| major = st.selectbox("Select a school:", unique_values_major) |
| df = filter_dataframe(df, "Major", major) |
|
|
| unique_values_school = df["MaSV_school"].unique() |
| all_values_school = np.concatenate([["All"], unique_values_school]) |
| no_numbers = [x for x in all_values_school if not re.search(r"\d", str(x))] |
|
|
| if len(no_numbers) == 2: |
| school = no_numbers[1] |
| with col2: |
| school = st.selectbox("Select a major:", no_numbers) |
|
|
| df = filter_dataframe(df, "MaSV_school", school) |
| predict = predict_late_student(df) |
| rank = predict_rank(df) |
| predict = pd.merge(predict, rank, on="MaSV") |
| predict.rename(columns={"Mean_Cre": "Mean Credit"}, inplace=True) |
|
|
| rank_mapping = { |
| "Khá": "Good", |
| "Trung Bình Khá": "Average good", |
| "Giỏi": "Very good", |
| "Kém": "Very weak", |
| "Trung Bình": "Ordinary", |
| "Yếu": "Weak", |
| "Xuất Sắc": "Excellent", |
| } |
| predict["Pred Rank"].replace(rank_mapping, inplace=True) |
|
|
| df_late = predict |
|
|
| MaSV = st.text_input("Enter Student ID:", key="MaSV") |
|
|
| def clear_form(): |
| st.session_state["MaSV"] = "" |
|
|
| if st.button("Clear", on_click=clear_form): |
| MaSV = "" |
|
|
| if MaSV: |
| df_filtered = predict[predict["MaSV"] == MaSV] |
| styled_table = ( |
| df_filtered[ |
| ["MaSV", "GPA", "Mean Credit", "Pred Rank", "Progress", "Semeters"] |
| ] |
| .style.applymap(color_cell) |
| .format({"GPA": "{:.2f}", "Mean Credit": "{:.1f}", "Semeters": "{:.1f}"}) |
| ) |
|
|
| with st.container(): |
| st.table(styled_table) |
| predict_one_student(df, MaSV) |
| else: |
| df_late = predict |
|
|
| df_late["Year"] = 2000 + df_late["MaSV"].apply(get_year) |
| df_late = df_late[ |
| (df_late["Year"] != currentYear - 1) & (df_late["Year"] != currentYear - 2) |
| ] |
| year = st.selectbox("Select Year", options=df_late["Year"].unique()) |
| df_filtered = df_late[df_late["Year"] == year] |
| styled_table = ( |
| df_filtered[ |
| ["MaSV", "GPA", "Mean Credit", "Pred Rank", "Progress", "Semeters"] |
| ] |
| .style.applymap(color_cell) |
| .format({"GPA": "{:.2f}", "Mean Credit": "{:.2f}", "Semeters": "{:.2f}"}) |
| ) |
| csv = df_filtered.to_csv(index=False) |
| b64 = base64.b64encode(csv.encode()).decode() |
| href = f'<a href="data:file/csv;base64,{b64}" download="Preidct data.csv">Download CSV</a>' |
| st.markdown(href, unsafe_allow_html=True) |
|
|
| legend_order = [ |
| "Excellent", |
| "Very good", |
| "Good", |
| "Average good", |
| "Ordinary", |
| "Weak", |
| "Very weak", |
| ] |
|
|
| fig1 = px.pie( |
| df_filtered, |
| names="Pred Rank", |
| title="Pred Rank", |
| color_discrete_sequence=px.colors.sequential.Mint, |
| height=400, |
| width=400, |
| labels=legend_order, |
| ) |
|
|
| fig2 = px.pie( |
| df_filtered, |
| names="Progress", |
| title="Progress", |
| color_discrete_sequence=px.colors.sequential.Peach, |
| height=400, |
| width=400, |
| ) |
|
|
| fig1.update_layout( |
| title={ |
| "text": "Pred Rank", |
| "y": 0.95, |
| "x": 0.35, |
| "xanchor": "center", |
| "yanchor": "top", |
| } |
| ) |
| fig2.update_layout( |
| title={ |
| "text": "Progress", |
| "y": 0.95, |
| "x": 0.35, |
| "xanchor": "center", |
| "yanchor": "top", |
| } |
| ) |
|
|
| col3, col1, col2 = st.columns([2, 1, 1]) |
| with col3: |
| st.dataframe(styled_table,use_container_width=True) |
| with col1: |
| st.plotly_chart(fig1, use_container_width=True) |
| with col2: |
| st.plotly_chart(fig2, use_container_width=True) |
| variables_to_delete = [ |
| "raw_data", |
| "df", |
| "df_late", |
| "MaSV", |
| "predict", |
| "rank", |
| "rank_mapping", |
| "styled_table", |
| "df_filtered", |
| "csv", |
| "b64", |
| "href", |
| "legend_order", |
| "fig1", |
| "fig2", |
| "col1", |
| "col2", |
| "col3" |
| ] |
|
|
| |
| for variable_name in variables_to_delete: |
| if variable_name in locals(): |
| del locals()[variable_name] |
|
|
| elif tabs == "Grade Distribution Tables": |
| clear_resources() |
| raw_data = score_table() |
| df = process_data(raw_data) |
| additional_selection = " " |
|
|
| unique_values_major = df["Major"].unique() |
| unique_values_major = [ |
| "BA", |
| "BE", |
| "BT", |
| "CE", |
| "EE", |
| "EN", |
| "EV", |
| "IE", |
| "MA", |
| "SE", |
| "IT", |
| ] |
| unique_values_major = sorted(unique_values_major, key=lambda s: s) |
| col1, col2 = st.columns(2) |
| with col1: |
| major = st.selectbox("Select a school:", unique_values_major) |
| df = filter_dataframe(df, "Major", major) |
|
|
| unique_values_school = df["MaSV_school"].unique() |
| all_values_school = np.concatenate([["All"], unique_values_school]) |
| no_numbers = [x for x in all_values_school if not re.search(r"\d", str(x))] |
|
|
| if len(no_numbers) == 2: |
| school = no_numbers[1] |
| with col2: |
| school = st.selectbox("Select a major:", no_numbers) |
|
|
| df = filter_dataframe(df, "MaSV_school", school) |
|
|
| unique_values_year = df["Year"].unique() |
| all_values_year = np.concatenate([["All"], unique_values_year]) |
|
|
| year = st.selectbox("Select a year:", all_values_year) |
|
|
| options = df.columns[:-4] |
| |
|
|
| course_data_dict = {course: df[course].dropna() for course in options} |
| |
| valid_courses = [ |
| course for course, data in course_data_dict.items() if len(data) > 1 |
| ] |
|
|
| course = "All" |
|
|
| if st.button("Generate Chart"): |
| courses_per_row = 4 |
| num_courses = len(valid_courses) |
| num_rows = (num_courses + courses_per_row - 1) // courses_per_row |
|
|
| for row in range(num_rows): |
| start_index = row * courses_per_row |
| end_index = min((row + 1) * courses_per_row, num_courses) |
| courses_in_row = valid_courses[start_index:end_index] |
|
|
| for course in courses_in_row: |
| course_data = course_data_dict[course] |
| course_data = course_data.astype(float) |
| st.markdown(f"Course: **{course}**") |
| st.write("Number of examinations: ", str(len(course_data))) |
| col1, col2, col3, col4 = st.columns(4) |
|
|
| with col1: |
| counts, bins = np.histogram(course_data, bins=np.arange(0, 110, 10)) |
| total_count = len(course_data) |
| frequencies_percentage = (counts / total_count) * 100 |
| grade_bins = [ |
| f"{bins[i]}-{bins[i+1]}" for i in range(len(bins) - 1) |
| ] |
| result_array = [] |
| cumulative_sum = 0 |
|
|
| for element in frequencies_percentage: |
| cumulative_sum += element |
| result_array.append(cumulative_sum) |
|
|
| df = pd.DataFrame( |
| { |
| "Grade": grade_bins, |
| "Grading percentage": frequencies_percentage, |
| "Cumulative percentage": result_array |
| } |
| ) |
| df["Grading percentage"] = df["Grading percentage"].map( |
| lambda x: "{:.2f}".format(x) |
| ) |
| df["Cumulative percentage"] = df["Cumulative percentage"].map( |
| lambda x: "{:.2f}".format(x) |
| ) |
|
|
| st.table(df) |
|
|
| with col2: |
| fig = go.Figure() |
| fig.add_trace( |
| go.Scatter( |
| x=bins[:-1], |
| y=frequencies_percentage, |
| mode="lines", |
| name="Frequency", |
| ) |
| ) |
|
|
| fig.update_layout( |
| title="Histogram of {}".format(course), |
| xaxis_title="Score", |
| yaxis_title="Percentage", |
| height=400, |
| width=400, |
| ) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col3: |
| fig = go.Figure() |
| fig.add_trace(go.Box(y=course_data, name="Box plot")) |
| fig.update_layout( |
| title="Box plot", |
| yaxis_title="Score", |
| height=400, |
| width=400, |
| ) |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| with col4: |
| raw_data1 = raw_data.copy() |
| raw_data1["major"] = raw_data1["MaSV"].str.slice(0, 2) |
| raw_data1.replace(["WH", "VT", "I"], np.nan, inplace=True) |
| raw_data1 = raw_data1[~raw_data1["DiemHP"].isin(["P", "F", "PC"])] |
| if major != "All": |
| raw_data1 = raw_data1[raw_data1["major"] == major] |
|
|
| raw_data1["MaSV_school"] = raw_data1["MaSV"].str.slice(2, 4) |
| if school != "All": |
| raw_data1 = raw_data1[raw_data1["MaSV_school"] == school] |
|
|
| df1 = raw_data1[["TenMH", "NHHK", "DiemHP"]].copy() |
| df1["DiemHP"] = df1["DiemHP"].astype(float) |
| df1["NHHK"] = df1["NHHK"].apply( |
| lambda x: str(x)[:4] + " S " + str(x)[4:] |
| ) |
|
|
| selected_TenMH = " " + course |
| filtered_df1 = df1[df1["TenMH"] == selected_TenMH] |
|
|
| mean_DiemHP = ( |
| filtered_df1.groupby("NHHK")["DiemHP"] |
| .mean() |
| .round(1) |
| .reset_index(name="Mean") |
| ) |
|
|
| if year != "All": |
| st.write("") |
| else: |
| fig = px.line( |
| mean_DiemHP, |
| x="NHHK", |
| y="Mean", |
| title=f"Mean DiemHP through Semesters", |
| ) |
| fig.update_layout(height=400, width=400) |
| st.plotly_chart(fig, use_container_width=True) |
| del raw_data1, df1, filtered_df1, mean_DiemHP, counts, bins, total_count, frequencies_percentage, grade_bins, fig |
| del course_data, course_data_dict, valid_courses |
| st.stop() |
|
|