grapher/main.py

207 lines
7.8 KiB
Python
Raw Normal View History

2025-01-01 18:27:58 +01:00
import imgui
import glfw
import OpenGL.GL as gl
from imgui.integrations.glfw import GlfwRenderer
from PIL import ImageColor
from dataclasses import dataclass
2025-01-02 02:36:42 +01:00
import numpy
2025-01-01 18:27:58 +01:00
@dataclass
class Lecture:
name: str
points: float
max_points: int
@dataclass
class Student:
name: str
jupyter_id: str
project: str
lectures: list
2025-01-02 02:36:42 +01:00
phil = Student(
"Phil Keier", "772fb04b24caa68fd38a05ec2a22e62b", "Geomapping",
[Lecture("1. Tutorial 1", 28.5, 31), Lecture("2. Tutorial 2", 4.5, 15), Lecture("3. Extended Application", 18, 18)]
)
nova = Student(
"Nova Eib", "772fb04b24caa68fd38a05ec2a22e62b", "Mapping Maps",
[Lecture("1. Tutorial 1", 28.5, 31), Lecture("2. Tutorial 2", 4.5, 15), Lecture("3. Extended Application", 18, 18)]
)
kathi = Student(
"Katharina Walz", "772fb04b24caa68fd38a05ec2a22e62b", "Geomapping",
[Lecture("1. Tutorial 1", 28.5, 31), Lecture("2. Tutorial 2", 4.5, 15), Lecture("3. Extended Application", 18, 18), Lecture("4. Numpy & MatPlotLib", 3, 30)]
)
students = [phil, nova, kathi]
2025-01-01 18:27:58 +01:00
# Global Color Pallet
COLOR_BACKGROUND = tuple([e/255 for e in ImageColor.getcolor("#29132E","RGBA")])
COLOR_1 = tuple([e/255 for e in ImageColor.getcolor("#321450","RGBA")])
COLOR_2 = tuple([e/255 for e in ImageColor.getcolor("#860029","RGBA")])
COLOR_3 = tuple([e/255 for e in ImageColor.getcolor("#DE004E","RGBA")])
COLOR_TEXT = tuple([e/255 for e in ImageColor.getcolor("#F887FF","RGBA")])
COLOR_TEXT_PASSED = tuple([e/255 for e in ImageColor.getcolor("#1AFE49","RGBA")])
COLOR_TEXT_FAILED = tuple([e/255 for e in ImageColor.getcolor("#FF124F","RGBA")])
2025-01-02 02:36:42 +01:00
def impl_glfw_init(window_name="Grapher Tool", width=1280, height=720):
2025-01-01 18:27:58 +01:00
if not glfw.init():
print("Could not initialize OpenGL context")
exit(1)
# OS X supports only forward-compatible core profiles from 3.2
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)
# Create a windowed mode window and its OpenGL context
window = glfw.create_window(int(width), int(height), window_name, None, None)
glfw.make_context_current(window)
if not window:
glfw.terminate()
print("Could not initialize Window")
exit(1)
return window
class GUI(object):
def __init__(self):
super().__init__()
self.backgroundColor = COLOR_BACKGROUND
self.window = impl_glfw_init()
gl.glClearColor(*self.backgroundColor)
imgui.create_context()
self.impl = GlfwRenderer(self.window)
2025-01-02 02:36:42 +01:00
# App states
self.select = 0
2025-01-01 18:27:58 +01:00
# Global GUI Setting
2025-01-02 02:36:42 +01:00
'''win_w, win_h = glfw.get_window_size(self.window)
2025-01-01 18:27:58 +01:00
fb_w, fb_h = glfw.get_framebuffer_size(self.window)
font_scaling_factor = max(float(fb_w) / win_w, float(fb_h) / win_h)
font_size_in_pixels = 30
io = imgui.get_io()
2025-01-02 02:36:42 +01:00
io.fonts.add_font_from_file_ttf("assets/MPLUSRounded1c-Regular.ttf", font_size_in_pixels * font_scaling_factor)
io.font_global_scale /= font_scaling_factor'''
2025-01-01 18:27:58 +01:00
self.loop()
def student_info(self, student: Student):
# Window Position and Sizing
io = imgui.get_io()
2025-01-02 02:36:42 +01:00
imgui.set_next_window_size(io.display_size.x*0.3, io.display_size.y*0.4)
2025-01-01 18:27:58 +01:00
imgui.set_next_window_position(io.display_size.x*0.7, io.display_size.y*0.05)
# Student accumulated Info
overall_points = sum([lecture.points for lecture in student.lectures])
if overall_points.is_integer():
overall_points = int(overall_points)
overall_max = sum([lecture.max_points for lecture in student.lectures])
with imgui.begin("Student Info", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
if not student:
imgui.text("No Student selected")
return
2025-01-02 02:36:42 +01:00
s = f"{overall_points}/{overall_max} | {round(overall_points/overall_max*100, 1)}%"
imgui.text_colored(student.name, *COLOR_TEXT)
w, h = imgui.get_window_size()
imgui.progress_bar(overall_points/overall_max, (w*0.5, h*0.1), s)
2025-01-01 18:27:58 +01:00
imgui.text("Jupyter ID:")
imgui.text_colored(student.jupyter_id.rjust(4+len(student.jupyter_id), " "), *COLOR_TEXT)
imgui.separator()
imgui.text("Project:")
imgui.text_colored(student.project.rjust(4+len(student.project), " "), *COLOR_TEXT)
imgui.text("Lectures:")
for lecture in student.lectures:
COLOR = COLOR_TEXT_PASSED if lecture.points >= lecture.max_points/3 else COLOR_TEXT_FAILED
s = f"{lecture.name}: {lecture.points}/{lecture.max_points}"
imgui.text_colored(s.rjust(4+len(s), " "), *COLOR)
def table(self, students: list):
# Window Position and Sizing
io = imgui.get_io()
2025-01-02 02:36:42 +01:00
imgui.set_next_window_size(io.display_size.x*0.15, io.display_size.y*0.95)
imgui.set_next_window_position(0, io.display_size.y*0.05)
2025-01-01 18:27:58 +01:00
with imgui.begin("Student Table", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
if not students:
imgui.text("No Dataset selected")
return
2025-01-02 02:36:42 +01:00
for n, student in enumerate(students):
opened, _ = imgui.selectable(student.name, self.select == n)
if opened:
self.select = n
def student_graph(self, student: Student):
2025-01-01 18:27:58 +01:00
2025-01-02 02:36:42 +01:00
# Window Position and Sizing
io = imgui.get_io()
imgui.set_next_window_size(io.display_size.x*0.55, io.display_size.y*0.4)
imgui.set_next_window_position(io.display_size.x*0.15, io.display_size.y*0.05)
# Setup Data
data = numpy.array([float(lecture.points) / float(lecture.max_points) * 100 for lecture in student.lectures], dtype=numpy.float32)
2025-01-01 18:27:58 +01:00
2025-01-02 02:36:42 +01:00
with imgui.begin("Student Graph", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
if not students:
imgui.text("No Dataset selected")
return
imgui.plot_histogram(
"##Data", data, overlay_text="Performance per Lecture (in %)",
scale_min=0.0, scale_max=100,
graph_size=imgui.get_content_region_available()
)
def header(self):
# Window Position and Sizing
io = imgui.get_io()
imgui.set_next_window_size(io.display_size.x, io.display_size.y*0.05)
imgui.set_next_window_position(0, 0)
2025-01-01 18:27:58 +01:00
2025-01-02 02:36:42 +01:00
with imgui.begin("HEADER", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE | imgui.WINDOW_NO_TITLE_BAR):
imgui.set_window_font_scale(1.5)
text = "Student Analyzer"
ww = imgui.get_window_size().x
tw = imgui.calc_text_size(text).x
imgui.set_cursor_pos_x((ww - tw) * 0.5)
imgui.text("Student Analyzer")
def loop(self):
2025-01-01 18:27:58 +01:00
while not glfw.window_should_close(self.window):
glfw.poll_events()
self.impl.process_inputs()
imgui.new_frame()
2025-01-02 02:36:42 +01:00
self.header()
self.table(students)
self.student_info(students[self.select])
self.student_graph(students[self.select])
2025-01-01 18:27:58 +01:00
#imgui.show_test_window()
imgui.render()
gl.glClearColor(*self.backgroundColor)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
self.impl.render(imgui.get_draw_data())
glfw.swap_buffers(self.window)
self.impl.shutdown()
glfw.terminate()
if __name__ == "__main__":
gui = GUI()