language_test / app.py
birgermoell's picture
Create app.py
87110a5
import streamlit as st
import numpy as np
import scipy.stats as stats
from fpdf import FPDF
import base64
import os
from plots import test_profile
import matplotlib.pyplot as plt
from PIL import Image
# Function to calculate z-score
def calculate_z_score(test_score, mean, std_dev):
return (test_score - mean) / std_dev
def z_score_calculator(value, norm_mean, norm_sd):
z_value = (value - norm_mean) / norm_sd
stanine_value = round(1.25 * z_value + 5.5)
z_score = round(z_value, 2)
return z_score, stanine_value
def bnt_calculator(age, education, bnt):
if age <= 60 and education <= 12:
norm_mean = 54.5
norm_sd = 3.2
z_score, stanine_value = z_score_calculator(bnt, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
elif age <= 60 and education > 12:
norm_mean = 54.0
norm_sd = 4.4
z_score, stanine_value = z_score_calculator(bnt, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
elif age > 60 and education <= 12:
norm_mean = 54.8
norm_sd = 3.3
z_score, stanine_value = z_score_calculator(bnt, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
elif age > 60 and education > 12:
norm_mean = 56.2
norm_sd = 3.4
z_score, stanine_value = z_score_calculator(bnt, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
else:
print("missing value/ wrong format")
def fas_calculator(age, education, fas):
if age <= 60 and education <= 12:
norm_mean = 42.7
norm_sd = 13.7
z_score, stanine_value = z_score_calculator(fas, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
elif age <= 60 and education > 12:
norm_mean = 46.7
norm_sd = 13.7
z_score, stanine_value = z_score_calculator(fas, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
elif age > 60 and education <= 12:
norm_mean = 46.9
norm_sd = 10.4
z_score, stanine_value = z_score_calculator(fas, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
elif age > 60 and education > 12:
norm_mean = 51.6
norm_sd = 12.6
z_score, stanine_value = z_score_calculator(fas, norm_mean, norm_sd)
return norm_mean, norm_sd, z_score, stanine_value
else:
print("missing value/ wrong format")
def generate_graph(BNT_stanine, FAS_stanine):
# Create a plot
fig, ax = plt.subplots()
# Set axis labels and title
ax.set_xlabel('Stanine values')
ax.set_ylabel('Test')
# Set the y-axis to display the tests
ax.set_yticks([1, 2])
ax.set_yticklabels(['BNT', 'FAS'])
# Set the range of the x-axis
ax.set_xlim([0, 10])
# Add dots for BNT and FAS scores
ax.scatter(BNT_stanine, 1, s=100, label='BNT')
ax.scatter(FAS_stanine, 2, s=100, label='FAS')
# Add legend
ax.legend()
# Show the plot
# plt.show()
# Save the graph as a png file
fig.savefig('test_profile.png')
return 'test_profile.png'
def create_pdf(z_score, mean, std_dev, logo_path, plot_path):
pdf = FPDF()
pdf.add_page()
pdf.set_xy(0, 0)
pdf.set_font("Arial", size=12)
# Add logos
x_positions = [25, 85, 145]
for i, logo_path in enumerate(logo_paths):
pdf.image(logo_path, x=x_positions[i], y=8, w=40)
pdf.set_xy(10, 50)
# Add title and center it
title = "Z-Score Report"
pdf.set_font("Arial", style="B", size=16)
title_width = pdf.get_string_width(title) + 6
pdf.cell((210 - title_width) / 2)
pdf.cell(title_width, 10, title, 0, 1, "C")
# Add z-score and center it
pdf.set_font("Arial", size=12)
z_score_text = "Your z-score is: {:.2f}".format(z_score)
z_score_width = pdf.get_string_width(z_score_text) + 6
pdf.cell((210 - z_score_width) / 2)
pdf.cell(z_score_width, 10, z_score_text, 0, 1, "C")
# Add mean and standard deviation and center it
mean_std_text = "Mean: {}, Standard Deviation: {}".format(mean, std_dev)
mean_std_width = pdf.get_string_width(mean_std_text) + 6
pdf.cell((210 - mean_std_width) / 2)
pdf.cell(mean_std_width, 10, mean_std_text, 0, 1, "C")
# Add logo
pdf.image(plot_path, x=10, y=80, w=200)
# pdf.set_xy(10, 40)
# Add tool description and center it
pdf.set_xy(10, 230)
pdf.set_font("Arial", size=10)
description = "This PDF report was generated using the Z-Score Calculator Streamlit App."
pdf.multi_cell(0, 10, description, 0, "C")
# Add explanatory text about the collaboration between KI and KTH
pdf.set_xy(10, 255)
pdf.set_font("Arial", size=8)
collaboration_text = (
"Den här PDF:en är en del av ett samarbetsprojekt mellan Karolinska Institutet (KI) och "
"Kungliga Tekniska Högskolan (KTH) med målsättningen att använda artificiell intelligens (AI) och "
"teknik för att minska administration i sjukhusarbete. Projektet fokuserar på att utveckla och "
"implementera AI-baserade lösningar för att förbättra arbetsflöden, öka effektiviteten och "
"minska den administrativa bördan för sjukvårdspersonal. För frågor om formuläret kontakta Fredrik Sand fredrik.sand-aronsson@regionstockholm.se, för frågor om teknik kontakta Birger Moëll bmoell@kth.se."
)
line_width = 190
line_height = pdf.font_size_pt * 0.6
lines = collaboration_text.split(' ')
current_line = ''
for word in lines:
if pdf.get_string_width(current_line + word) < line_width:
current_line += word + ' '
else:
pdf.cell(line_width, line_height, current_line, 0, 1)
current_line = word + ' '
pdf.cell(line_width, line_height, current_line, 0, 1)
return pdf
def pdf_to_base64(pdf):
with open(pdf, "rb") as file:
return base64.b64encode(file.read()).decode('utf-8')
# Title and description
st.title("Z-Score Calculator")
st.write("Enter your test score, age, and education level to calculate the z-score.")
# Input fields
#test_score = st.number_input("Test Score", min_value=0, value=0, step=1)
age = st.number_input("Age", min_value=0, value=18, step=1)
education_level = st.number_input("Education Level in years", min_value=0, value=18, step=1)
isw = st.number_input("ISW", min_value=0, value=0, step=1)
bnt = st.number_input("BNT", min_value=0, value=0, step=1)
fas = st.number_input("FAS", min_value=0, value=0, step=1)
animal = st.number_input("Animal", min_value=0, value=0, step=1)
verb = st.number_input("Verb", min_value=0, value=0, step=1)
repetition = st.number_input("Repetition", min_value=0, value=0, step=1)
logicogrammatic = st.number_input("Logicogrammatic", min_value=0, value=0, step=1)
inference = st.number_input("Inference", min_value=0, value=0, step=1)
reading_speed = st.number_input("Reading Speed", min_value=0, value=0, step=1)
decoding_words = st.number_input("Decoding Words", min_value=0, value=0, step=1)
decoding_non_words = st.number_input("Decoding Non-Words", min_value=0, value=0, step=1)
months_backward = st.number_input("Months Backward", min_value=0, value=0, step=1)
pataka = st.number_input("Pataka", min_value=0, value=0, step=1)
# add all the tests
# Calculate mean and standard deviation based on age and education level
# For simplicity, we will use made-up values for mean and std_dev
mean = np.random.randint(50, 100)
std_dev = np.random.randint(10, 30)
# Calculate z-score and display result
if st.button("Calculate Z-Score"):
profile = test_profile(age, education_level, isw, bnt, fas)
# for each value in the profile, calculate the z-score
bnt_mean, bnt_std, z_bnt, stanine_bnt = bnt_calculator(age, education_level, bnt)
fas_mean, fas_std, z_fas, stanine_fas = fas_calculator(age, education_level, fas)
# z_score = calculate_z_score(test_score, mean, std_dev)
st.write(f"Your bnt z-score is: {z_bnt:.2f}")
st.write(f"Mean: {bnt_mean}, Standard Deviation: {bnt_std}")
st.write(f"Your fas z-score is: {z_fas:.2f}")
st.write(f"Mean: {fas_mean}, Standard Deviation: {fas_std}")
# Create PDF
# logo_path="logo.jpg"
logo_paths = ["logo.jpg", "logo2.jpg", "logo3.jpg"]
# create the plot from the dataframe
# check if education level is more than 12 years, if more than 12, set value to one, otherwise zero
education_level = 1 if education_level > 12 else 0
plot_path = generate_graph(stanine_bnt, stanine_fas)
# create an image from the plot and add to streamlit display
image = Image.open(plot_path)
st.image(image, caption='Stanine plot', use_column_width=True)
pdf_filename = "z_score_report.pdf"
pdf = create_pdf(z_bnt, bnt_mean, bnt_std, logo_paths, plot_path)
pdf.output(name=pdf_filename)
# Download PDF
with open(pdf_filename, "rb") as file:
base64_pdf = base64.b64encode(file.read()).decode('utf-8')
pdf_display = f'<a href="data:application/octet-stream;base64,{base64_pdf}" download="{pdf_filename}">Download PDF</a>'
st.markdown(pdf_display, unsafe_allow_html=True)
# Remove PDF file after download
if os.path.exists(pdf_filename):
os.remove(pdf_filename)