From 3a59c38ad69a9455ffbd65e43f2e845ab9b8f7a4 Mon Sep 17 00:00:00 2001 From: GeorgBrantegger Date: Fri, 20 Mar 2026 13:13:29 +0100 Subject: [PATCH] wrote template for trainingsplan --- .gitignore | 1 + Trainingspläne/create_template.ipynb | 251 +++++++++++++++++++++++++++ package_loader.py | 5 +- 3 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 Trainingspläne/create_template.ipynb diff --git a/.gitignore b/.gitignore index e66547a..3a7f7b9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .venv *.txt *temp/ +*.xlsx ######################################################################################## # project specific gitignore entries diff --git a/Trainingspläne/create_template.ipynb b/Trainingspläne/create_template.ipynb new file mode 100644 index 0000000..8490137 --- /dev/null +++ b/Trainingspläne/create_template.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 11, + "id": "efde98a5", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "import openpyxl.styles" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8e84cb92", + "metadata": {}, + "outputs": [], + "source": [ + "def get_week_boundary(target_date, boundary='first'):\n", + " \"\"\"\n", + " Returns the Monday (first) or Sunday (last) of the week for a given date.\n", + " \n", + " :param target_date: datetime object\n", + " :param boundary: 'first' or 'last'\n", + " :return: datetime object\n", + " \"\"\"\n", + " # .weekday() returns 0 for Monday, 6 for Sunday\n", + " days_since_monday = target_date.weekday()\n", + " \n", + " if boundary == 'first':\n", + " return target_date - dt.timedelta(days=days_since_monday)\n", + " elif boundary == 'last':\n", + " days_until_sunday = 6 - days_since_monday\n", + " return target_date + dt.timedelta(days=days_until_sunday)\n", + " else:\n", + " raise ValueError(\"Boundary must be 'first' or 'last'\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "7a9ce99f", + "metadata": {}, + "outputs": [], + "source": [ + "year = 2026\n", + "\n", + "date_index = pd.date_range(get_week_boundary(dt.datetime(year,1,1),'first'),get_week_boundary(dt.datetime(year,12,31),'last'),freq='1D')\n", + "\n", + "columns = ['KW','date','weekday','location','trainer','meetup_time','start_time','warmup','main','cooldown','post_workout','approx_end']\n", + "columns = columns + [f'padding_{i}' for i in range(5)]\n", + "header_names = ['KW','Datum','Tag','Ort','Trainer:in','Treffpunkt','Trainingsbeginn','Warm-Up','Programm','Cool-Down','Post-Workout','Trainingsende']\n", + "header_names = header_names + ['' for i in range(5)]\n", + "\n", + "\n", + "df = pd.DataFrame(index=date_index,columns=columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "7be00de3", + "metadata": {}, + "outputs": [], + "source": [ + "weekday_dict_short = {0: 'Mo',\n", + " 1: 'Di',\n", + " 2: 'Mi',\n", + " 3: 'Do',\n", + " 4: 'Fr',\n", + " 5: 'Sa',\n", + " 6: 'So'}\n", + "\n", + "weekday_dict_long = {0: 'Montag',\n", + " 1: 'Dienstag',\n", + " 2: 'Mittwoch',\n", + " 3: 'Donnerstag',\n", + " 4: 'Freitag',\n", + " 5: 'Samstag',\n", + " 6: 'Sonntag'}" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "3f25dd5f", + "metadata": {}, + "outputs": [], + "source": [ + "df['KW'] = df.index.isocalendar().week\n", + "df['date'] = df.index.strftime('%d.%m.%Y')\n", + "df['weekday'] = df.index.weekday\n", + "df['weekday'] = df['weekday'].replace(weekday_dict_short)\n", + "df['location'] = 'RVV'" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "2b98908c", + "metadata": {}, + "outputs": [], + "source": [ + "def get_month_slice(df,month_number):\n", + "\n", + " week_numbers_of_month = df.loc[df.index.month==month_number,'KW'].unique()\n", + "\n", + " if month_number == 1:\n", + " week_numbers_of_month = [week_number if (week_number < 6) else None for week_number in week_numbers_of_month]\n", + " elif month_number == 12:\n", + " week_numbers_of_month = [week_number if (week_number > 40) else None for week_number in week_numbers_of_month]\n", + "\n", + " df_slice = df.loc[df['KW'].isin(week_numbers_of_month),:]\n", + " return df_slice" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "69339931", + "metadata": {}, + "outputs": [], + "source": [ + "def highlight_weekends(row):\n", + " # .weekday() > 4 means Saturday (5) or Sunday (6)\n", + " if row.name.weekday() > 4:\n", + " return ['background-color: #ffcccc'] * len(row) # Light red/pink\n", + " return [''] * len(row)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "379682df", + "metadata": {}, + "outputs": [], + "source": [ + "def format_rows(row):\n", + " # .weekday() > 4 means Saturday (5) or Sunday (6)\n", + " if row.name.weekday() == 0:\n", + " bg_style = 'background-color: #D1D1D1'\n", + " border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n", + " elif row.name.weekday() == 1:\n", + " bg_style = ''\n", + " border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n", + " elif row.name.weekday() == 2:\n", + " bg_style = 'background-color: #D1D1D1'\n", + " border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n", + " elif row.name.weekday() == 3:\n", + " bg_style = ''\n", + " border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n", + " elif row.name.weekday() == 4:\n", + " bg_style = 'background-color: #D1D1D1'\n", + " border_style = 'border-bottom: 2pt solid black; border-left: 1pt solid black'\n", + " elif row.name.weekday() == 5:\n", + " bg_style = 'background-color: ##C5D9F1'\n", + " border_style = 'border-bottom: 1pt solid black; border-left: 1pt solid black'\n", + " elif row.name.weekday() == 6:\n", + " bg_style = 'background-color: ##C5D9F1'\n", + " border_style = 'border-bottom: 3pt solid black; border-left: 1pt solid black'\n", + "\n", + " # Combine them (separated by semicolon)\n", + " combined = f\"{bg_style}; {border_style}\"\n", + " return [combined] * len(row)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "ae3bf250", + "metadata": {}, + "outputs": [], + "source": [ + "months = range(1,12+1,1)\n", + "file_name = f\"Trainingsplan_{year}.xlsx\"\n", + "\n", + "with pd.ExcelWriter(file_name, engine='openpyxl') as writer:\n", + " for month in months:\n", + " df_month = get_month_slice(df, month)\n", + " \n", + " # 1 format the cells\n", + " \n", + " # 1.1 format the rows (background color and borders)\n", + " styled_df = df_month.style.apply(format_rows, axis=1)\n", + " \n", + " # 1.2 center all cells\n", + " styled_df = styled_df.set_properties(**{'text-align': 'center'})\n", + " \n", + " # 2 Write to xlsx\n", + " styled_df.to_excel(writer, sheet_name=f\"{month}_{year}\",index=False,header=header_names)\n", + "\n", + " # 3 after writing, change other formats\n", + " # --- Access the openpyxl worksheet object ---\n", + " worksheet = writer.sheets[f\"{month}_{year}\"]\n", + "\n", + " # 3.1 set the widths\n", + " worksheet.column_dimensions['A'].width = 18*0.35\n", + " worksheet.column_dimensions['B'].width = 18*0.89\n", + " worksheet.column_dimensions['C'].width = 18*0.35\n", + " worksheet.column_dimensions['D'].width = 18*0.40\n", + " worksheet.column_dimensions['E'].width = 18*0.73\n", + " worksheet.column_dimensions['F'].width = 18*0.81\n", + " worksheet.column_dimensions['G'].width = 18*1.05\n", + " worksheet.column_dimensions['H'].width = 18*0.76\n", + " worksheet.column_dimensions['I'].width = 18*2.50\n", + " worksheet.column_dimensions['J'].width = 18*0.76\n", + " worksheet.column_dimensions['K'].width = 18*1.05\n", + " worksheet.column_dimensions['L'].width = 18*1.05\n", + "\n", + " # 3.2 format the header\n", + " # Define a bold, larger font\n", + " header_font = openpyxl.styles.Font(name='Arial', size=12, bold=True, color=\"000000\")\n", + " \n", + " # Iterate through the first row (Header)\n", + " # worksheet[1] returns all cells in the first row\n", + " for cell in worksheet[1]:\n", + " cell.font = header_font\n", + " cell.alignment = openpyxl.styles.Alignment(horizontal='center', vertical='center')\n", + " cell.border = openpyxl.styles.Border(bottom=openpyxl.styles.Side(border_style='medium', color='000000'))\n", + "\n", + " # 3.3 freeze the first row\n", + " worksheet.freeze_panes = 'A2' " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/package_loader.py b/package_loader.py index b10e4d7..ba19882 100644 --- a/package_loader.py +++ b/package_loader.py @@ -15,10 +15,13 @@ def get_list_of_packages_to_load(): packages.append('numpy') packages.append('pandas') packages.append('pyarrow') + packages.append('odfpy') packages.append('fsspec') packages.append('vobject') packages.append('requests') - # packages.append('openpyxl') + packages.append('openpyxl') + packages.append('jinja2') # for styling + # packages.append('matplotlib') # packages.append('pyqt5') # packages.append('tirex-ts')