UPDATES
This commit is contained in:
parent
e50d566327
commit
859e17cf5a
170
chl/draw_func.py
170
chl/draw_func.py
@ -86,8 +86,8 @@ from math import sqrt, sin, cos, atan2, pi
|
||||
import numpy as np
|
||||
|
||||
# XPRESS ENVIRONMENT
|
||||
os.environ['XPRESSDIR'] = "/opt/xpressmp_9.2.5"
|
||||
os.environ['XPRESS'] = "/opt/xpressmp_9.2.5/bin"
|
||||
os.environ['XPRESSDIR'] = "/opt/xpressmp_9.5.0"
|
||||
os.environ['XPRESS'] = "/opt/xpressmp_9.5.0/bin"
|
||||
os.environ['LD_LIBRARY_PATH'] = os.environ['XPRESSDIR'] + \
|
||||
"/lib:"+os.environ['LD_LIBRARY_PATH']
|
||||
os.environ['DYLD_LIBRARY_PATH'] = os.environ['XPRESSDIR']+"/lib:"
|
||||
@ -326,13 +326,64 @@ def Availabilities(scenario_id,showSolution = "0"):
|
||||
|
||||
|
||||
class Draw_Simulator:
|
||||
def __init__(self,algorithm, opponent_func, html_output, use_db=False):
|
||||
def __init__(self,algorithm, opponent_func, html_output, use_db=False, use_chess=False):
|
||||
|
||||
self.chess = use_chess
|
||||
self.blue_groups = []
|
||||
self.red_groups = []
|
||||
if self.chess:
|
||||
|
||||
# basepots {'D': [
|
||||
# {'id': 47715, 'pot': 'D', 'name': 'Rouen Dragons', 'country': 'France', 'coeff': 2.0, 'lat': 49.443232, 'lon': 1.099971},
|
||||
# {'id': 47747, 'pot': 'D', 'name': 'Fehérvár AV19', 'country': 'Austria', 'coeff': 3.0, 'lat': 47.1860262, 'lon': 18.4221358},
|
||||
# {'id': 52169, 'pot': 'D', 'name': 'Sheffield Steelers', 'country': 'United Kingdom', 'coeff': 3.0, 'lat': 53.38112899999999, 'lon': -1.470085},
|
||||
# {'id': 52170, 'pot': 'D', 'name': 'SønderjyskE Vojens', 'country': 'Denmark', 'coeff': 1.0, 'lat': 55.249489, 'lon': 9.3019649},
|
||||
# {'id': 52171, 'pot': 'D', 'name': 'Unia Oświęcim', 'country': 'Poland', 'coeff': 1.0, 'lat': 50.0343982, 'lon': 19.2097782},
|
||||
# {'id': 47741, 'pot': 'D', 'name': 'Storhamar Hamar', 'country': 'Norway', 'coeff': 1.0, 'lat': 60.794442, 'lon': 11.0442983}], 'C': [
|
||||
# {'id': 52167, 'pot': 'C', 'name': 'KAC Klagenfurt', 'country': 'Austria', 'coeff': 3.0, 'lat': 46.625704, 'lon': 14.3137371},
|
||||
# {'id': 47742, 'pot': 'C', 'name': 'Växjö Lakers', 'country': 'Sweden', 'coeff': 4.0, 'lat': 56.8790044, 'lon': 14.8058522},
|
||||
# {'id': 47743, 'pot': 'C', 'name': 'Straubing Tigers', 'country': 'Germany', 'coeff': 4.0, 'lat': 48.8777333, 'lon': 12.5801538},
|
||||
# {'id': 47755, 'pot': 'C', 'name': 'Sparta Prague', 'country': 'Czechia', 'coeff': 4.0, 'lat': 50.0755381, 'lon': 14.4378005},
|
||||
# {'id': 52168, 'pot': 'C', 'name': 'Lausanne HC', 'country': 'Switzerland', 'coeff': 3.0, 'lat': 46.5196535, 'lon': 6.6322734},
|
||||
# {'id': 47737, 'pot': 'C', 'name': 'Lahti Pelicans', 'country': 'Finland', 'coeff': 2.0, 'lat': 60.9826749, 'lon': 25.6612096}], 'B': [
|
||||
# {'id': 52166, 'pot': 'B', 'name': 'Pinguins Bremerhaven', 'country': 'Germany', 'coeff': 4.0, 'lat': 53.5395845, 'lon': 8.5809424},
|
||||
# {'id': 47761, 'pot': 'B', 'name': 'Red Bull Salzburg', 'country': 'Austria', 'coeff': 3.0, 'lat': 47.80949, 'lon': 13.05501},
|
||||
# {'id': 47724, 'pot': 'B', 'name': 'Ilves Tampere', 'country': 'Finland', 'coeff': 4.0, 'lat': 61.4977524, 'lon': 23.7609535},
|
||||
# {'id': 47735, 'pot': 'B', 'name': 'Dynamo Pardubice', 'country': 'Czechia', 'coeff': 4.0, 'lat': 50.0343092, 'lon': 15.7811994},
|
||||
# {'id': 47740, 'pot': 'B', 'name': 'Färjestad Karlstad', 'country': 'Sweden', 'coeff': 4.0, 'lat': 59.4002601, 'lon': 13.5009352},
|
||||
# {'id': 47717, 'pot': 'B', 'name': 'Fribourg-Gottéron', 'country': 'Switzerland', 'coeff': 4.0, 'lat': 46.8064773, 'lon': 7.1619719}], 'A': [
|
||||
# {'id': 47721, 'pot': 'A', 'name': 'Eisbären Berlin', 'country': 'Germany', 'coeff': 4.0, 'lat': 52.5200066, 'lon': 13.404954},
|
||||
# {'id': 47719, 'pot': 'A', 'name': 'ZSC Lions Zurich', 'country': 'Switzerland', 'coeff': 4.0, 'lat': 47.4124497, 'lon': 8.5578995},
|
||||
# {'id': 47756, 'pot': 'A', 'name': 'Oceláři Třinec', 'country': 'Czechia', 'coeff': 4.0, 'lat': 49.677631, 'lon': 18.6707901},
|
||||
# {'id': 47757, 'pot': 'A', 'name': 'Skellefteå AIK', 'country': 'Sweden', 'coeff': 4.0, 'lat': 64.750244, 'lon': 20.950917},
|
||||
# {'id': 47725, 'pot': 'A', 'name': 'Tappara Tampere', 'country': 'Finland', 'coeff': 4.0, 'lat': 61.4977524, 'lon': 23.7609535},
|
||||
# {'id': 47733, 'pot': 'A', 'name': 'Genève-Servette', 'country': 'Switzerland', 'coeff': 4.0, 'lat': 46.2043907, 'lon': 6.1431577}]}
|
||||
|
||||
self.blue_teams = [
|
||||
52169, 47717, 47719
|
||||
]
|
||||
|
||||
self.red_teams = [
|
||||
47755
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
# self.blue_teams = [
|
||||
# 47733,47721,52169,47719,47717,
|
||||
# ]
|
||||
# self.red_teams = [
|
||||
# 47724,47755,47725,
|
||||
# ]
|
||||
else:
|
||||
self.blue_teams = []
|
||||
self.red_teams = []
|
||||
|
||||
self.pots = ['D','C','B','A']
|
||||
|
||||
if use_db:
|
||||
scenario_id = 9529
|
||||
scenario_id = 12098
|
||||
scenario = Scenario.objects.get(id=scenario_id)
|
||||
|
||||
self.basepots = {
|
||||
@ -354,50 +405,77 @@ class Draw_Simulator:
|
||||
df_rank = pd.read_csv('rankings_2.0.csv')
|
||||
for pot in self.basepots:
|
||||
for team in self.basepots[pot]:
|
||||
ranking = df_rank[df_rank['TEAM'] == team['name']].iloc[0]
|
||||
team['coeff'] = ranking['RANK']
|
||||
try:
|
||||
ranking = df_rank[df_rank['TEAM'] == team['name']].iloc[0]
|
||||
team['coeff'] = ranking['RANK']
|
||||
except:
|
||||
team['coeff'] = 0
|
||||
|
||||
else:
|
||||
self.basepots = {
|
||||
'A': [
|
||||
|
||||
{'id': 0, 'pot': 'A', 'name': 'Rögle Ängelholm', 'country': 'Sweden'},
|
||||
|
||||
{'id': 1, 'pot': 'A', 'name': 'Färjestad Karlstad', 'country': 'Sweden'},
|
||||
|
||||
{'id': 2, 'pot': 'A', 'name': 'EV Zug', 'country': 'Switzerland'},
|
||||
|
||||
{'id': 3, 'pot': 'A', 'name': 'Eisbären Berlin', 'country': 'Germany'},
|
||||
|
||||
{'id': 4, 'pot': 'A', 'name': 'Tappara Tampere', 'country': 'Finland'},
|
||||
|
||||
{'id': 5, 'pot': 'A', 'name': 'Oceláři Třinec',
|
||||
'country': 'Czech Republic'},
|
||||
],
|
||||
'B': [
|
||||
|
||||
{'id': 6, 'pot': 'B', 'name': 'Red Bull Salzburg', 'country': 'Austria'},
|
||||
|
||||
{'id': 7, 'pot': 'B', 'name': 'Lulea Hockey', 'country': 'Sweden'},
|
||||
|
||||
{'id': 8, 'pot': 'B', 'name': 'Fribourg-Gottéron',
|
||||
'country': 'Switzerland'},
|
||||
|
||||
{'id': 9, 'pot': 'B', 'name': 'Red Bull Munich', 'country': 'Germany'},
|
||||
|
||||
{'id': 10, 'pot': 'B', 'name': 'Jukurit Mikkeli', 'country': 'Finland'},
|
||||
|
||||
{'id': 11, 'pot': 'B', 'name': 'Mountfield HK',
|
||||
'country': 'Czech Republic'},
|
||||
],
|
||||
'C': [
|
||||
|
||||
{'id': 12, 'pot': 'C', 'name': 'VS Villach',
|
||||
'country': 'Austria'},
|
||||
|
||||
{'id': 13, 'pot': 'C', 'name': 'ZSC Lions Zürich',
|
||||
'country': 'Switzerland'},
|
||||
|
||||
{'id': 14, 'pot': 'C', 'name': 'Grizzlys Wolfsburg', 'country': 'Germany'},
|
||||
|
||||
{'id': 15, 'pot': 'C', 'name': 'Ilves Tampere',
|
||||
'country': 'Finland'},
|
||||
|
||||
{'id': 16, 'pot': 'C', 'name': 'Sparta Prague',
|
||||
'country': 'Czech Republic'},
|
||||
|
||||
{'id': 17, 'pot': 'C', 'name': 'Fehérvár AV19',
|
||||
'country': 'Austria'},
|
||||
],
|
||||
'D': [
|
||||
|
||||
{'id': 18, 'pot': 'D', 'name': 'Belfast Giants',
|
||||
'country': 'United Kingdom'},
|
||||
|
||||
{'id': 19, 'pot': 'D', 'name': 'Grenoble', 'country': 'France'},
|
||||
|
||||
{'id': 20, 'pot': 'D', 'name': 'GKS Katowice', 'country': 'Poland'},
|
||||
|
||||
{'id': 21, 'pot': 'D', 'name': 'Aalborg Pirates', 'country': 'Denmark'},
|
||||
|
||||
{'id': 22, 'pot': 'D', 'name': 'Stavanger Oilers', 'country': 'Norway'},
|
||||
|
||||
{'id': 23, 'pot': 'D', 'name': 'Slovan Bratislava', 'country': 'Slovakia'},
|
||||
]
|
||||
}
|
||||
@ -683,6 +761,11 @@ class Draw_Simulator:
|
||||
return opponents, homeGames, awayGames
|
||||
|
||||
|
||||
def groups_1_24_martin_chess(self):
|
||||
return self.groups_1_24_martin()
|
||||
|
||||
|
||||
|
||||
def groups_1_24_martin(self):
|
||||
"""
|
||||
1 groups of 24 teams
|
||||
@ -884,10 +967,17 @@ class Draw_Simulator:
|
||||
model_xp.addConstraint(
|
||||
xp.Sum([x_xp[t['id'], g] for t in self.teams if t['country'] == c]) <= 2)
|
||||
|
||||
|
||||
if self.chess:
|
||||
model_xp.addConstraint(xp.Sum(x_xp[t,g] for t in self.red_teams for g in self.blue_groups) <= 0)
|
||||
model_xp.addConstraint(xp.Sum(x_xp[t,g] for t in self.blue_teams for g in self.red_groups) <= 0)
|
||||
|
||||
|
||||
|
||||
|
||||
# do not play other countries more than 3 times
|
||||
# for t1 in self.teams:
|
||||
# for c in ['FIN']:
|
||||
# for c in ['Finland']:
|
||||
# for (g1, p1), awayGames in self.awayGames.items():
|
||||
# if p1 == t1['pot']:
|
||||
# model_xp.addConstraint(
|
||||
@ -900,7 +990,7 @@ class Draw_Simulator:
|
||||
# # model_xp.addConstraint(
|
||||
# xp.Sum([x_xp[t['id'], g] for t in self.teams if t['country'] == c]) <= 2)
|
||||
# for t in self.teams:
|
||||
# for c in ['FIN']:
|
||||
# for c in ['Finland']:
|
||||
# for t2 in self.teams_by_country[c]:
|
||||
# for (g1, p1), awayGames in self.awayGames.items():
|
||||
# if p1 == t1['pot']:
|
||||
@ -997,14 +1087,15 @@ class Draw_Simulator:
|
||||
|
||||
|
||||
def simulate(self, nTimes):
|
||||
|
||||
tt = time.time()
|
||||
if nTimes < 1:
|
||||
return None
|
||||
|
||||
tmp_stats = defaultdict(lambda: {})
|
||||
|
||||
|
||||
for n in range(nTimes):
|
||||
print(f"{self.opponent_func.__name__} - Simulation {n}")
|
||||
print(f"{self.opponent_func.__name__} - Simulation {n} - in {time.time()-tt}")
|
||||
ttt =time.time()
|
||||
|
||||
sol_dict = {
|
||||
@ -1018,6 +1109,8 @@ class Draw_Simulator:
|
||||
total_model_time = 0
|
||||
total_computations = 0
|
||||
|
||||
self.blue_groups = []
|
||||
self.red_groups = []
|
||||
|
||||
feasible = False
|
||||
for p in self.pots:
|
||||
@ -1039,6 +1132,13 @@ class Draw_Simulator:
|
||||
total_model_time += modeltime
|
||||
if feasible:
|
||||
feasible = True
|
||||
if self.chess and not self.blue_groups:
|
||||
if r['id'] in self.blue_teams:
|
||||
self.blue_groups = [1,3,5] if g % 2 == 1 else [2,4,6]
|
||||
self.red_groups = [2,4,6] if g % 2 == 1 else [1,3,5]
|
||||
elif r['id'] in self.red_teams:
|
||||
self.blue_groups = [2,4,6] if g % 2 == 1 else [1,3,5]
|
||||
self.red_groups = [1,3,5] if g % 2 == 1 else [2,4,6]
|
||||
break
|
||||
else:
|
||||
# print("\tCONFLICT: skipping group {} for team {}".format(g,r))
|
||||
@ -1064,7 +1164,7 @@ class Draw_Simulator:
|
||||
for ag in self.awayGames[g, p]:
|
||||
t2 = sol_dict[ag[0]][ag[1]]
|
||||
travel[t1['id']] += self.distance_matrix[t1['id'],t2['id']]
|
||||
if t2['country'] == 'FIN':
|
||||
if t2['country'] == 'Switzerland':
|
||||
travel_finland[t1['id']] += 1
|
||||
for op in self.opponents[g,p]:
|
||||
t2 = sol_dict[op[0]][op[1]]
|
||||
@ -1073,13 +1173,13 @@ class Draw_Simulator:
|
||||
else:
|
||||
coefficients[t1['id']] += abs(t1['coeff']-t2['coeff'])
|
||||
visited_countries[t1['id']].add(t2['country'])
|
||||
if t2['country'] == 'FIN':
|
||||
if t2['country'] == 'Switzerland':
|
||||
visited_finland[t1['id']] += 1
|
||||
|
||||
|
||||
# blockings, breaks = self.create_schedule(sol_dict, n)
|
||||
blockings = defaultdict(lambda:0)
|
||||
breaks = defaultdict(lambda:0)
|
||||
blockings, breaks = self.create_schedule(sol_dict, n)
|
||||
# blockings = defaultdict(lambda:0)
|
||||
# breaks = defaultdict(lambda:0)
|
||||
|
||||
|
||||
|
||||
@ -1220,7 +1320,7 @@ class Draw_Simulator:
|
||||
# print("\t",game[0],game[1],sol_dict[game[0]][game[1]])
|
||||
# for game in self.awayGames[g, p]:
|
||||
# print("\t",game[0],game[1],sol_dict[game[0]][game[1]])
|
||||
base_scenario_id = 9529
|
||||
base_scenario_id = 12098
|
||||
base_scenario = Scenario.objects.get(id=base_scenario_id)
|
||||
|
||||
scenario = copy_scenario(base_scenario,f" - {self.opponent_func.__name__} - {nSim}")
|
||||
@ -1282,7 +1382,13 @@ class Draw_Simulator:
|
||||
sol += "<thead>\n"
|
||||
sol += "<tr><th></th>"
|
||||
for g in self.groups:
|
||||
sol += f"<th>{g}</th>"
|
||||
if g in self.blue_groups:
|
||||
color = 'blue'
|
||||
elif g in self.red_groups:
|
||||
color = 'red'
|
||||
else:
|
||||
color = 'white'
|
||||
sol += f"<th style='background-color:{color}'>{g}</th>"
|
||||
sol += "</tr>"
|
||||
sol += "</thead>\n"
|
||||
sol += "<tbody>\n"
|
||||
@ -1295,10 +1401,16 @@ class Draw_Simulator:
|
||||
nFixed += 1
|
||||
else:
|
||||
color = 'lightyellow'
|
||||
if sol_dict[g][p]['id'] in self.blue_teams:
|
||||
text_color = 'blue'
|
||||
elif sol_dict[g][p]['id'] in self.red_teams:
|
||||
text_color = 'red'
|
||||
else:
|
||||
text_color = 'black'
|
||||
tpot = sol_dict[g][p]['pot']
|
||||
tname = sol_dict[g][p]['name']
|
||||
tcountry = sol_dict[g][p]['country']
|
||||
sol += f"<td style='background-color:{color}'>({tpot}){tname}({tcountry})</td>"
|
||||
sol += f"<td style='background-color:{color};color:{text_color}'>({tpot}){tname}({tcountry})</td>"
|
||||
sol += "</tr>"
|
||||
sol += "</tbody>\n"
|
||||
sol += "</table>\n"
|
||||
@ -1338,22 +1450,26 @@ funcs = [
|
||||
# Draw_Simulator.groups_6_4,
|
||||
# Draw_Simulator.groups_3_8,
|
||||
Draw_Simulator.groups_1_24_martin,
|
||||
Draw_Simulator.groups_2_12_martin,
|
||||
Draw_Simulator.groups_1_24_martin_chess,
|
||||
# Draw_Simulator.groups_2_12_martin,
|
||||
# Draw_Simulator.groups_2_12_stephan,
|
||||
# Draw_Simulator.groups_1_24_stephan,
|
||||
Draw_Simulator.groups_3_8_stephan,
|
||||
# Draw_Simulator.groups_3_8_stephan,
|
||||
]
|
||||
|
||||
|
||||
scenario_id = 9529
|
||||
scenario_id = 12098
|
||||
scenario = Scenario.objects.get(id=scenario_id)
|
||||
# Scenario.objects.filter(base_scenario=scenario).delete()
|
||||
|
||||
|
||||
stats = {}
|
||||
for func in funcs:
|
||||
simulator = Draw_Simulator(algorithm='XP', opponent_func = func, html_output=True,use_db=True)
|
||||
nSim = 1000
|
||||
if func == Draw_Simulator.groups_1_24_martin_chess:
|
||||
simulator = Draw_Simulator(algorithm='XP', opponent_func = func, html_output=True,use_db=True,use_chess=True)
|
||||
else:
|
||||
simulator = Draw_Simulator(algorithm='XP', opponent_func = func, html_output=True,use_db=True)
|
||||
nSim = 100
|
||||
stats[func.__name__] = simulator.simulate(nSim)
|
||||
|
||||
|
||||
@ -1391,16 +1507,16 @@ sol += "<td colspan='2'>Coe.</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Block</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>No Travel</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Countr.</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Play Finland 3x</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Travel Finland 3x</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Play Switzerland 3x</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Travel Switzerland 3x</td>"
|
||||
for t in simulator.teams:
|
||||
sol += "<td colspan='2' rowspan='1'>Trav.</td>"
|
||||
sol += "<td colspan='2' rowspan='1'>Coe.</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Block</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>No Travel</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Countr.</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Play Finland 3x</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Travel Finland 3x</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Play Switzerland 3x</td>"
|
||||
sol += "<td colspan='1' rowspan='2'>Travel Switzerland 3x</td>"
|
||||
sol += "</tr>"
|
||||
sol += "<tr>"
|
||||
sol += "<td>M</td>"
|
||||
|
||||
145
dfbnet/auswertung_sachsen.py
Normal file
145
dfbnet/auswertung_sachsen.py
Normal file
@ -0,0 +1,145 @@
|
||||
# %%
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
|
||||
|
||||
# %%
|
||||
with open("data/previous_stats_road_distance.json", "r", encoding="utf-8") as f:
|
||||
stats_previous_road = json.load(f)
|
||||
stats_previous_road = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_previous_road.items()}
|
||||
|
||||
with open("data/previous_stats_road_duration.json", "r", encoding="utf-8") as f:
|
||||
stats_previous_duration = json.load(f)
|
||||
stats_previous_duration = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_previous_duration.items()}
|
||||
|
||||
with open("data/new_stats_road_distance.json", "r", encoding="utf-8") as f:
|
||||
stats_new_road = json.load(f)
|
||||
stats_new_road = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_new_road.items()}
|
||||
|
||||
with open("data/new_stats_road_duration.json", "r", encoding="utf-8") as f:
|
||||
stats_new_duration = json.load(f)
|
||||
stats_new_duration = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_new_duration.items()}
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
print(stats_previous_road['overall'])
|
||||
print(stats_previous_duration['overall'])
|
||||
print(stats_new_road['overall'])
|
||||
print(stats_new_duration['overall'])
|
||||
|
||||
overall_stats = {
|
||||
"previous": {
|
||||
"road": stats_previous_road['overall'],
|
||||
"duration": stats_previous_duration['overall'],
|
||||
"average_max_team_distance": sum([v['max_team_distance'] for k, v in stats_previous_road.items() if k != "overall"]) / len([v['max_team_distance'] for k, v in stats_previous_road.items() if k != "overall"])
|
||||
},
|
||||
"new": {
|
||||
"road": stats_new_road['overall'],
|
||||
"duration": stats_new_duration['overall'],
|
||||
"average_max_team_distance": sum([v['max_team_distance'] for k, v in stats_new_road.items() if k != "overall"]) / len([v['max_team_distance'] for k, v in stats_new_road.items() if k != "overall"])
|
||||
}
|
||||
}
|
||||
|
||||
# %%
|
||||
|
||||
import plotly.graph_objects as go
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
""" create bar plot for overall stats """
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["previous"]["road"]['total_distance'], overall_stats["previous"]["duration"]['total_distance']],
|
||||
name="Previous",
|
||||
marker_color='rgb(55, 83, 109)'
|
||||
))
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["new"]["road"]['total_distance'], overall_stats["new"]["duration"]['total_distance']],
|
||||
name="New",
|
||||
marker_color='rgb(26, 118, 255)'
|
||||
))
|
||||
|
||||
fig.update_layout(
|
||||
title="Total Distances",
|
||||
xaxis_title="",
|
||||
yaxis_title="Distance in km / Time in m",
|
||||
barmode='group'
|
||||
)
|
||||
|
||||
fig.show()
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
""" create bar plot for overall stats """
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration", "Max Team Distance"],
|
||||
y=[overall_stats["previous"]["road"]['average_distance'], overall_stats["previous"]["duration"]['average_distance'], overall_stats["previous"]["average_max_team_distance"]],
|
||||
name="Previous",
|
||||
marker_color='rgb(55, 83, 109)'
|
||||
))
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration", "Max Team Distance"],
|
||||
y=[overall_stats["new"]["road"]['average_distance'], overall_stats["new"]["duration"]['average_distance'], overall_stats["new"]["average_max_team_distance"]],
|
||||
name="New",
|
||||
marker_color='rgb(26, 118, 255)'
|
||||
))
|
||||
|
||||
fig.update_layout(
|
||||
title="Average Total Distance per Team",
|
||||
xaxis_title="",
|
||||
yaxis_title="Distance in km / Time in m",
|
||||
barmode='group'
|
||||
)
|
||||
|
||||
fig.show()
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
""" create bar plot for overall stats """
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["previous"]["road"]['average_group_distance'], overall_stats["previous"]["duration"]['average_group_distance']],
|
||||
name="Previous",
|
||||
marker_color='rgb(55, 83, 109)'
|
||||
))
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["new"]["road"]['average_group_distance'], overall_stats["new"]["duration"]['average_group_distance']],
|
||||
name="New",
|
||||
marker_color='rgb(26, 118, 255)'
|
||||
))
|
||||
|
||||
fig.update_layout(
|
||||
title="Average Total Distance per Group",
|
||||
xaxis_title="",
|
||||
yaxis_title="Distance in km / Time in m",
|
||||
barmode='group'
|
||||
)
|
||||
|
||||
fig.show()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
59
dfbnet/competitions.py
Normal file
59
dfbnet/competitions.py
Normal file
@ -0,0 +1,59 @@
|
||||
import pandas as pd
|
||||
|
||||
def get_teams_from_staffel(staffel=None):
|
||||
|
||||
dresden = pd.read_excel("data/beispiel_daten_dresden.xlsx")
|
||||
# staffeln = dresden["STAFFEL"].unique()
|
||||
|
||||
if staffel:
|
||||
|
||||
teams_in_staffel = {}
|
||||
teams = dresden[dresden["STAFFEL"] == staffel][
|
||||
[
|
||||
"MANNSCHAFT",
|
||||
"MS_ART",
|
||||
"SP_KLASSE",
|
||||
"SCHLUESSEL_ZAHL",
|
||||
"WUNSCH_WOCHENTAG",
|
||||
"WUNSCH_TAG",
|
||||
"WUNSCH_ZEIT",
|
||||
"SPIELSTAETTE",
|
||||
]
|
||||
].to_dict(orient="records")
|
||||
|
||||
for t in teams:
|
||||
if t['MANNSCHAFT'] not in teams_in_staffel:
|
||||
teams_in_staffel[t['MANNSCHAFT']] = t
|
||||
|
||||
|
||||
return teams_in_staffel
|
||||
|
||||
else:
|
||||
staffeln = dresden["STAFFEL"].unique()
|
||||
teams_in_staffel = {}
|
||||
staffel_type = None
|
||||
for staffel in staffeln:
|
||||
find_duplicates = []
|
||||
teams_in_staffel[staffel] = []
|
||||
teams = dresden[dresden["STAFFEL"] == staffel][
|
||||
[
|
||||
"MANNSCHAFT",
|
||||
"MS_ART",
|
||||
"SP_KLASSE",
|
||||
"SCHLUESSEL_ZAHL",
|
||||
"WUNSCH_WOCHENTAG",
|
||||
"WUNSCH_TAG",
|
||||
"WUNSCH_ZEIT",
|
||||
"SPIELSTAETTE",
|
||||
]
|
||||
].to_dict(orient="records")
|
||||
|
||||
for t in teams:
|
||||
if t['MANNSCHAFT'] not in find_duplicates:
|
||||
teams_in_staffel[staffel].append(t)
|
||||
find_duplicates.append(t['MANNSCHAFT'])
|
||||
|
||||
return staffeln, teams_in_staffel
|
||||
|
||||
|
||||
|
||||
649
dfbnet/competitions_sachsen.py
Normal file
649
dfbnet/competitions_sachsen.py
Normal file
@ -0,0 +1,649 @@
|
||||
# %%
|
||||
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
|
||||
|
||||
# %%
|
||||
def convert_xlsx_to_json():
|
||||
gmaps = googlemaps.Client(key="AIzaSyB76EhR4OqjdXHQUiTkHZC0Svx_7cPGqyU")
|
||||
|
||||
staffel = None
|
||||
|
||||
dresden = pd.read_excel("data/beispiel_daten_sachsen.xlsx")
|
||||
# staffeln = dresden["STAFFEL"].unique()
|
||||
|
||||
unique_staffeln = list(
|
||||
dresden[["MS_ART", "SP_KLASSE", "STAFFEL"]]
|
||||
.drop_duplicates()
|
||||
.itertuples(index=False, name=None)
|
||||
)
|
||||
competitions_dict = {s: {} for s in unique_staffeln}
|
||||
teams_in_competition = {}
|
||||
staffel_type = None
|
||||
for art, klasse, staffel in unique_staffeln:
|
||||
find_duplicates = []
|
||||
teams_in_competition[(art, klasse, staffel)] = []
|
||||
teams = dresden[
|
||||
(dresden["MS_ART"] == art)
|
||||
& (dresden["SP_KLASSE"] == klasse)
|
||||
& (dresden["STAFFEL"] == staffel)
|
||||
][
|
||||
[
|
||||
"GEB_VEREIN",
|
||||
"GEB_MS",
|
||||
"MANNSCHAFT",
|
||||
"MS_KEY",
|
||||
"MS_ART",
|
||||
"SP_KLASSE",
|
||||
"STAFFEL",
|
||||
"SCHLUESSEL_ZAHL",
|
||||
"WUNSCH_WOCHENTAG",
|
||||
"WUNSCH_TAG",
|
||||
"WUNSCH_ZEIT",
|
||||
"SPIELSTAETTE",
|
||||
]
|
||||
].to_dict(
|
||||
orient="records"
|
||||
)
|
||||
|
||||
for t in teams:
|
||||
if t["MANNSCHAFT"] not in find_duplicates:
|
||||
teams_in_competition[(art, klasse, staffel)].append(t)
|
||||
find_duplicates.append(t["MANNSCHAFT"])
|
||||
geocode_result = gmaps.geocode(
|
||||
f"{t['GEB_VEREIN']} {t['MANNSCHAFT']} {t['SPIELSTAETTE']}"
|
||||
)
|
||||
latitude = 0
|
||||
longitude = 0
|
||||
if len(geocode_result) > 0:
|
||||
location = geocode_result[0]["geometry"]["location"]
|
||||
latitude = location["lat"]
|
||||
longitude = location["lng"]
|
||||
|
||||
t["LATITUDE"] = latitude
|
||||
t["LONGITUDE"] = longitude
|
||||
|
||||
competitions_dict[(art, klasse, staffel)]["teams"] = teams_in_competition[
|
||||
(art, klasse, staffel)
|
||||
]
|
||||
competitions_dict[(art, klasse, staffel)]["nTeams"] = len(
|
||||
teams_in_competition[(art, klasse, staffel)]
|
||||
)
|
||||
competitions_dict[(art, klasse, staffel)]["art"] = art
|
||||
competitions_dict[(art, klasse, staffel)]["klasse"] = klasse
|
||||
competitions_dict[(art, klasse, staffel)]["staffel"] = staffel
|
||||
|
||||
competitions_dict_list_keys = {str(k): v for k, v in competitions_dict.items()}
|
||||
|
||||
with open("data/sachsen.json", "w", encoding="utf-8") as f:
|
||||
json.dump(
|
||||
competitions_dict_list_keys, f, ensure_ascii=False, indent=4, default=str
|
||||
)
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
from math import sqrt, sin, cos, atan2, pi
|
||||
|
||||
|
||||
def degreesToRadians(degrees):
|
||||
"""Convert degrees to radians"""
|
||||
return degrees * pi / 180
|
||||
|
||||
|
||||
def distanceInKmByGPS(lat1, lon1, lat2, lon2):
|
||||
"""Calculate the distance between two points in km"""
|
||||
earthRadiusKm = 6371
|
||||
dLat = degreesToRadians(lat2 - lat1)
|
||||
dLon = degreesToRadians(lon2 - lon1)
|
||||
lat1 = degreesToRadians(lat1)
|
||||
lat2 = degreesToRadians(lat2)
|
||||
a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(lat1) * cos(
|
||||
lat2
|
||||
)
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
return int(earthRadiusKm * c)
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
with open("data/sachsen.json", "r", encoding="utf-8") as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
competitions = {ast.literal_eval(k): v for k, v in competitions.items()}
|
||||
|
||||
# STAFFELN PRO ART UND KLASSE
|
||||
# ('Herren', 'Landesliga') 1
|
||||
# ('Herren', 'Landesklasse') 3
|
||||
# ('Frauen', 'Landesliga') 1
|
||||
# ('Frauen', 'Landesklasse') 3
|
||||
# ('A-Junioren', 'Landesliga') 1
|
||||
# ('A-Junioren', 'Landesklasse') 4
|
||||
# ('Herren', 'Kreisoberliga') 13
|
||||
# ('Herren', '1.Kreisliga (A)') 19
|
||||
# ('Herren', '2.Kreisliga (B)') 8
|
||||
# ('Herren', '3.Kreisliga (C)') 1
|
||||
# ('Herren', '1.Kreisklasse') 21
|
||||
# ('Herren', '2.Kreisklasse') 9
|
||||
# ('A-Junioren', 'Kreisoberliga') 10
|
||||
# ('A-Junioren', '1.Kreisliga (A)') 6
|
||||
# ('Frauen', 'Kreisoberliga') 4
|
||||
# ('Frauen', '1.Kreisliga (A)') 1
|
||||
# ('Frauen', '1.Kreisklasse') 3
|
||||
# ('B-Junioren', 'Landesliga') 1
|
||||
# ('B-Junioren', 'Landesklasse') 4
|
||||
# ('B-Junioren', 'Kreisoberliga') 13
|
||||
# ('B-Junioren', '1.Kreisliga (A)') 13
|
||||
# ('B-Junioren', '1.Kreisklasse') 1
|
||||
# ('C-Junioren', 'Landesliga') 1
|
||||
# ('C-Junioren', 'Landesklasse') 4
|
||||
# ('C-Junioren', 'Kreisoberliga') 16
|
||||
# ('C-Junioren', '1.Kreisliga (A)') 15
|
||||
# ('C-Junioren', '1.Kreisklasse') 9
|
||||
# ('D-Junioren', 'Landesliga') 1
|
||||
# ('D-Junioren', 'Landesklasse') 6
|
||||
# ('D-Junioren', 'Kreisoberliga') 16
|
||||
# ('D-Junioren', '1.Kreisliga (A)') 24
|
||||
# ('D-Junioren', '2.Kreisliga (B)') 8
|
||||
# ('D-Junioren', '3.Kreisliga (C)') 2
|
||||
# ('D-Junioren', '1.Kreisklasse') 33
|
||||
# ('D-Junioren', '2.Kreisklasse') 10
|
||||
# ('B-Juniorinnen', 'Landesliga') 1
|
||||
# ('B-Juniorinnen', 'Landesklasse') 2
|
||||
# ('C-Juniorinnen', 'Landesklasse') 3
|
||||
# ('D-Juniorinnen', 'Kreisoberliga') 1
|
||||
# ('Herren Ü35', 'Kreisoberliga') 4
|
||||
# ('Herren Ü35', '1.Kreisliga (A)') 3
|
||||
# ('Herren Ü35', '1.Kreisklasse') 3
|
||||
# ('Herren Ü35', '2.Kreisklasse') 1
|
||||
# ('Herren Ü40', '1.Kreisliga (A)') 5
|
||||
# ('Herren Ü40', '1.Kreisklasse') 1
|
||||
# ('Herren Ü50', '1.Kreisliga (A)') 1
|
||||
# ('Herren Ü50', '1.Kreisklasse') 1
|
||||
# ('Freizeitsport', '1.Kreisliga (A)') 3
|
||||
# ('Freizeitsport', '1.Kreisklasse') 2
|
||||
|
||||
|
||||
some_colors = [
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
"yellow",
|
||||
"purple",
|
||||
"orange",
|
||||
"pink",
|
||||
"brown",
|
||||
"black",
|
||||
"white",
|
||||
"gray",
|
||||
"cyan",
|
||||
"magenta",
|
||||
"lime",
|
||||
"indigo",
|
||||
"violet",
|
||||
"turquoise",
|
||||
"gold",
|
||||
"silver",
|
||||
"beige",
|
||||
"maroon",
|
||||
"olive",
|
||||
"navy",
|
||||
"teal",
|
||||
"coral",
|
||||
"lavender",
|
||||
"salmon",
|
||||
"chocolate",
|
||||
"crimson",
|
||||
"aqua",
|
||||
"ivory",
|
||||
"khaki",
|
||||
"plum",
|
||||
"orchid",
|
||||
"peru",
|
||||
"tan",
|
||||
"tomato",
|
||||
"wheat",
|
||||
"azure",
|
||||
"mint",
|
||||
"apricot",
|
||||
"chartreuse",
|
||||
"amber",
|
||||
"fuchsia",
|
||||
"jade",
|
||||
"ruby",
|
||||
"amethyst",
|
||||
"rose",
|
||||
"sapphire",
|
||||
"cerulean",
|
||||
"moss",
|
||||
"denim",
|
||||
"copper",
|
||||
"peach",
|
||||
"sand",
|
||||
"pearl",
|
||||
"mulberry",
|
||||
"lemon",
|
||||
"cream",
|
||||
"ocher",
|
||||
"brass",
|
||||
"eggplant",
|
||||
"cinnamon",
|
||||
"mustard",
|
||||
"rust",
|
||||
"sienna",
|
||||
"sepia",
|
||||
"umber",
|
||||
"limegreen",
|
||||
"seagreen",
|
||||
"forestgreen",
|
||||
"dodgerblue",
|
||||
"mediumslateblue",
|
||||
"royalblue",
|
||||
"firebrick",
|
||||
"darkolivegreen",
|
||||
"midnightblue",
|
||||
"darkturquoise",
|
||||
"lightcoral",
|
||||
"palevioletred",
|
||||
"hotpink",
|
||||
"deeppink",
|
||||
"darkkhaki",
|
||||
"lightseagreen",
|
||||
"darkslategray",
|
||||
"slategray",
|
||||
"lightsteelblue",
|
||||
"skyblue",
|
||||
"lightblue",
|
||||
"powderblue",
|
||||
"darkorange",
|
||||
"lightsalmon",
|
||||
"indianred",
|
||||
"thistle",
|
||||
"burlywood",
|
||||
"mediumaquamarine",
|
||||
"mediumorchid",
|
||||
"mediumvioletred",
|
||||
"papayawhip",
|
||||
"moccasin",
|
||||
"bisque",
|
||||
"blanchedalmond",
|
||||
"antiquewhite",
|
||||
"mistyrose",
|
||||
"lavenderblush",
|
||||
"linen",
|
||||
"snow",
|
||||
"honeydew",
|
||||
"palegreen",
|
||||
"lightcyan",
|
||||
"aliceblue",
|
||||
"ghostwhite",
|
||||
"whitesmoke",
|
||||
"gainsboro",
|
||||
]
|
||||
|
||||
latitude = 51.18292980165227
|
||||
longitude = 13.11435805600463
|
||||
gmap = GoogleMapPlotter(
|
||||
latitude, longitude, 8, apikey="AIzaSyAPzFyMk3ZA0kL9TUlJ_kpV_IY56uBwdrc"
|
||||
)
|
||||
|
||||
|
||||
def random_color():
|
||||
return "#{:06x}".format(random.randint(0, 0xFFFFFF))
|
||||
|
||||
|
||||
competition_details = {}
|
||||
color = None
|
||||
for staffel, attr in competitions.items():
|
||||
if (staffel[0], staffel[1]) != ("Herren", "Kreisoberliga"):
|
||||
# if (staffel[0], staffel[1]) != ('Herren', '1.Kreisklasse'):
|
||||
continue
|
||||
competitions[staffel]["distance"] = []
|
||||
|
||||
if (staffel[0], staffel[1]) not in competition_details:
|
||||
competition_details[(staffel[0], staffel[1])] = {
|
||||
"nStaffeln": 1,
|
||||
"nTeams": 0,
|
||||
"previous_distances": [],
|
||||
"teams": [],
|
||||
}
|
||||
color = some_colors.pop(0)
|
||||
else:
|
||||
competition_details[(staffel[0], staffel[1])]["nStaffeln"] += 1
|
||||
color = some_colors.pop(0)
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
markers_text = []
|
||||
|
||||
for team1 in attr["teams"]:
|
||||
competition_details[(staffel[0], staffel[1])]["nTeams"] += 1
|
||||
competition_details[(staffel[0], staffel[1])]["teams"].append(team1)
|
||||
for team2 in attr["teams"]:
|
||||
distance = 0
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
distance = distanceInKmByGPS(
|
||||
team1["LATITUDE"],
|
||||
team1["LONGITUDE"],
|
||||
team2["LATITUDE"],
|
||||
team2["LONGITUDE"],
|
||||
)
|
||||
|
||||
competition_details[(staffel[0], staffel[1])][
|
||||
"previous_distances"
|
||||
].append(distance)
|
||||
competitions[staffel]["distance"].append(distance)
|
||||
latitudes.append(team1["LATITUDE"])
|
||||
longitudes.append(team1["LONGITUDE"])
|
||||
markers_text.append(f"{team1['MANNSCHAFT']} @{team1['SPIELSTAETTE']}")
|
||||
|
||||
# Plot the points on the map
|
||||
gmap.scatter(latitudes, longitudes, color=color, size=40, marker=False)
|
||||
for (lat1, lon1), (lat2, lon2) in itertools.combinations(
|
||||
zip(latitudes, longitudes), 2
|
||||
):
|
||||
gmap.plot([lat1, lat2], [lon1, lon2], color=color, edge_width=2)
|
||||
for lat, lon, text in zip(latitudes, longitudes, markers_text):
|
||||
gmap.marker(lat, lon, title=text.replace('"', ""), color=color)
|
||||
|
||||
print(color, staffel, attr["nTeams"], sum(attr["distance"]))
|
||||
|
||||
|
||||
for competition, details in competition_details.items():
|
||||
print(
|
||||
competition,
|
||||
details["nStaffeln"],
|
||||
details["nTeams"],
|
||||
sum(details["previous_distances"]),
|
||||
)
|
||||
|
||||
|
||||
# Optionally, draw a line path connecting the points
|
||||
# gmap.plot(latitudes, longitudes, color='blue', edge_width=2.5)
|
||||
|
||||
# Save the map to an HTML file
|
||||
gmap.draw("map_previous.html")
|
||||
|
||||
# %%
|
||||
# for key, value in competition_details.items():
|
||||
# print(key,value['nStaffeln'])
|
||||
|
||||
# %%
|
||||
|
||||
"""" GENERATE ALL DISTANCES BETWEEN TEAMS """
|
||||
|
||||
distance_between_teams = {}
|
||||
for competition, details in competition_details.items():
|
||||
print(f"Calculating distances for {competition}")
|
||||
for team1 in details["teams"]:
|
||||
distance_between_teams[team1["MANNSCHAFT"]] = {}
|
||||
for team2 in details["teams"]:
|
||||
distance = 0
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
distance = distanceInKmByGPS(
|
||||
team1["LATITUDE"],
|
||||
team1["LONGITUDE"],
|
||||
team2["LATITUDE"],
|
||||
team2["LONGITUDE"],
|
||||
)
|
||||
distance_between_teams[team1["MANNSCHAFT"]][team2["MANNSCHAFT"]] = distance
|
||||
|
||||
|
||||
|
||||
for comp, attr in competition_details.items():
|
||||
teams = attr["teams"]
|
||||
|
||||
print(teams)
|
||||
|
||||
"""" RECLUSTERING THE COMPETITION INTO DIVISIONS """
|
||||
|
||||
# from pulp import (
|
||||
# LpVariable,
|
||||
# LpProblem,
|
||||
# LpMinimize,
|
||||
# lpSum,
|
||||
# LpStatus,
|
||||
# value,
|
||||
# LpInteger,
|
||||
# XPRESS,
|
||||
# )
|
||||
|
||||
# model = LpProblem("Cluster", LpMinimize)
|
||||
|
||||
|
||||
# """ x = 1 if team i is in same division as j, 0 otherwise """
|
||||
# x = {}
|
||||
|
||||
# for team1 in teams:
|
||||
# for team2 in teams:
|
||||
# x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] = LpVariable(
|
||||
# f"team_{team1['MANNSCHAFT']}_{team2['MANNSCHAFT']}",
|
||||
# lowBound=0,
|
||||
# upBound=1,
|
||||
# cat=LpInteger,
|
||||
# )
|
||||
|
||||
# """ g = 1 if team i is i group j, 0 otherwise """
|
||||
# groups = range(1,20)
|
||||
|
||||
# g = {}
|
||||
# for team in teams:
|
||||
# for group in groups:
|
||||
# g[(team["MANNSCHAFT"], group)] = LpVariable(
|
||||
# f"team_{team['MANNSCHAFT']}_{group}",
|
||||
# lowBound=0,
|
||||
# upBound=1,
|
||||
# cat=LpInteger,
|
||||
# )
|
||||
|
||||
# """ Each team is in exactly one division """
|
||||
# for team1 in teams:
|
||||
# model += lpSum(g[(team["MANNSCHAFT"], group)] for group in groups) == 1
|
||||
|
||||
|
||||
# """ Each team is in same divisin as itself """
|
||||
# for team in teams:
|
||||
# model += x[(team["MANNSCHAFT"], team["MANNSCHAFT"])] == 1
|
||||
|
||||
# """ Each team is in same division with at least 14 and at most 16 other teams"""
|
||||
# for team1 in teams:
|
||||
# model += (
|
||||
# lpSum(
|
||||
# x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] for team2 in teams
|
||||
# )
|
||||
# >= 14
|
||||
# )
|
||||
# model += (
|
||||
# lpSum(
|
||||
# x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] for team2 in teams
|
||||
# )
|
||||
# <= 16
|
||||
# )
|
||||
|
||||
# """ no more than 16 teams in a division """
|
||||
# for group in groups:
|
||||
# model += lpSum(g[(team["MANNSCHAFT"], group)] for team in teams) <= 16
|
||||
|
||||
# """ if team1 and team2 are paired, than they are in the same division """
|
||||
# for group in groups:
|
||||
# for team1 in teams:
|
||||
# for team2 in teams:
|
||||
# if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
# model += x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] + g[(team1["MANNSCHAFT"], group)] <= 1 + g[(team2["MANNSCHAFT"], group)]
|
||||
# model += x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] + g[(team2["MANNSCHAFT"], group)] <= 1 + g[(team1["MANNSCHAFT"], group)]
|
||||
|
||||
|
||||
# """ symmetry constraint """
|
||||
# for t1, t2 in x.keys():
|
||||
# model += x[(t1, t2)] == x[(t2, t1)]
|
||||
|
||||
|
||||
# """ MINIMIZE THE TRAVEL DISTANCE """
|
||||
# model += lpSum(
|
||||
# distance_between_teams[team1["MANNSCHAFT"]][team2["MANNSCHAFT"]]
|
||||
# * x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])]
|
||||
# for team1 in teams
|
||||
# for team2 in teams
|
||||
# )
|
||||
|
||||
# model.solve(XPRESS(msg=1, gapRel=0.5))
|
||||
|
||||
# new_cluster = 1
|
||||
|
||||
# for group in groups:
|
||||
# for team in teams:
|
||||
# if value(g[(team['MANNSCHAFT'], group)]) > 0.9:
|
||||
# print(f"TEAM {team['MANNSCHAFT']} - {group}")
|
||||
|
||||
# # for team1 in teams:
|
||||
# # for team2 in teams:
|
||||
# # if value(x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])]) == 1:
|
||||
|
||||
# # print(
|
||||
# # f"SAME CLUSTER {team1['MANNSCHAFT']} - {team2['MANNSCHAFT']} - {value(g[(team1["MANNSCHAFT"], group)])}"
|
||||
# # )
|
||||
|
||||
|
||||
# # some_colors = [
|
||||
# # "red",
|
||||
# # "blue",
|
||||
# # "green",
|
||||
# # "yellow",
|
||||
# # "purple",
|
||||
# # "orange",
|
||||
# # "pink",
|
||||
# # "brown",
|
||||
# # "black",
|
||||
# # "white",
|
||||
# # "gray",
|
||||
# # "cyan",
|
||||
# # "magenta",
|
||||
# # "lime",
|
||||
# # "indigo",
|
||||
# # "violet",
|
||||
# # "turquoise",
|
||||
# # "gold",
|
||||
# # "silver",
|
||||
# # "beige",
|
||||
# # "maroon",
|
||||
# # "olive",
|
||||
# # "navy",
|
||||
# # "teal",
|
||||
# # "coral",
|
||||
# # "lavender",
|
||||
# # "salmon",
|
||||
# # "chocolate",
|
||||
# # "crimson",
|
||||
# # "aqua",
|
||||
# # "ivory",
|
||||
# # "khaki",
|
||||
# # "plum",
|
||||
# # "orchid",
|
||||
# # "peru",
|
||||
# # "tan",
|
||||
# # "tomato",
|
||||
# # "wheat",
|
||||
# # "azure",
|
||||
# # "mint",
|
||||
# # "apricot",
|
||||
# # "chartreuse",
|
||||
# # "amber",
|
||||
# # "fuchsia",
|
||||
# # "jade",
|
||||
# # "ruby",
|
||||
# # "amethyst",
|
||||
# # "rose",
|
||||
# # "sapphire",
|
||||
# # "cerulean",
|
||||
# # "moss",
|
||||
# # "denim",
|
||||
# # "copper",
|
||||
# # "peach",
|
||||
# # "sand",
|
||||
# # "pearl",
|
||||
# # "mulberry",
|
||||
# # "lemon",
|
||||
# # "cream",
|
||||
# # "ocher",
|
||||
# # "brass",
|
||||
# # "eggplant",
|
||||
# # "cinnamon",
|
||||
# # "mustard",
|
||||
# # "rust",
|
||||
# # "sienna",
|
||||
# # "sepia",
|
||||
# # "umber",
|
||||
# # "limegreen",
|
||||
# # "seagreen",
|
||||
# # "forestgreen",
|
||||
# # "dodgerblue",
|
||||
# # "mediumslateblue",
|
||||
# # "royalblue",
|
||||
# # "firebrick",
|
||||
# # "darkolivegreen",
|
||||
# # "midnightblue",
|
||||
# # "darkturquoise",
|
||||
# # "lightcoral",
|
||||
# # "palevioletred",
|
||||
# # "hotpink",
|
||||
# # "deeppink",
|
||||
# # "darkkhaki",
|
||||
# # "lightseagreen",
|
||||
# # "darkslategray",
|
||||
# # "slategray",
|
||||
# # "lightsteelblue",
|
||||
# # "skyblue",
|
||||
# # "lightblue",
|
||||
# # "powderblue",
|
||||
# # "darkorange",
|
||||
# # "lightsalmon",
|
||||
# # "indianred",
|
||||
# # "thistle",
|
||||
# # "burlywood",
|
||||
# # "mediumaquamarine",
|
||||
# # "mediumorchid",
|
||||
# # "mediumvioletred",
|
||||
# # "papayawhip",
|
||||
# # "moccasin",
|
||||
# # "bisque",
|
||||
# # "blanchedalmond",
|
||||
# # "antiquewhite",
|
||||
# # "mistyrose",
|
||||
# # "lavenderblush",
|
||||
# # "linen",
|
||||
# # "snow",
|
||||
# # "honeydew",
|
||||
# # "palegreen",
|
||||
# # "lightcyan",
|
||||
# # "aliceblue",
|
||||
# # "ghostwhite",
|
||||
# # "whitesmoke",
|
||||
# # "gainsboro",
|
||||
# # ]
|
||||
|
||||
# # latitude = 51.18292980165227
|
||||
# # longitude = 13.11435805600463
|
||||
# # gmap = GoogleMapPlotter(
|
||||
# # latitude, longitude, 8, apikey="AIzaSyAPzFyMk3ZA0kL9TUlJ_kpV_IY56uBwdrc"
|
||||
# # )
|
||||
|
||||
|
||||
# # # Plot the points on the map
|
||||
# # gmap.scatter(latitudes, longitudes, color=color, size=40, marker=False)
|
||||
# # for (lat1, lon1), (lat2, lon2) in itertools.combinations(
|
||||
# # zip(latitudes, longitudes), 2
|
||||
# # ):
|
||||
# # gmap.plot([lat1, lat2], [lon1, lon2], color=color, edge_width=2)
|
||||
# # for lat, lon, text in zip(latitudes, longitudes, markers_text):
|
||||
# # gmap.marker(lat, lon, title=text.replace('"', ""), color=color)
|
||||
|
||||
# %%
|
||||
896
dfbnet/competitions_sachsen_new.py
Normal file
896
dfbnet/competitions_sachsen_new.py
Normal file
@ -0,0 +1,896 @@
|
||||
# %%
|
||||
|
||||
from pulp import (
|
||||
LpVariable,
|
||||
LpProblem,
|
||||
LpMinimize,
|
||||
lpSum,
|
||||
LpStatus,
|
||||
value,
|
||||
LpInteger,
|
||||
LpContinuous,
|
||||
XPRESS,
|
||||
)
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
|
||||
|
||||
# %%
|
||||
def convert_xlsx_to_json():
|
||||
gmaps = googlemaps.Client(key="AIzaSyB76EhR4OqjdXHQUiTkHZC0Svx_7cPGqyU")
|
||||
|
||||
staffel = None
|
||||
|
||||
dresden = pd.read_excel("data/beispiel_daten_sachsen.xlsx")
|
||||
# staffeln = dresden["STAFFEL"].unique()
|
||||
|
||||
unique_staffeln = list(
|
||||
dresden[["MS_ART", "SP_KLASSE", "STAFFEL"]]
|
||||
.drop_duplicates()
|
||||
.itertuples(index=False, name=None)
|
||||
)
|
||||
competitions_dict = {s: {} for s in unique_staffeln}
|
||||
teams_in_competition = {}
|
||||
staffel_type = None
|
||||
for art, klasse, staffel in unique_staffeln:
|
||||
find_duplicates = []
|
||||
teams_in_competition[(art, klasse, staffel)] = []
|
||||
teams = dresden[
|
||||
(dresden["MS_ART"] == art)
|
||||
& (dresden["SP_KLASSE"] == klasse)
|
||||
& (dresden["STAFFEL"] == staffel)
|
||||
][
|
||||
[
|
||||
"GEB_VEREIN",
|
||||
"GEB_MS",
|
||||
"MANNSCHAFT",
|
||||
"MS_KEY",
|
||||
"MS_ART",
|
||||
"SP_KLASSE",
|
||||
"STAFFEL",
|
||||
"SCHLUESSEL_ZAHL",
|
||||
"WUNSCH_WOCHENTAG",
|
||||
"WUNSCH_TAG",
|
||||
"WUNSCH_ZEIT",
|
||||
"SPIELSTAETTE",
|
||||
]
|
||||
].to_dict(
|
||||
orient="records"
|
||||
)
|
||||
|
||||
for t in teams:
|
||||
if t["MANNSCHAFT"] not in find_duplicates:
|
||||
teams_in_competition[(art, klasse, staffel)].append(t)
|
||||
find_duplicates.append(t["MANNSCHAFT"])
|
||||
geocode_result = gmaps.geocode(
|
||||
f"{t['GEB_VEREIN']} {t['MANNSCHAFT']} {t['SPIELSTAETTE']}"
|
||||
)
|
||||
latitude = 0
|
||||
longitude = 0
|
||||
if len(geocode_result) > 0:
|
||||
location = geocode_result[0]["geometry"]["location"]
|
||||
latitude = location["lat"]
|
||||
longitude = location["lng"]
|
||||
|
||||
t["LATITUDE"] = latitude
|
||||
t["LONGITUDE"] = longitude
|
||||
|
||||
competitions_dict[(art, klasse, staffel)]["teams"] = teams_in_competition[
|
||||
(art, klasse, staffel)
|
||||
]
|
||||
competitions_dict[(art, klasse, staffel)]["nTeams"] = len(
|
||||
teams_in_competition[(art, klasse, staffel)]
|
||||
)
|
||||
competitions_dict[(art, klasse, staffel)]["art"] = art
|
||||
competitions_dict[(art, klasse, staffel)]["klasse"] = klasse
|
||||
competitions_dict[(art, klasse, staffel)]["staffel"] = staffel
|
||||
|
||||
competitions_dict_list_keys = {str(k): v for k, v in competitions_dict.items()}
|
||||
|
||||
with open("data/sachsen.json", "w", encoding="utf-8") as f:
|
||||
json.dump(
|
||||
competitions_dict_list_keys, f, ensure_ascii=False, indent=4, default=str
|
||||
)
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
from math import sqrt, sin, cos, atan2, pi
|
||||
|
||||
|
||||
def degreesToRadians(degrees):
|
||||
"""Convert degrees to radians"""
|
||||
return degrees * pi / 180
|
||||
|
||||
|
||||
def distanceInKmByGPS(lat1, lon1, lat2, lon2):
|
||||
"""Calculate the distance between two points in km"""
|
||||
earthRadiusKm = 6371
|
||||
dLat = degreesToRadians(lat2 - lat1)
|
||||
dLon = degreesToRadians(lon2 - lon1)
|
||||
lat1 = degreesToRadians(lat1)
|
||||
lat2 = degreesToRadians(lat2)
|
||||
a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(lat1) * cos(
|
||||
lat2
|
||||
)
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
return int(earthRadiusKm * c)
|
||||
|
||||
|
||||
for metric in ["road_distance", "road_duration", "flight_distance"]:
|
||||
print("\n\n#######################################################")
|
||||
print(f"Calculating {metric}")
|
||||
# %%
|
||||
""" read csv and skip first row """
|
||||
distance_dict = {}
|
||||
with open("data/distances.csv", "r", encoding="utf-8") as f:
|
||||
csv_distances = f.readlines()
|
||||
for i, row in enumerate(csv_distances):
|
||||
if i == 0:
|
||||
continue
|
||||
_, _, team1, team2, road_distance, road_duration, flight_distance = (
|
||||
row.split(",")
|
||||
)
|
||||
distance_dict[(team1, team2)] = {
|
||||
"road_distance": float(road_distance),
|
||||
"road_duration": float(road_duration),
|
||||
"flight_distance": float(flight_distance),
|
||||
}
|
||||
|
||||
# %%
|
||||
|
||||
with open("data/sachsen.json", "r", encoding="utf-8") as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
competitions = {ast.literal_eval(k): v for k, v in competitions.items()}
|
||||
|
||||
# region
|
||||
# STAFFELN PRO ART UND KLASSE
|
||||
# ('Herren', 'Landesliga') 1
|
||||
# ('Herren', 'Landesklasse') 3
|
||||
# ('Frauen', 'Landesliga') 1
|
||||
# ('Frauen', 'Landesklasse') 3
|
||||
# ('A-Junioren', 'Landesliga') 1
|
||||
# ('A-Junioren', 'Landesklasse') 4
|
||||
# ('Herren', 'Kreisoberliga') 13
|
||||
# ('Herren', '1.Kreisliga (A)') 19
|
||||
# ('Herren', '2.Kreisliga (B)') 8
|
||||
# ('Herren', '3.Kreisliga (C)') 1
|
||||
# ('Herren', '1.Kreisklasse') 21
|
||||
# ('Herren', '2.Kreisklasse') 9
|
||||
# ('A-Junioren', 'Kreisoberliga') 10
|
||||
# ('A-Junioren', '1.Kreisliga (A)') 6
|
||||
# ('Frauen', 'Kreisoberliga') 4
|
||||
# ('Frauen', '1.Kreisliga (A)') 1
|
||||
# ('Frauen', '1.Kreisklasse') 3
|
||||
# ('B-Junioren', 'Landesliga') 1
|
||||
# ('B-Junioren', 'Landesklasse') 4
|
||||
# ('B-Junioren', 'Kreisoberliga') 13
|
||||
# ('B-Junioren', '1.Kreisliga (A)') 13
|
||||
# ('B-Junioren', '1.Kreisklasse') 1
|
||||
# ('C-Junioren', 'Landesliga') 1
|
||||
# ('C-Junioren', 'Landesklasse') 4
|
||||
# ('C-Junioren', 'Kreisoberliga') 16
|
||||
# ('C-Junioren', '1.Kreisliga (A)') 15
|
||||
# ('C-Junioren', '1.Kreisklasse') 9
|
||||
# ('D-Junioren', 'Landesliga') 1
|
||||
# ('D-Junioren', 'Landesklasse') 6
|
||||
# ('D-Junioren', 'Kreisoberliga') 16
|
||||
# ('D-Junioren', '1.Kreisliga (A)') 24
|
||||
# ('D-Junioren', '2.Kreisliga (B)') 8
|
||||
# ('D-Junioren', '3.Kreisliga (C)') 2
|
||||
# ('D-Junioren', '1.Kreisklasse') 33
|
||||
# ('D-Junioren', '2.Kreisklasse') 10
|
||||
# ('B-Juniorinnen', 'Landesliga') 1
|
||||
# ('B-Juniorinnen', 'Landesklasse') 2
|
||||
# ('C-Juniorinnen', 'Landesklasse') 3
|
||||
# ('D-Juniorinnen', 'Kreisoberliga') 1
|
||||
# ('Herren Ü35', 'Kreisoberliga') 4
|
||||
# ('Herren Ü35', '1.Kreisliga (A)') 3
|
||||
# ('Herren Ü35', '1.Kreisklasse') 3
|
||||
# ('Herren Ü35', '2.Kreisklasse') 1
|
||||
# ('Herren Ü40', '1.Kreisliga (A)') 5
|
||||
# ('Herren Ü40', '1.Kreisklasse') 1
|
||||
# ('Herren Ü50', '1.Kreisliga (A)') 1
|
||||
# ('Herren Ü50', '1.Kreisklasse') 1
|
||||
# ('Freizeitsport', '1.Kreisliga (A)') 3
|
||||
# ('Freizeitsport', '1.Kreisklasse') 2
|
||||
# endregion
|
||||
|
||||
some_colors = [
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
"yellow",
|
||||
"purple",
|
||||
"orange",
|
||||
"pink",
|
||||
"brown",
|
||||
"black",
|
||||
"white",
|
||||
"gray",
|
||||
"cyan",
|
||||
"magenta",
|
||||
"lime",
|
||||
"indigo",
|
||||
"violet",
|
||||
"turquoise",
|
||||
"gold",
|
||||
"silver",
|
||||
"beige",
|
||||
"maroon",
|
||||
"olive",
|
||||
"navy",
|
||||
"teal",
|
||||
"coral",
|
||||
"lavender",
|
||||
"salmon",
|
||||
"chocolate",
|
||||
"crimson",
|
||||
"aqua",
|
||||
"ivory",
|
||||
"khaki",
|
||||
"plum",
|
||||
"orchid",
|
||||
"peru",
|
||||
"tan",
|
||||
"tomato",
|
||||
"wheat",
|
||||
"azure",
|
||||
"mint",
|
||||
"apricot",
|
||||
"chartreuse",
|
||||
"amber",
|
||||
"fuchsia",
|
||||
"jade",
|
||||
"ruby",
|
||||
"amethyst",
|
||||
"rose",
|
||||
"sapphire",
|
||||
"cerulean",
|
||||
"moss",
|
||||
"denim",
|
||||
"copper",
|
||||
"peach",
|
||||
"sand",
|
||||
"pearl",
|
||||
"mulberry",
|
||||
"lemon",
|
||||
"cream",
|
||||
"ocher",
|
||||
"brass",
|
||||
"eggplant",
|
||||
"cinnamon",
|
||||
"mustard",
|
||||
"rust",
|
||||
"sienna",
|
||||
"sepia",
|
||||
"umber",
|
||||
"limegreen",
|
||||
"seagreen",
|
||||
"forestgreen",
|
||||
"dodgerblue",
|
||||
"mediumslateblue",
|
||||
"royalblue",
|
||||
"firebrick",
|
||||
"darkolivegreen",
|
||||
"midnightblue",
|
||||
"darkturquoise",
|
||||
"lightcoral",
|
||||
"palevioletred",
|
||||
"hotpink",
|
||||
"deeppink",
|
||||
"darkkhaki",
|
||||
"lightseagreen",
|
||||
"darkslategray",
|
||||
"slategray",
|
||||
"lightsteelblue",
|
||||
"skyblue",
|
||||
"lightblue",
|
||||
"powderblue",
|
||||
"darkorange",
|
||||
"lightsalmon",
|
||||
"indianred",
|
||||
"thistle",
|
||||
"burlywood",
|
||||
"mediumaquamarine",
|
||||
"mediumorchid",
|
||||
"mediumvioletred",
|
||||
"papayawhip",
|
||||
"moccasin",
|
||||
"bisque",
|
||||
"blanchedalmond",
|
||||
"antiquewhite",
|
||||
"mistyrose",
|
||||
"lavenderblush",
|
||||
"linen",
|
||||
"snow",
|
||||
"honeydew",
|
||||
"palegreen",
|
||||
"lightcyan",
|
||||
"aliceblue",
|
||||
"ghostwhite",
|
||||
"whitesmoke",
|
||||
"gainsboro",
|
||||
]
|
||||
|
||||
latitude = 51.18292980165227
|
||||
longitude = 13.11435805600463
|
||||
gmap = GoogleMapPlotter(
|
||||
latitude, longitude, 8, apikey="AIzaSyAPzFyMk3ZA0kL9TUlJ_kpV_IY56uBwdrc"
|
||||
)
|
||||
|
||||
def random_color():
|
||||
return "#{:06x}".format(random.randint(0, 0xFFFFFF))
|
||||
|
||||
previous_statistics = {}
|
||||
|
||||
competition_details = {}
|
||||
color = None
|
||||
for staffel, attr in competitions.items():
|
||||
if (staffel[0], staffel[1]) != ("Herren", "Kreisoberliga"):
|
||||
# if (staffel[0], staffel[1]) != ('Herren', '1.Kreisklasse'):
|
||||
continue
|
||||
competitions[staffel]["distance"] = []
|
||||
|
||||
if (staffel[0], staffel[1]) not in competition_details:
|
||||
competition_details[(staffel[0], staffel[1])] = {
|
||||
"nStaffeln": 1,
|
||||
"nTeams": 0,
|
||||
"previous_distances": [],
|
||||
"teams": [],
|
||||
}
|
||||
color = some_colors.pop(0)
|
||||
else:
|
||||
competition_details[(staffel[0], staffel[1])]["nStaffeln"] += 1
|
||||
color = some_colors.pop(0)
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
markers_text = []
|
||||
|
||||
distance_for_team = {}
|
||||
for team1 in attr["teams"]:
|
||||
competition_details[(staffel[0], staffel[1])]["nTeams"] += 1
|
||||
competition_details[(staffel[0], staffel[1])]["teams"].append(team1)
|
||||
distance_for_team[team1["MANNSCHAFT"]] = []
|
||||
for team2 in attr["teams"]:
|
||||
distance = 0
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
distance = distance_dict[
|
||||
(team1["MANNSCHAFT"], team2["MANNSCHAFT"])
|
||||
][metric]
|
||||
competition_details[(staffel[0], staffel[1])][
|
||||
"previous_distances"
|
||||
].append(distance)
|
||||
competitions[staffel]["distance"].append(distance)
|
||||
distance_for_team[team1["MANNSCHAFT"]].append(distance)
|
||||
latitudes.append(team1["LATITUDE"])
|
||||
longitudes.append(team1["LONGITUDE"])
|
||||
markers_text.append(f"{team1['MANNSCHAFT']} @{team1['SPIELSTAETTE']}")
|
||||
|
||||
# Plot the points on the map
|
||||
gmap.scatter(latitudes, longitudes, color=color, size=40, marker=False)
|
||||
for (lat1, lon1), (lat2, lon2) in itertools.combinations(
|
||||
zip(latitudes, longitudes), 2
|
||||
):
|
||||
gmap.plot([lat1, lat2], [lon1, lon2], color=color, edge_width=2)
|
||||
for lat, lon, text in zip(latitudes, longitudes, markers_text):
|
||||
gmap.marker(lat, lon, title=text.replace('"', ""), color=color)
|
||||
|
||||
print(color, staffel, attr["nTeams"], sum(attr["distance"]))
|
||||
|
||||
previous_statistics[staffel] = {
|
||||
"nTeams": attr["nTeams"],
|
||||
"total_distance": sum(attr["distance"]),
|
||||
"average_distance": sum(attr["distance"]) / attr["nTeams"],
|
||||
"max_distance": max(attr["distance"]),
|
||||
"min_distance": min(attr["distance"]),
|
||||
"max_team": max(distance_for_team, key=lambda x: sum(distance_for_team[x])),
|
||||
"max_team_distance": max(
|
||||
[sum(distance_for_team[x]) for x in distance_for_team]
|
||||
),
|
||||
"min_team": min(distance_for_team, key=lambda x: sum(distance_for_team[x])),
|
||||
"min_team_distance": min(
|
||||
[sum(distance_for_team[x]) for x in distance_for_team]
|
||||
),
|
||||
}
|
||||
|
||||
""" GATHER SOME PREVIOUS STATISTICS """
|
||||
|
||||
for key, val in previous_statistics.items():
|
||||
print(key, val)
|
||||
|
||||
""" add overall statistics """
|
||||
for competition, details in competition_details.items():
|
||||
print(
|
||||
competition,
|
||||
details["nStaffeln"],
|
||||
details["nTeams"],
|
||||
sum(details["previous_distances"]),
|
||||
)
|
||||
previous_statistics["overall"] = {
|
||||
"nStaffeln": sum(
|
||||
[details["nStaffeln"] for details in competition_details.values()]
|
||||
),
|
||||
"nTeams": sum(
|
||||
[details["nTeams"] for details in competition_details.values()]
|
||||
),
|
||||
"total_distance": sum(
|
||||
[
|
||||
sum(details["previous_distances"])
|
||||
for details in competition_details.values()
|
||||
]
|
||||
),
|
||||
"average_distance": sum(
|
||||
[
|
||||
sum(details["previous_distances"])
|
||||
for details in competition_details.values()
|
||||
]
|
||||
)
|
||||
/ sum([details["nTeams"] for details in competition_details.values()]),
|
||||
"max_distance": max(
|
||||
[
|
||||
max(details["previous_distances"])
|
||||
for details in competition_details.values()
|
||||
]
|
||||
),
|
||||
"min_distance": min(
|
||||
[
|
||||
min(details["previous_distances"])
|
||||
for details in competition_details.values()
|
||||
]
|
||||
),
|
||||
"average_group_distance": sum(
|
||||
[
|
||||
sum(details["previous_distances"])
|
||||
for details in competition_details.values()
|
||||
]
|
||||
)
|
||||
/ sum([details["nStaffeln"] for details in competition_details.values()]),
|
||||
}
|
||||
|
||||
previous_statistics_str_keys = {str(k): v for k, v in previous_statistics.items()}
|
||||
|
||||
with open(f"data/previous_stats_{metric}.json", "w", encoding="utf-8") as f:
|
||||
json.dump(
|
||||
previous_statistics_str_keys, f, ensure_ascii=False, indent=4, default=str
|
||||
)
|
||||
|
||||
# Optionally, draw a line path connecting the points
|
||||
# gmap.plot(latitudes, longitudes, color='blue', edge_width=2.5)
|
||||
|
||||
# Save the map to an HTML file
|
||||
gmap.draw(f"map_previous_{metric}.html")
|
||||
# %%
|
||||
# for key, value in competition_details.items():
|
||||
# print(key,value['nStaffeln'])
|
||||
|
||||
# %%
|
||||
|
||||
"""" GENERATE ALL DISTANCES BETWEEN TEAMS """
|
||||
|
||||
distance_between_teams = {}
|
||||
for competition, details in competition_details.items():
|
||||
print(f"Calculating distances for {competition}")
|
||||
for team1 in details["teams"]:
|
||||
distance_between_teams[team1["MANNSCHAFT"]] = {}
|
||||
for team2 in details["teams"]:
|
||||
distance = 0
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
distance = distance_dict[
|
||||
(team1["MANNSCHAFT"], team2["MANNSCHAFT"])
|
||||
][metric]
|
||||
distance_between_teams[team1["MANNSCHAFT"]][
|
||||
team2["MANNSCHAFT"]
|
||||
] = distance
|
||||
|
||||
for comp, attr in competition_details.items():
|
||||
teams = attr["teams"]
|
||||
|
||||
"""" RECLUSTERING THE COMPETITION INTO DIVISIONS """
|
||||
|
||||
model = LpProblem("Cluster", LpMinimize)
|
||||
|
||||
""" x = 1 if team i is in same division as j, 0 otherwise """
|
||||
x = {}
|
||||
|
||||
for team1 in teams:
|
||||
for team2 in teams:
|
||||
x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] = LpVariable(
|
||||
f"team_{team1['MANNSCHAFT']}_{team2['MANNSCHAFT']}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
""" g = 1 if team i is i group j, 0 otherwise """
|
||||
groups = range(1, 14)
|
||||
|
||||
g = {}
|
||||
for team in teams:
|
||||
for group in groups:
|
||||
g[(team["MANNSCHAFT"], group)] = LpVariable(
|
||||
f"team_{team['MANNSCHAFT']}_{group}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
""" Each team is in exactly one division """
|
||||
for team in teams:
|
||||
model += lpSum(g[(team["MANNSCHAFT"], group)] for group in groups) == 1
|
||||
|
||||
""" Each team is in same divisin as itself """
|
||||
for team in teams:
|
||||
model += x[(team["MANNSCHAFT"], team["MANNSCHAFT"])] == 1
|
||||
|
||||
""" Each team is in same division with at least 14 and at most 16 other teams"""
|
||||
|
||||
for team1 in teams:
|
||||
model += (
|
||||
lpSum(x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] for team2 in teams)
|
||||
>= 14
|
||||
)
|
||||
model += (
|
||||
lpSum(x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])] for team2 in teams)
|
||||
<= 16
|
||||
)
|
||||
|
||||
if False:
|
||||
""" no more than 16 teams in a division """
|
||||
for group in groups:
|
||||
model += lpSum(g[(team["MANNSCHAFT"], group)] for team in teams) <= 16
|
||||
|
||||
""" use each group / at least one team per group """
|
||||
for group in groups:
|
||||
model += lpSum(g[(team["MANNSCHAFT"], group)] for team in teams) >= 1
|
||||
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 1)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 2)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 3)] for team in teams) == 16
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 4)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 5)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 6)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 7)] for team in teams) == 16
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 8)] for team in teams) == 16
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 9)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 10)] for team in teams) == 14
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 11)] for team in teams) == 15
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 12)] for team in teams) == 16
|
||||
model += lpSum(g[(team["MANNSCHAFT"], 13)] for team in teams) == 14
|
||||
|
||||
|
||||
""" if team1 and team2 are paired, than they are in the same division """
|
||||
for group in groups:
|
||||
for team1 in teams:
|
||||
for team2 in teams:
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
model += (
|
||||
x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])]
|
||||
+ g[(team1["MANNSCHAFT"], group)]
|
||||
<= 1 + g[(team2["MANNSCHAFT"], group)]
|
||||
)
|
||||
model += (
|
||||
x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])]
|
||||
+ g[(team2["MANNSCHAFT"], group)]
|
||||
<= 1 + g[(team1["MANNSCHAFT"], group)]
|
||||
)
|
||||
|
||||
""" symmetry constraint """
|
||||
for t1, t2 in x.keys():
|
||||
model += x[(t1, t2)] == x[(t2, t1)]
|
||||
|
||||
""" MINIMIZE THE TRAVEL DISTANCE """
|
||||
model += lpSum(
|
||||
distance_between_teams[team1["MANNSCHAFT"]][team2["MANNSCHAFT"]]
|
||||
* x[(team1["MANNSCHAFT"], team2["MANNSCHAFT"])]
|
||||
for team1 in teams
|
||||
for team2 in teams
|
||||
)
|
||||
|
||||
model.solve(XPRESS(msg=1, gapRel=0.01, timeLimit=1))
|
||||
|
||||
localsearch_time = 3600*2
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
while time.time() - start_time < localsearch_time:
|
||||
|
||||
used_groups = [
|
||||
group
|
||||
for group in groups
|
||||
if sum(value(g[(team["MANNSCHAFT"], group)]) for team in teams) > 0.9
|
||||
]
|
||||
|
||||
group_size = random.randint(2, 6)
|
||||
opt_groups = random.sample(used_groups, group_size)
|
||||
opt_stalltime = group_size * 25
|
||||
|
||||
print(f"Time: {time.time() - start_time}")
|
||||
print("Optimizing groups", opt_groups)
|
||||
|
||||
for key in x.keys():
|
||||
x[key].setInitialValue(value(x[key]))
|
||||
x[key].lowBound = value(x[key])
|
||||
|
||||
for key in g.keys():
|
||||
g[key].setInitialValue(value(g[key]))
|
||||
if key[1] in opt_groups:
|
||||
g[key].lowBound = 0
|
||||
for (t1,t2) in x.keys():
|
||||
if t1 == key[0] or t2 == key[0]:
|
||||
x[(t1,t2)].lowBound = 0
|
||||
else:
|
||||
g[key].lowBound = value(g[key])
|
||||
|
||||
model.solve(
|
||||
XPRESS(
|
||||
msg=1,
|
||||
gapRel=0.01,
|
||||
warmStart=True,
|
||||
options=[f"MAXSTALLTIME={opt_stalltime}"],
|
||||
)
|
||||
)
|
||||
|
||||
some_colors = [
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
"yellow",
|
||||
"purple",
|
||||
"orange",
|
||||
"pink",
|
||||
"brown",
|
||||
"black",
|
||||
"white",
|
||||
"gray",
|
||||
"cyan",
|
||||
"magenta",
|
||||
"lime",
|
||||
"indigo",
|
||||
"violet",
|
||||
"turquoise",
|
||||
"gold",
|
||||
"silver",
|
||||
"beige",
|
||||
"maroon",
|
||||
"olive",
|
||||
"navy",
|
||||
"teal",
|
||||
"coral",
|
||||
"lavender",
|
||||
"salmon",
|
||||
"chocolate",
|
||||
"crimson",
|
||||
"aqua",
|
||||
"ivory",
|
||||
"khaki",
|
||||
"plum",
|
||||
"orchid",
|
||||
"peru",
|
||||
"tan",
|
||||
"tomato",
|
||||
"wheat",
|
||||
"azure",
|
||||
"mint",
|
||||
"apricot",
|
||||
"chartreuse",
|
||||
"amber",
|
||||
"fuchsia",
|
||||
"jade",
|
||||
"ruby",
|
||||
"amethyst",
|
||||
"rose",
|
||||
"sapphire",
|
||||
"cerulean",
|
||||
"moss",
|
||||
"denim",
|
||||
"copper",
|
||||
"peach",
|
||||
"sand",
|
||||
"pearl",
|
||||
"mulberry",
|
||||
"lemon",
|
||||
"cream",
|
||||
"ocher",
|
||||
"brass",
|
||||
"eggplant",
|
||||
"cinnamon",
|
||||
"mustard",
|
||||
"rust",
|
||||
"sienna",
|
||||
"sepia",
|
||||
"umber",
|
||||
"limegreen",
|
||||
"seagreen",
|
||||
"forestgreen",
|
||||
"dodgerblue",
|
||||
"mediumslateblue",
|
||||
"royalblue",
|
||||
"firebrick",
|
||||
"darkolivegreen",
|
||||
"midnightblue",
|
||||
"darkturquoise",
|
||||
"lightcoral",
|
||||
"palevioletred",
|
||||
"hotpink",
|
||||
"deeppink",
|
||||
"darkkhaki",
|
||||
"lightseagreen",
|
||||
"darkslategray",
|
||||
"slategray",
|
||||
"lightsteelblue",
|
||||
"skyblue",
|
||||
"lightblue",
|
||||
"powderblue",
|
||||
"darkorange",
|
||||
"lightsalmon",
|
||||
"indianred",
|
||||
"thistle",
|
||||
"burlywood",
|
||||
"mediumaquamarine",
|
||||
"mediumorchid",
|
||||
"mediumvioletred",
|
||||
"papayawhip",
|
||||
"moccasin",
|
||||
"bisque",
|
||||
"blanchedalmond",
|
||||
"antiquewhite",
|
||||
"mistyrose",
|
||||
"lavenderblush",
|
||||
"linen",
|
||||
"snow",
|
||||
"honeydew",
|
||||
"palegreen",
|
||||
"lightcyan",
|
||||
"aliceblue",
|
||||
"ghostwhite",
|
||||
"whitesmoke",
|
||||
"gainsboro",
|
||||
]
|
||||
|
||||
latitude = 51.18292980165227
|
||||
longitude = 13.11435805600463
|
||||
gmap = GoogleMapPlotter(
|
||||
latitude, longitude, 8, apikey="AIzaSyAPzFyMk3ZA0kL9TUlJ_kpV_IY56uBwdrc"
|
||||
)
|
||||
|
||||
new_statistics = {}
|
||||
|
||||
f = open(f"data/new_solution_{metric}.csv", "w")
|
||||
|
||||
for group in groups:
|
||||
print(f"GROUP {group}")
|
||||
new_statistics[group] = {
|
||||
"nTeams": 0,
|
||||
"total_distance": 0,
|
||||
"average_distance": 0,
|
||||
"max_distance": 0,
|
||||
"min_distance": 0,
|
||||
"max_team": "",
|
||||
"max_team_distance": 0,
|
||||
"min_team": "",
|
||||
"min_team_distance": 0,
|
||||
}
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
markers_text = []
|
||||
|
||||
color = some_colors.pop(0)
|
||||
|
||||
for team in teams:
|
||||
if value(g[(team["MANNSCHAFT"], group)]) > 0.9:
|
||||
print(f"TEAM {team['MANNSCHAFT']} - {group}")
|
||||
f.write(f"{team['MANNSCHAFT']},{group}\n")
|
||||
|
||||
latitudes.append(team["LATITUDE"])
|
||||
longitudes.append(team["LONGITUDE"])
|
||||
markers_text.append(f"{team['MANNSCHAFT']} @{team['SPIELSTAETTE']}")
|
||||
new_statistics[group]["nTeams"] += 1
|
||||
|
||||
for t1, t2 in x.keys():
|
||||
if t1 == team["MANNSCHAFT"] and value(x[(t1, t2)]) > 0.9:
|
||||
new_statistics[group][
|
||||
"total_distance"
|
||||
] += distance_between_teams[t1][t2]
|
||||
|
||||
new_statistics[group]["average_distance"] = new_statistics[group][
|
||||
"total_distance"
|
||||
] / (max(new_statistics[group]["nTeams"], 1))
|
||||
|
||||
teams_in_group = [
|
||||
team["MANNSCHAFT"]
|
||||
for team in teams
|
||||
if value(g[(team["MANNSCHAFT"], group)]) > 0.9
|
||||
]
|
||||
new_statistics[group]["max_distance"] = max(
|
||||
[
|
||||
distance_between_teams[t1][t2]
|
||||
for t1 in teams_in_group
|
||||
for t2 in teams_in_group
|
||||
],
|
||||
default=0,
|
||||
)
|
||||
new_statistics[group]["min_distance"] = min(
|
||||
[
|
||||
distance_between_teams[t1][t2]
|
||||
for t1 in teams_in_group
|
||||
for t2 in teams_in_group
|
||||
],
|
||||
default=0,
|
||||
)
|
||||
new_statistics[group]["max_team"] = max(
|
||||
teams_in_group,
|
||||
key=lambda x: sum([distance_between_teams[x][t2] for t2 in teams_in_group]),
|
||||
default=0,
|
||||
)
|
||||
new_statistics[group]["max_team_distance"] = sum(
|
||||
[
|
||||
distance_between_teams[new_statistics[group]["max_team"]][t2]
|
||||
for t2 in teams_in_group
|
||||
]
|
||||
)
|
||||
new_statistics[group]["min_team"] = min(
|
||||
teams_in_group,
|
||||
key=lambda x: sum([distance_between_teams[x][t2] for t2 in teams_in_group]),
|
||||
default=0,
|
||||
)
|
||||
new_statistics[group]["min_team_distance"] = sum(
|
||||
[
|
||||
distance_between_teams[new_statistics[group]["min_team"]][t2]
|
||||
for t2 in teams_in_group
|
||||
]
|
||||
)
|
||||
|
||||
# Plot the points on the map
|
||||
gmap.scatter(latitudes, longitudes, color=color, size=40, marker=False)
|
||||
for (lat1, lon1), (lat2, lon2) in itertools.combinations(
|
||||
zip(latitudes, longitudes), 2
|
||||
):
|
||||
gmap.plot([lat1, lat2], [lon1, lon2], color=color, edge_width=2)
|
||||
for lat, lon, text in zip(latitudes, longitudes, markers_text):
|
||||
gmap.marker(lat, lon, title=text.replace('"', ""), color=color)
|
||||
|
||||
f.close()
|
||||
|
||||
gmap.draw(f"map_new_{metric}.html")
|
||||
|
||||
new_statistics["overall"] = {
|
||||
"nGroups": len(
|
||||
[group for group in groups if new_statistics[group]["nTeams"] > 0]
|
||||
),
|
||||
"nTeams": sum([new_statistics[group]["nTeams"] for group in groups]),
|
||||
"total_distance": sum(
|
||||
[new_statistics[group]["total_distance"] for group in groups]
|
||||
),
|
||||
"average_distance": sum(
|
||||
[new_statistics[group]["total_distance"] for group in groups]
|
||||
)
|
||||
/ sum([new_statistics[group]["nTeams"] for group in groups]),
|
||||
"max_distance": max(
|
||||
[new_statistics[group]["max_distance"] for group in groups]
|
||||
),
|
||||
"min_distance": min(
|
||||
[new_statistics[group]["min_distance"] for group in groups]
|
||||
),
|
||||
}
|
||||
new_statistics["overall"]["average_group_distance"] = (
|
||||
new_statistics["overall"]["total_distance"]
|
||||
/ new_statistics["overall"]["nGroups"]
|
||||
)
|
||||
|
||||
new_statistics_str_keys = {str(k): v for k, v in new_statistics.items()}
|
||||
|
||||
with open(f"data/new_stats_{metric}.json", "w", encoding="utf-8") as f:
|
||||
json.dump(new_statistics_str_keys, f, ensure_ascii=False, indent=4, default=str)
|
||||
102
dfbnet/dfbnet.py
Normal file
102
dfbnet/dfbnet.py
Normal file
@ -0,0 +1,102 @@
|
||||
# %%
|
||||
import json
|
||||
from datetime import datetime, time, date
|
||||
from serializers import ProblemSerializer
|
||||
|
||||
|
||||
from competitions import get_teams_from_staffel
|
||||
from schluesselzahlen import get_schluesselzahlen
|
||||
from rahmentermine import get_rahmentermine
|
||||
|
||||
|
||||
PROJECT_PATH = '/home/md/Work/ligalytics/leagues_stable/'
|
||||
import os, sys
|
||||
sys.path.insert(0, PROJECT_PATH)
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "leagues.settings")
|
||||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||
|
||||
""" read json """
|
||||
with open("data/competitions.json", "r", encoding="utf-8") as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
prob = ProblemSerializer(data=competitions)
|
||||
prob.is_valid()
|
||||
|
||||
# %%
|
||||
""" Create pulp model for solving a schedule for a given set of teams and rahmentermine """
|
||||
|
||||
|
||||
rounds1 = list(range(1, len(rahmentermine)//2+1))
|
||||
rounds2 = list(range(len(rahmentermine)//2+1, len(rahmentermine)+1))
|
||||
rounds = rounds1 + rounds2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
from pulp import LpVariable, LpProblem, LpMinimize, lpSum, LpStatus, value, LpInteger, XPRESS
|
||||
|
||||
model = LpProblem("Spielplan", LpMinimize)
|
||||
|
||||
# Create a variable for each team and each rahmentermin
|
||||
x = {}
|
||||
for team, attr in teams.items():
|
||||
for round in rounds:
|
||||
x[(team, round)] = LpVariable(
|
||||
f"team_{attr['MANNSCHAFT']}_{round}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
# Create home variables """
|
||||
home = {}
|
||||
for team, attr in teams.items():
|
||||
for round in rounds:
|
||||
home[(team, round)] = LpVariable(
|
||||
f"home_{attr['MANNSCHAFT']}_{round}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
# Create pattern variables
|
||||
assignPattern = {}
|
||||
for team, attr in teams.items():
|
||||
for p in pattern:
|
||||
assignPattern[(team, p)] = LpVariable(
|
||||
f"pattern_{attr['MANNSCHAFT']}_{p}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
""" Each team exactly one pattern """
|
||||
for team in teams:
|
||||
model += (lpSum(assignPattern[(team, p)] for p in pattern) == 1, f"team_{team}_one_pattern")
|
||||
|
||||
""" Patterns cannot be used more than once """
|
||||
for p in pattern:
|
||||
model += (lpSum(assignPattern[(team, p)] for team in teams) <= 1, f"pattern_{p}_used_once")
|
||||
|
||||
""" Couple patterns with home variables """
|
||||
for round in rounds1:
|
||||
for team, attr in teams.items():
|
||||
model += (lpSum(assignPattern[(team, p)] for p in pattern if pattern[p][round-1] == "H") == home[(team, round)], f"coupling_pattern_home_{attr['MANNSCHAFT']}_{round}")
|
||||
|
||||
# %%
|
||||
model.solve(XPRESS(msg=1))
|
||||
|
||||
|
||||
""" print patterns """
|
||||
for team, attr in teams.items():
|
||||
for p in pattern:
|
||||
if value(assignPattern[(team, p)]) == 1:
|
||||
print(f"{attr['MANNSCHAFT']} is assigned pattern {p}")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
70
dfbnet/dfbnet_tojson.py
Normal file
70
dfbnet/dfbnet_tojson.py
Normal file
@ -0,0 +1,70 @@
|
||||
# %%
|
||||
from datetime import datetime, time, date
|
||||
|
||||
from competitions import get_teams_from_staffel
|
||||
from schluesselzahlen import get_schluesselzahlen
|
||||
from rahmentermine import get_rahmentermine
|
||||
from spielstaetten import get_venues
|
||||
|
||||
# staffel = "Brandible Stadtliga B"
|
||||
# teams = get_teams_from_staffel(staffel)
|
||||
def datetime_serializer(obj):
|
||||
if isinstance(obj, datetime) or isinstance(obj, date) or isinstance(obj, time):
|
||||
return obj.isoformat() # or use obj.strftime("%Y-%m-%d %H:%M:%S")
|
||||
raise TypeError("Type not serializable")
|
||||
|
||||
staffeln_raw, teams = get_teams_from_staffel()
|
||||
|
||||
|
||||
staffeln = []
|
||||
divisions = []
|
||||
court_names = []
|
||||
venues = []
|
||||
|
||||
for s in staffeln_raw:
|
||||
if len(teams[s]) < 4 or len(teams[s]) % 2 == 1:
|
||||
# if len(teams[s]) > 0:
|
||||
# print(s, teams[s][0]['MS_ART'], len(teams[s]))
|
||||
# else:
|
||||
# print(s, "no teams")
|
||||
print("Incompatible", s)
|
||||
continue
|
||||
|
||||
nTeams = len(teams[s])
|
||||
pattern, opponent = get_schluesselzahlen(nTeams)
|
||||
|
||||
ms_art = teams[s][0]['MS_ART']
|
||||
if ms_art in ["A-Junioren","B-Junioren","C-Junioren","D-Junioren","D-Juniorinnen"]:
|
||||
ms_art = "Junioren A-D"
|
||||
elif ms_art in ["Herren Ü50"]:
|
||||
ms_art = "Senioren Ü50"
|
||||
elif ms_art in ["Herren Ü35"]:
|
||||
ms_art = "Senioren Ü35"
|
||||
|
||||
rahmentermine = get_rahmentermine(ms_art, nTeams)
|
||||
|
||||
if not rahmentermine:
|
||||
print("No rahmentermine for", s, ms_art, nTeams)
|
||||
continue
|
||||
divisions.append({
|
||||
"name": s,
|
||||
"teams": teams[s],
|
||||
"nTeams": nTeams,
|
||||
"ms_art": ms_art,
|
||||
"pattern": pattern,
|
||||
"opponent": opponent,
|
||||
"rahmentermine": rahmentermine
|
||||
})
|
||||
# for t in teams[s]:
|
||||
# if not t['SPIELSTAETTE'] in court_names:
|
||||
# courts += [{"name":t['SPIELSTAETTE']}]
|
||||
# court_names += [t['SPIELSTAETTE']]
|
||||
|
||||
venues = get_venues()
|
||||
|
||||
|
||||
""" dump json """
|
||||
import json
|
||||
with open("data/competitions.json", "w", encoding="utf-8") as f:
|
||||
json.dump({'divisions':divisions,'venues':venues}, f, default=datetime_serializer, ensure_ascii=False, indent=4)
|
||||
# %%
|
||||
116
dfbnet/generate_distances.py
Normal file
116
dfbnet/generate_distances.py
Normal file
@ -0,0 +1,116 @@
|
||||
# %%
|
||||
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
|
||||
|
||||
|
||||
from math import sqrt, sin, cos, atan2, pi
|
||||
|
||||
|
||||
|
||||
gmaps = googlemaps.Client(key='AIzaSyB76EhR4OqjdXHQUiTkHZC0Svx_7cPGqyU')
|
||||
|
||||
|
||||
def degreesToRadians(degrees):
|
||||
""" Convert degrees to radians """
|
||||
return degrees * pi / 180
|
||||
|
||||
|
||||
def distanceInKmByGPS(lat1, lon1, lat2, lon2):
|
||||
""" Calculate the distance between two points in km """
|
||||
earthRadiusKm = 6371
|
||||
dLat = degreesToRadians(lat2 - lat1)
|
||||
dLon = degreesToRadians(lon2 - lon1)
|
||||
lat1 = degreesToRadians(lat1)
|
||||
lat2 = degreesToRadians(lat2)
|
||||
a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * \
|
||||
sin(dLon / 2) * cos(lat1) * cos(lat2)
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
return int(earthRadiusKm * c)
|
||||
|
||||
# %%
|
||||
|
||||
with open('data/sachsen.json', 'r', encoding='utf-8') as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
competitions = {ast.literal_eval(k): v for k, v in competitions.items()}
|
||||
|
||||
competition_details = {}
|
||||
color = None
|
||||
|
||||
teams_in_competition = {}
|
||||
|
||||
for staffel ,attr in competitions.items():
|
||||
if (staffel[0],staffel[1]) not in competition_details:
|
||||
competition_details[(staffel[0],staffel[1])] = {
|
||||
'nStaffeln': 1,
|
||||
'nTeams': 0,
|
||||
'distances': {},
|
||||
'teams': []
|
||||
}
|
||||
else:
|
||||
competition_details[(staffel[0],staffel[1])]['nStaffeln'] += 1
|
||||
|
||||
|
||||
|
||||
for team in attr['teams']:
|
||||
if team['MANNSCHAFT'] not in competition_details[(staffel[0],staffel[1])]['teams']:
|
||||
competition_details[(staffel[0],staffel[1])]['teams'].append(team)
|
||||
|
||||
csv_file = 'data/distances.csv'
|
||||
|
||||
|
||||
f = open(csv_file, 'w')
|
||||
f.write('art,klasse,team1,team2,road_distance,road_duration,flight_distance\n')
|
||||
|
||||
|
||||
for competition, details in competition_details.items():
|
||||
print(f"Calculating distances for {competition}")
|
||||
for team1 in details['teams']:
|
||||
details['distances'][team1['MANNSCHAFT']] = {}
|
||||
for team2 in details['teams']:
|
||||
if team1 != team2:
|
||||
start = team1
|
||||
end = team2
|
||||
c = 0
|
||||
while(c <= 1):
|
||||
try:
|
||||
road_distance = gmaps.distance_matrix((start['LATITUDE'],start['LONGITUDE']),(end['LATITUDE'],end['LONGITUDE']))['rows'][0]['elements'][0]['distance']['value']
|
||||
road_duration = gmaps.distance_matrix((start['LATITUDE'],start['LONGITUDE']),(end['LATITUDE'],end['LONGITUDE']))['rows'][0]['elements'][0]['duration']['value']
|
||||
c = 3
|
||||
except:
|
||||
road_distance = 0
|
||||
road_duration = 0
|
||||
print(f"Error with {team1['MANNSCHAFT']} and {team2['MANNSCHAFT']}")
|
||||
time.sleep(3)
|
||||
c += 1
|
||||
road_distance = round(road_distance*0.001)
|
||||
road_duration = round(road_duration*0.016666)
|
||||
|
||||
flight_distance = distanceInKmByGPS(team1['LATITUDE'], team1['LONGITUDE'], team2['LATITUDE'], team2['LONGITUDE'])
|
||||
|
||||
# details['distances'][team1['MANNSCHAFT']][team2['MANNSCHAFT']] = {
|
||||
# 'road_distance': road_distance,
|
||||
# 'road_duration': road_duration,
|
||||
# 'flight_distance': flight_distance
|
||||
# }
|
||||
# print(f"Distance between {team1['MANNSCHAFT']} and {team2['MANNSCHAFT']} calculated", details['distances'][team1['MANNSCHAFT']][team2['MANNSCHAFT']])
|
||||
f.write(f"{competition[0]},{competition[1]},{team1['MANNSCHAFT']},{team2['MANNSCHAFT']},{road_distance},{road_duration},{flight_distance}\n")
|
||||
|
||||
|
||||
f.close()
|
||||
|
||||
# matrix_str_keys = {str(k): v for k, v in competition_details.items()}
|
||||
# with open('data/sachsen_matrix.json', 'w', encoding='utf-8') as f:
|
||||
# json.dump(matrix_str_keys, f, ensure_ascii=False, indent=4, default=str)
|
||||
# %%
|
||||
# %%
|
||||
116
dfbnet/generate_distances_new.py
Normal file
116
dfbnet/generate_distances_new.py
Normal file
@ -0,0 +1,116 @@
|
||||
# %%
|
||||
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
|
||||
|
||||
|
||||
from math import sqrt, sin, cos, atan2, pi
|
||||
|
||||
|
||||
|
||||
gmaps = googlemaps.Client(key='AIzaSyB76EhR4OqjdXHQUiTkHZC0Svx_7cPGqyU')
|
||||
|
||||
|
||||
def degreesToRadians(degrees):
|
||||
""" Convert degrees to radians """
|
||||
return degrees * pi / 180
|
||||
|
||||
|
||||
def distanceInKmByGPS(lat1, lon1, lat2, lon2):
|
||||
""" Calculate the distance between two points in km """
|
||||
earthRadiusKm = 6371
|
||||
dLat = degreesToRadians(lat2 - lat1)
|
||||
dLon = degreesToRadians(lon2 - lon1)
|
||||
lat1 = degreesToRadians(lat1)
|
||||
lat2 = degreesToRadians(lat2)
|
||||
a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * \
|
||||
sin(dLon / 2) * cos(lat1) * cos(lat2)
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
return int(earthRadiusKm * c)
|
||||
|
||||
# %%
|
||||
|
||||
with open('data/sachsen.json', 'r', encoding='utf-8') as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
competitions = {ast.literal_eval(k): v for k, v in competitions.items()}
|
||||
|
||||
competition_details = {}
|
||||
color = None
|
||||
|
||||
teams_in_competition = {}
|
||||
|
||||
for staffel ,attr in competitions.items():
|
||||
if (staffel[0],staffel[1]) not in competition_details:
|
||||
competition_details[(staffel[0],staffel[1])] = {
|
||||
'nStaffeln': 1,
|
||||
'nTeams': 0,
|
||||
'distances': {},
|
||||
'teams': []
|
||||
}
|
||||
else:
|
||||
competition_details[(staffel[0],staffel[1])]['nStaffeln'] += 1
|
||||
|
||||
|
||||
|
||||
for team in attr['teams']:
|
||||
if team['MANNSCHAFT'] not in competition_details[(staffel[0],staffel[1])]['teams']:
|
||||
competition_details[(staffel[0],staffel[1])]['teams'].append(team)
|
||||
|
||||
csv_file = 'data/distances_2.csv'
|
||||
|
||||
|
||||
f = open(csv_file, 'w')
|
||||
f.write('art,klasse,team1,team2,road_distance,road_duration,flight_distance\n')
|
||||
|
||||
|
||||
for competition, details in sorted(competition_details.items(), key=lambda x:x[0], reverse=True):
|
||||
print(f"Calculating distances for {competition}")
|
||||
for team1 in details['teams']:
|
||||
details['distances'][team1['MANNSCHAFT']] = {}
|
||||
for team2 in details['teams']:
|
||||
if team1 != team2:
|
||||
start = team1
|
||||
end = team2
|
||||
c = 0
|
||||
while(c <= 1):
|
||||
try:
|
||||
road_distance = gmaps.distance_matrix((start['LATITUDE'],start['LONGITUDE']),(end['LATITUDE'],end['LONGITUDE']))['rows'][0]['elements'][0]['distance']['value']
|
||||
road_duration = gmaps.distance_matrix((start['LATITUDE'],start['LONGITUDE']),(end['LATITUDE'],end['LONGITUDE']))['rows'][0]['elements'][0]['duration']['value']
|
||||
c = 3
|
||||
except:
|
||||
road_distance = 0
|
||||
road_duration = 0
|
||||
print(f"Error with {team1['MANNSCHAFT']} and {team2['MANNSCHAFT']}")
|
||||
time.sleep(3)
|
||||
c += 1
|
||||
road_distance = round(road_distance*0.001)
|
||||
road_duration = round(road_duration*0.016666)
|
||||
|
||||
flight_distance = distanceInKmByGPS(team1['LATITUDE'], team1['LONGITUDE'], team2['LATITUDE'], team2['LONGITUDE'])
|
||||
|
||||
# details['distances'][team1['MANNSCHAFT']][team2['MANNSCHAFT']] = {
|
||||
# 'road_distance': road_distance,
|
||||
# 'road_duration': road_duration,
|
||||
# 'flight_distance': flight_distance
|
||||
# }
|
||||
# print(f"Distance between {team1['MANNSCHAFT']} and {team2['MANNSCHAFT']} calculated", details['distances'][team1['MANNSCHAFT']][team2['MANNSCHAFT']])
|
||||
f.write(f"{competition[0]},{competition[1]},{team1['MANNSCHAFT']},{team2['MANNSCHAFT']},{road_distance},{road_duration},{flight_distance}\n")
|
||||
|
||||
|
||||
f.close()
|
||||
|
||||
# matrix_str_keys = {str(k): v for k, v in competition_details.items()}
|
||||
# with open('data/sachsen_matrix.json', 'w', encoding='utf-8') as f:
|
||||
# json.dump(matrix_str_keys, f, ensure_ascii=False, indent=4, default=str)
|
||||
# %%
|
||||
# %%
|
||||
665
dfbnet/kmeans_sachsen.py
Normal file
665
dfbnet/kmeans_sachsen.py
Normal file
@ -0,0 +1,665 @@
|
||||
# %%
|
||||
|
||||
from pulp import (
|
||||
LpVariable,
|
||||
LpProblem,
|
||||
LpMinimize,
|
||||
lpSum,
|
||||
LpStatus,
|
||||
value,
|
||||
LpInteger,
|
||||
LpContinuous,
|
||||
XPRESS,
|
||||
)
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
import os
|
||||
|
||||
from scipy.cluster.vq import kmeans, vq
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
os.environ["XPRESSDIR"] = "/opt/xpressmp_9.5.0"
|
||||
os.environ["XPRESS"] = "/opt/xpressmp_9.5.0/bin"
|
||||
os.environ["LD_LIBRARY_PATH"] = os.environ["XPRESSDIR"] + "/lib"
|
||||
os.environ["DYLD_LIBRARY_PATH"] = os.environ["XPRESSDIR"] + "/lib"
|
||||
os.environ["SHLIB_PATH"] = os.environ["XPRESSDIR"] + "/lib"
|
||||
os.environ["LIBPATH"] = os.environ["XPRESSDIR"] + "/lib"
|
||||
os.environ["PYTHONPATH"] = os.environ["XPRESSDIR"] + "/lib"
|
||||
os.environ["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprs.jar"
|
||||
os.environ["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprb.jar" + os.pathsep + os.environ["CLASSPATH"]
|
||||
os.environ["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprm.jar" + os.pathsep + os.environ["CLASSPATH"]
|
||||
os.environ["PATH"] = os.environ["XPRESSDIR"] + "/bin" + os.pathsep + os.environ["PATH"]
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
from math import sqrt, sin, cos, atan2, pi
|
||||
|
||||
|
||||
def degreesToRadians(degrees):
|
||||
"""Convert degrees to radians"""
|
||||
return degrees * pi / 180
|
||||
|
||||
|
||||
def distanceInKmByGPS(lat1, lon1, lat2, lon2):
|
||||
"""Calculate the distance between two points in km"""
|
||||
earthRadiusKm = 6371
|
||||
dLat = degreesToRadians(lat2 - lat1)
|
||||
dLon = degreesToRadians(lon2 - lon1)
|
||||
lat1 = degreesToRadians(lat1)
|
||||
lat2 = degreesToRadians(lat2)
|
||||
a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(lat1) * cos(
|
||||
lat2
|
||||
)
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
return int(earthRadiusKm * c)
|
||||
|
||||
|
||||
def random_color():
|
||||
return "#{:06x}".format(random.randint(0, 0xFFFFFF))
|
||||
|
||||
# %%
|
||||
|
||||
with open("data/sachsen.json", "r", encoding="utf-8") as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
competitions = {ast.literal_eval(k): v for k, v in competitions.items()}
|
||||
|
||||
# %%
|
||||
|
||||
# region
|
||||
# STAFFELN PRO ART UND KLASSE
|
||||
# ('Herren', 'Landesliga') 1
|
||||
# ('Herren', 'Landesklasse') 3
|
||||
# ('Frauen', 'Landesliga') 1
|
||||
# ('Frauen', 'Landesklasse') 3
|
||||
# ('A-Junioren', 'Landesliga') 1
|
||||
# ('A-Junioren', 'Landesklasse') 4
|
||||
# ('Herren', 'Kreisoberliga') 13
|
||||
# ('Herren', '1.Kreisliga (A)') 19
|
||||
# ('Herren', '2.Kreisliga (B)') 8
|
||||
# ('Herren', '3.Kreisliga (C)') 1
|
||||
# ('Herren', '1.Kreisklasse') 21
|
||||
# ('Herren', '2.Kreisklasse') 9
|
||||
# ('A-Junioren', 'Kreisoberliga') 10
|
||||
# ('A-Junioren', '1.Kreisliga (A)') 6
|
||||
# ('Frauen', 'Kreisoberliga') 4
|
||||
# ('Frauen', '1.Kreisliga (A)') 1
|
||||
# ('Frauen', '1.Kreisklasse') 3
|
||||
# ('B-Junioren', 'Landesliga') 1
|
||||
# ('B-Junioren', 'Landesklasse') 4
|
||||
# ('B-Junioren', 'Kreisoberliga') 13
|
||||
# ('B-Junioren', '1.Kreisliga (A)') 13
|
||||
# ('B-Junioren', '1.Kreisklasse') 1
|
||||
# ('C-Junioren', 'Landesliga') 1
|
||||
# ('C-Junioren', 'Landesklasse') 4
|
||||
# ('C-Junioren', 'Kreisoberliga') 16
|
||||
# ('C-Junioren', '1.Kreisliga (A)') 15
|
||||
# ('C-Junioren', '1.Kreisklasse') 9
|
||||
# ('D-Junioren', 'Landesliga') 1
|
||||
# ('D-Junioren', 'Landesklasse') 6
|
||||
# ('D-Junioren', 'Kreisoberliga') 16
|
||||
# ('D-Junioren', '1.Kreisliga (A)') 24
|
||||
# ('D-Junioren', '2.Kreisliga (B)') 8
|
||||
# ('D-Junioren', '3.Kreisliga (C)') 2
|
||||
# ('D-Junioren', '1.Kreisklasse') 33
|
||||
# ('D-Junioren', '2.Kreisklasse') 10
|
||||
# ('B-Juniorinnen', 'Landesliga') 1
|
||||
# ('B-Juniorinnen', 'Landesklasse') 2
|
||||
# ('C-Juniorinnen', 'Landesklasse') 3
|
||||
# ('D-Juniorinnen', 'Kreisoberliga') 1
|
||||
# ('Herren Ü35', 'Kreisoberliga') 4
|
||||
# ('Herren Ü35', '1.Kreisliga (A)') 3
|
||||
# ('Herren Ü35', '1.Kreisklasse') 3
|
||||
# ('Herren Ü35', '2.Kreisklasse') 1
|
||||
# ('Herren Ü40', '1.Kreisliga (A)') 5
|
||||
# ('Herren Ü40', '1.Kreisklasse') 1
|
||||
# ('Herren Ü50', '1.Kreisliga (A)') 1
|
||||
# ('Herren Ü50', '1.Kreisklasse') 1
|
||||
# ('Freizeitsport', '1.Kreisliga (A)') 3
|
||||
# ('Freizeitsport', '1.Kreisklasse') 2
|
||||
# endregion
|
||||
|
||||
competition_details = {}
|
||||
color = None
|
||||
for staffel, attr in competitions.items():
|
||||
# if (staffel[0], staffel[1]) != ('Herren', 'Kreisoberliga'):
|
||||
# continue
|
||||
competitions[staffel]["distance"] = []
|
||||
|
||||
if (staffel[0], staffel[1]) not in competition_details:
|
||||
competition_details[(staffel[0], staffel[1])] = {
|
||||
"nStaffeln": 1,
|
||||
"nTeams": len(attr["teams"]),
|
||||
"teams": attr["teams"],
|
||||
"group_sizes": [len(attr["teams"])],
|
||||
"clusters": {},
|
||||
}
|
||||
else:
|
||||
competition_details[(staffel[0], staffel[1])]["nStaffeln"] += 1
|
||||
competition_details[(staffel[0], staffel[1])]["group_sizes"].append(len(attr["teams"]))
|
||||
competition_details[(staffel[0], staffel[1])]["nTeams"] += len(attr["teams"])
|
||||
competition_details[(staffel[0], staffel[1])]["teams"] += attr["teams"]
|
||||
|
||||
|
||||
"""" GENERATE ALL DISTANCES BETWEEN TEAMS """
|
||||
|
||||
distance_between_teams = {}
|
||||
for competition, details in competition_details.items():
|
||||
|
||||
# competition = ('Herren', 'Kreisoberliga')
|
||||
# details = competition_details[competition]
|
||||
|
||||
|
||||
print(f"Calculating distances for {competition}")
|
||||
for id, team1 in enumerate(details["teams"]):
|
||||
team1['ID'] = id
|
||||
distance_between_teams[team1["MANNSCHAFT"]] = {}
|
||||
for team2 in details["teams"]:
|
||||
distance = 0
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
distance = distanceInKmByGPS(
|
||||
team1["LATITUDE"],
|
||||
team1["LONGITUDE"],
|
||||
team2["LATITUDE"],
|
||||
team2["LONGITUDE"],
|
||||
)
|
||||
distance_between_teams[team1["MANNSCHAFT"]][
|
||||
team2["MANNSCHAFT"]
|
||||
] = distance
|
||||
|
||||
teams = details["teams"]
|
||||
# print("Number of teams", len(teams))
|
||||
|
||||
|
||||
locations = []
|
||||
for team in teams:
|
||||
locations.append([team["LATITUDE"], team["LONGITUDE"]])
|
||||
|
||||
data = np.array(locations)
|
||||
|
||||
k = details['nStaffeln']
|
||||
|
||||
# print("Number of groups", k)
|
||||
|
||||
centroids, _ = kmeans(data, k)
|
||||
cluster_labels, _ = vq(data, centroids)
|
||||
|
||||
# print("Initial centroids", len(centroids), centroids)
|
||||
for diff in range(len(centroids), k):
|
||||
centroids = np.append(centroids, [[0, 0]], axis=0)
|
||||
|
||||
|
||||
|
||||
"""" RECLUSTERING THE COMPETITION INTO DIVISIONS """
|
||||
improvement = True
|
||||
it = 0
|
||||
last_objective = False
|
||||
while(improvement):
|
||||
it += 1
|
||||
print("Iteration", it)
|
||||
|
||||
model = LpProblem(f"KMeans_{it}", LpMinimize)
|
||||
|
||||
""" x = 1 if team i is in same division as j, 0 otherwise """
|
||||
x = {}
|
||||
|
||||
""" g = 1 if team i is i group j, 0 otherwise """
|
||||
groups = range(1, k+1)
|
||||
|
||||
|
||||
g = {}
|
||||
for team in teams:
|
||||
for group in groups:
|
||||
g[(team["MANNSCHAFT"], group)] = LpVariable(
|
||||
f"team_{team['ID']}_{group}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
""" Each team is in exactly one division """
|
||||
for team in teams:
|
||||
model += lpSum(g[(team["MANNSCHAFT"], group)] for group in groups) == 1
|
||||
|
||||
for group, group_size in enumerate(details["group_sizes"]):
|
||||
# print(group+1, group_size)
|
||||
model += lpSum(g[(team["MANNSCHAFT"], group+1)] for team in teams) == group_size
|
||||
|
||||
""" MINIMIZE THE DISTANCE TO THE CLUSTER CENTROID """
|
||||
model += lpSum(g[team["MANNSCHAFT"], group] * distanceInKmByGPS(
|
||||
team["LATITUDE"],
|
||||
team["LONGITUDE"],
|
||||
centroids[group - 1][0],
|
||||
centroids[group - 1][1],
|
||||
) for team in teams for group in groups
|
||||
)
|
||||
|
||||
""" write the model to a file """
|
||||
# model.writeLP(f"kmeans/kmeans_{competition}_{it}.lp")
|
||||
|
||||
model.solve(XPRESS(msg=0, gapRel=0.01))
|
||||
|
||||
if last_objective:
|
||||
if last_objective <= value(model.objective):
|
||||
improvement = False
|
||||
last_objective = value(model.objective)
|
||||
|
||||
|
||||
""" recompute the centroids """
|
||||
centroids = []
|
||||
for group in groups:
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
for team in teams:
|
||||
if value(g[(team["MANNSCHAFT"], group)]) > 0.9:
|
||||
latitudes.append(team["LATITUDE"])
|
||||
longitudes.append(team["LONGITUDE"])
|
||||
centroids.append([np.mean(latitudes), np.mean(longitudes)])
|
||||
|
||||
|
||||
clusters = {k: [] for k in range(1, len(groups)+1)}
|
||||
augmented_teams = []
|
||||
for group in groups:
|
||||
for team in teams:
|
||||
if value(g[(team["MANNSCHAFT"], group)]) > 0.9:
|
||||
clusters[group].append(team)
|
||||
|
||||
competition_details[competition]["clusters"] = clusters
|
||||
|
||||
some_colors = [
|
||||
"red",
|
||||
"blue",
|
||||
"green",
|
||||
"yellow",
|
||||
"purple",
|
||||
"orange",
|
||||
"pink",
|
||||
"brown",
|
||||
"black",
|
||||
"white",
|
||||
"gray",
|
||||
"cyan",
|
||||
"magenta",
|
||||
"lime",
|
||||
"indigo",
|
||||
"violet",
|
||||
"turquoise",
|
||||
"gold",
|
||||
"silver",
|
||||
"beige",
|
||||
"maroon",
|
||||
"olive",
|
||||
"navy",
|
||||
"teal",
|
||||
"coral",
|
||||
"lavender",
|
||||
"salmon",
|
||||
"chocolate",
|
||||
"crimson",
|
||||
"aqua",
|
||||
"ivory",
|
||||
"khaki",
|
||||
"plum",
|
||||
"orchid",
|
||||
"peru",
|
||||
"tan",
|
||||
"tomato",
|
||||
"wheat",
|
||||
"azure",
|
||||
"mint",
|
||||
"apricot",
|
||||
"chartreuse",
|
||||
"amber",
|
||||
"fuchsia",
|
||||
"jade",
|
||||
"ruby",
|
||||
"amethyst",
|
||||
"rose",
|
||||
"sapphire",
|
||||
"cerulean",
|
||||
"moss",
|
||||
"denim",
|
||||
"copper",
|
||||
"peach",
|
||||
"sand",
|
||||
"pearl",
|
||||
"mulberry",
|
||||
"lemon",
|
||||
"cream",
|
||||
"ocher",
|
||||
"brass",
|
||||
"eggplant",
|
||||
"cinnamon",
|
||||
"mustard",
|
||||
"rust",
|
||||
"sienna",
|
||||
"sepia",
|
||||
"umber",
|
||||
"limegreen",
|
||||
"seagreen",
|
||||
"forestgreen",
|
||||
"dodgerblue",
|
||||
"mediumslateblue",
|
||||
"royalblue",
|
||||
"firebrick",
|
||||
"darkolivegreen",
|
||||
"midnightblue",
|
||||
"darkturquoise",
|
||||
"lightcoral",
|
||||
"palevioletred",
|
||||
"hotpink",
|
||||
"deeppink",
|
||||
"darkkhaki",
|
||||
"lightseagreen",
|
||||
"darkslategray",
|
||||
"slategray",
|
||||
"lightsteelblue",
|
||||
"skyblue",
|
||||
"lightblue",
|
||||
"powderblue",
|
||||
"darkorange",
|
||||
"lightsalmon",
|
||||
"indianred",
|
||||
"thistle",
|
||||
"burlywood",
|
||||
"mediumaquamarine",
|
||||
"mediumorchid",
|
||||
"mediumvioletred",
|
||||
"papayawhip",
|
||||
"moccasin",
|
||||
"bisque",
|
||||
"blanchedalmond",
|
||||
"antiquewhite",
|
||||
"mistyrose",
|
||||
"lavenderblush",
|
||||
"linen",
|
||||
"snow",
|
||||
"honeydew",
|
||||
"palegreen",
|
||||
"lightcyan",
|
||||
"aliceblue",
|
||||
"ghostwhite",
|
||||
"whitesmoke",
|
||||
"gainsboro",
|
||||
]
|
||||
|
||||
latitude = 51.18292980165227
|
||||
longitude = 13.11435805600463
|
||||
gmap = GoogleMapPlotter(
|
||||
latitude, longitude, 8, apikey="AIzaSyAPzFyMk3ZA0kL9TUlJ_kpV_IY56uBwdrc"
|
||||
)
|
||||
|
||||
aggregated_distance = 0
|
||||
distance_for_team = {}
|
||||
for cluster, teamslist in clusters.items():
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
markers_text = []
|
||||
color = some_colors.pop(0)
|
||||
cluster_distance = 0
|
||||
for team1 in teamslist:
|
||||
distance_for_team[team1["MANNSCHAFT"]] = []
|
||||
for team2 in teamslist:
|
||||
distance = 0
|
||||
if team1["MANNSCHAFT"] != team2["MANNSCHAFT"]:
|
||||
distance = distance_between_teams[team1["MANNSCHAFT"]][team2["MANNSCHAFT"]]
|
||||
cluster_distance += distance
|
||||
aggregated_distance += distance
|
||||
distance_for_team[team1["MANNSCHAFT"]].append(distance)
|
||||
latitudes.append(team1["LATITUDE"])
|
||||
longitudes.append(team1["LONGITUDE"])
|
||||
markers_text.append(f"{team1['MANNSCHAFT']} @{team1['SPIELSTAETTE']}")
|
||||
|
||||
# Plot the points on the map
|
||||
gmap.scatter(latitudes, longitudes, color=color, size=40, marker=False)
|
||||
for (lat1, lon1), (lat2, lon2) in itertools.combinations(
|
||||
zip(latitudes, longitudes), 2
|
||||
):
|
||||
gmap.plot([lat1, lat2], [lon1, lon2], color=color, edge_width=2)
|
||||
for lat, lon, text in zip(latitudes, longitudes, markers_text):
|
||||
gmap.marker(lat, lon, title=text.replace('"', ""), color=color)
|
||||
|
||||
print(cluster, len(teamslist), cluster_distance, aggregated_distance, color)
|
||||
|
||||
gmap.draw(f"kmeans/map_mip_{competition}.html")
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
""" DUMP THE COMPETITIONS """
|
||||
from datetime import datetime, time, date
|
||||
|
||||
# from competitions import get_teams_from_staffel
|
||||
from schluesselzahlen import get_schluesselzahlen
|
||||
from rahmentermine import get_rahmentermine
|
||||
from spielstaetten import get_venues
|
||||
|
||||
# staffel = "Brandible Stadtliga B"
|
||||
# teams = get_teams_from_staffel(staffel)
|
||||
def datetime_serializer(obj):
|
||||
if isinstance(obj, datetime) or isinstance(obj, date) or isinstance(obj, time):
|
||||
return obj.isoformat() # or use obj.strftime("%Y-%m-%d %H:%M:%S")
|
||||
raise TypeError("Type not serializable")
|
||||
|
||||
|
||||
|
||||
staffeln = []
|
||||
divisions = []
|
||||
courts = []
|
||||
court_names = []
|
||||
venues = []
|
||||
|
||||
for competition, details in competition_details.items():
|
||||
|
||||
for cluster, cluster_teams in details['clusters'].items():
|
||||
print(f"Processing {competition} {cluster}")
|
||||
nTeams = len(cluster_teams) + len(cluster_teams) % 2
|
||||
pattern, opponent = get_schluesselzahlen(nTeams)
|
||||
|
||||
teams = cluster_teams
|
||||
|
||||
ms_art = teams[0]['MS_ART']
|
||||
if ms_art in ["A-Junioren","B-Junioren","C-Junioren","D-Junioren","D-Juniorinnen"]:
|
||||
ms_art = "Junioren A-D"
|
||||
elif ms_art in ["Herren Ü50"]:
|
||||
ms_art = "Senioren Ü50"
|
||||
elif ms_art in ["Herren Ü35"]:
|
||||
ms_art = "Senioren Ü35"
|
||||
|
||||
rahmentermine = get_rahmentermine(ms_art, nTeams)
|
||||
|
||||
if not rahmentermine:
|
||||
print("No rahmentermine for", competition, cluster, ms_art, nTeams)
|
||||
continue
|
||||
divisions.append({
|
||||
"name": f"{competition[0]} {competition[1]} {cluster}",
|
||||
"teams": teams,
|
||||
"nTeams": nTeams,
|
||||
"ms_art": ms_art,
|
||||
"pattern": pattern,
|
||||
"opponent": opponent,
|
||||
"rahmentermine": rahmentermine
|
||||
})
|
||||
for t in teams:
|
||||
if not t['SPIELSTAETTE'] in court_names:
|
||||
# courts += [{"name":t['SPIELSTAETTE']}]
|
||||
|
||||
venues.append({
|
||||
"SB_SPST_ID": len(venues)+1,
|
||||
"SB_SPST_GEBIET_REF": len(venues)+1,
|
||||
"SB_SPST_NAME": t['SPIELSTAETTE'],
|
||||
"SB_SPST_TYP_REF": 1,
|
||||
"SB_SPST_ZUSTAND_REF": 1,
|
||||
"SB_SPST_PLATZ_NR": "(null)",
|
||||
"SB_SPST_FLUTLICHT": "t",
|
||||
"SB_SPST_SPIELE_PARALLEL_MAX": 3,
|
||||
"SB_SPST_ANSTOSSZEIT_VON": "08:30:00",
|
||||
"SB_SPST_ANSTOSSZEIT_BIS": "20:30:00",
|
||||
"SB_SPST_ANZ_UMKLEIDEN": 5,
|
||||
"SB_SPST_MITTAGSPAUSE_VON": "(null)",
|
||||
"SB_SPST_MITTAGSPAUSE_BIS": "(null)",
|
||||
"SB_SPST_GROESSE_REF": 1,
|
||||
"SB_SPST_SPIELE_TAG_MAX": 20,
|
||||
"SB_SPST_ANZ_TORE": 6,
|
||||
"SB_SPST_SPIELE_ABSTAND": 0,
|
||||
"latitude": t["LATITUDE"],
|
||||
"longitude": t["LONGITUDE"],
|
||||
})
|
||||
|
||||
court_names += [t['SPIELSTAETTE']]
|
||||
|
||||
|
||||
|
||||
""" dump json """
|
||||
import json
|
||||
with open("kmeans/competitions.json", "w", encoding="utf-8") as f:
|
||||
json.dump({'divisions':divisions,'venues':venues}, f, default=datetime_serializer, ensure_ascii=False, indent=4)
|
||||
|
||||
|
||||
|
||||
|
||||
# # %%
|
||||
|
||||
# %%
|
||||
with open("kmeans/competitions.json", "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
|
||||
from pulp import LpVariable, LpProblem, LpMinimize, lpSum, LpStatus, value, LpInteger, XPRESS
|
||||
model = LpProblem("Spielplan", LpMinimize)
|
||||
x = {}
|
||||
home = {}
|
||||
assignPattern = {}
|
||||
|
||||
|
||||
divisions = data['divisions']
|
||||
venues = data['venues']
|
||||
max_rounds = 0
|
||||
|
||||
team_id = 0
|
||||
|
||||
for division_id, division in enumerate(divisions):
|
||||
division['id'] = division_id
|
||||
|
||||
rahmentermine = division['rahmentermine']
|
||||
teams = division['teams']
|
||||
pattern = division['pattern']
|
||||
opponent = division['opponent']
|
||||
nTeams = division['nTeams']
|
||||
ms_art = division['ms_art']
|
||||
|
||||
for t in teams:
|
||||
t['id'] = team_id
|
||||
team_id += 1
|
||||
|
||||
|
||||
# %%
|
||||
""" Create pulp model for solving a schedule for a given set of teams and rahmentermine """
|
||||
|
||||
|
||||
rounds1 = list(range(1, len(rahmentermine)//2+1))
|
||||
rounds2 = list(range(len(rahmentermine)//2+1, len(rahmentermine)+1))
|
||||
rounds = rounds1 + rounds2
|
||||
max_rounds = max(max_rounds, len(rounds1))
|
||||
|
||||
# %%
|
||||
|
||||
# Create a variable for each team and each rahmentermin
|
||||
for team in teams:
|
||||
for round in rounds:
|
||||
x[(team['id'], round)] = LpVariable(
|
||||
f"team_{team['id']}_{round}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
# Create home variables """
|
||||
for team in teams:
|
||||
for round in rounds:
|
||||
home[(team['id'], round)] = LpVariable(
|
||||
f"home_{team['id']}_{round}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
# Create pattern variables
|
||||
for team in teams:
|
||||
for p in pattern:
|
||||
assignPattern[(team['id'], p)] = LpVariable(
|
||||
f"pattern_{team['id']}_{p}",
|
||||
lowBound=0,
|
||||
upBound=1,
|
||||
cat=LpInteger,
|
||||
)
|
||||
|
||||
""" Each team exactly one pattern """
|
||||
for team in teams:
|
||||
model += (lpSum(assignPattern[(team['id'], p)] for p in pattern) == 1, f"team_{team['id']}_one_pattern")
|
||||
|
||||
# if team['SPIELSTAETTE'].strip() not in [venue['SB_SPST_NAME'] for venue in venues]:
|
||||
# print(f"Venue {team['SPIELSTAETTE']} not found in venues")
|
||||
# exit()
|
||||
# else:
|
||||
# print(f"Venue {team['SPIELSTAETTE']} found in venues")
|
||||
|
||||
""" Patterns cannot be used more than once """
|
||||
for p in pattern:
|
||||
model += (lpSum(assignPattern[(team['id'], p)] for team in teams) <= 1, f"pattern_{p}_used_once_in_division_{division['id']}")
|
||||
|
||||
""" Couple patterns with home variables """
|
||||
for round in rounds1:
|
||||
for team in teams:
|
||||
model += (lpSum(assignPattern[(team['id'], p)] for p in pattern if pattern[p][round-1] == "H") == home[(team['id'], round)], f"coupling_pattern_home_{team['id']}_{round}")
|
||||
|
||||
|
||||
|
||||
model.solve(XPRESS(msg=1))
|
||||
|
||||
|
||||
|
||||
csv_file = open("kmeans/schedule.csv", "w")
|
||||
csv_file.write("round,venue,day,division,hometeam,awayteam,homepattern,awaypattern,wunschtag,wunschzeit\n")
|
||||
""" print patterns """
|
||||
for round in range(1,max_rounds+1):
|
||||
for venue in venues:
|
||||
print(f"Round {round} at {venue['SB_SPST_NAME']}")
|
||||
for division in divisions:
|
||||
if division['nTeams'] <= round:
|
||||
continue
|
||||
for team in division['teams']:
|
||||
|
||||
|
||||
if team['SPIELSTAETTE'] == venue['SB_SPST_NAME']:
|
||||
if value(home.get((team['id'], round),0)) == 1:
|
||||
p1 = [p for p in division['pattern'] if assignPattern[(team['id'], p)].varValue == 1][0]
|
||||
p2 = 0
|
||||
o = None
|
||||
for t2 in division['teams']:
|
||||
p2 = [p for p in division['pattern'] if assignPattern[(t2['id'], p)].varValue == 1][0]
|
||||
# print(round,division['nTeams'])
|
||||
if int(p2) == int(division['opponent'][p1][round-1]):
|
||||
o = t2['MANNSCHAFT']
|
||||
break
|
||||
# print(f"{round} ({team['SPIELSTAETTE']}, {venue['SB_SPST_SPIELE_TAG_MAX']}): {division['name']} - {team['MANNSCHAFT']} - {p1} - {team['WUNSCH_TAG']} - {team['WUNSCH_ZEIT']} vs {o} - {p2}")
|
||||
if o:
|
||||
csv_file.write(f"{round},{team['SPIELSTAETTE'].replace(","," ")},{venue['SB_SPST_SPIELE_TAG_MAX']},{division['name']},{team['MANNSCHAFT']},{o},{p1},{p2},{team['WUNSCH_TAG']},{team['WUNSCH_ZEIT']}\n")
|
||||
csv_file.close()
|
||||
|
||||
|
||||
|
||||
48
dfbnet/rahmentermine.py
Normal file
48
dfbnet/rahmentermine.py
Normal file
@ -0,0 +1,48 @@
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def get_rahmentermine(MS_ART, nTeams):
|
||||
|
||||
""" LOAD RAHMENTERMINPLAN FROM CSV"""
|
||||
rahmentermine = pd.read_csv("data/rahmentermine.csv")
|
||||
cols = list(rahmentermine.columns)
|
||||
|
||||
# %%
|
||||
|
||||
rahmentermine['From'] = pd.to_datetime(rahmentermine['From'], format='%d/%m').dt.date
|
||||
rahmentermine['From'] = rahmentermine['From'].apply(lambda x: x.replace(year=2025) if x.month < 7 else x.replace(year=2024))
|
||||
rahmentermine['To'] = pd.to_datetime(rahmentermine['To'], format='%d/%m').dt.date
|
||||
rahmentermine['To'] = rahmentermine['To'].apply(lambda x: x.replace(year=2025) if x.month < 7 else x.replace(year=2024))
|
||||
|
||||
# %%
|
||||
|
||||
""" REMOVE ALL ENTRIES THAT ARE NO REAL MATCHDAYS"""
|
||||
for col in cols:
|
||||
if col in ['From', 'To']:
|
||||
continue
|
||||
rahmentermine[col] = pd.to_numeric(rahmentermine[col], errors='coerce')
|
||||
rahmentermine[col] = rahmentermine[col].apply(lambda x: int(x) if pd.notna(x) and x == int(x) else '')
|
||||
|
||||
# %%
|
||||
|
||||
""" CREATE DICTIONARY WITH MATCHDAYS"""
|
||||
termine = {}
|
||||
for col in cols:
|
||||
colname = col.split('.')[0]
|
||||
if col in ['From', 'To']:
|
||||
continue
|
||||
if rahmentermine[col][0] != nTeams:
|
||||
continue
|
||||
termine[(colname,nTeams)] = {}
|
||||
|
||||
for row in rahmentermine.iterrows():
|
||||
if row[0] == 0:
|
||||
continue
|
||||
if row[1][col] != "":
|
||||
termine[(colname,nTeams)][row[1][col]] = [row[1]['From'], row[1]['To']]
|
||||
|
||||
return termine.get((MS_ART,nTeams), [])
|
||||
|
||||
|
||||
|
||||
|
||||
136
dfbnet/schluesselzahlen.py
Normal file
136
dfbnet/schluesselzahlen.py
Normal file
@ -0,0 +1,136 @@
|
||||
rahmenplan = {}
|
||||
|
||||
rahmenplan[4] = [
|
||||
[(1,3),(1,2),(2,3)],
|
||||
[(4,2),(3,4),(4,1)],
|
||||
]
|
||||
|
||||
|
||||
rahmenplan[6] = [
|
||||
[(1,5), (2,6), (1,3), (1,2), (2,5)],
|
||||
[(3,2), (4,1), (4,2), (3,6), (4,3)],
|
||||
[(6,4), (5,3), (6,5), (5,4), (6,1)],
|
||||
]
|
||||
|
||||
rahmenplan[8] = [
|
||||
[(1,7), (2,3), (1,5), (2,6), (1,3), (1,2), (2,7)],
|
||||
[(3,4), (4,8), (3,7), (4,1), (4,2), (3,8), (4,5)],
|
||||
[(5,2), (6,1), (6,4), (5,3), (6,7), (5,6), (6,3)],
|
||||
[(8,6), (7,5), (8,2), (7,8), (8,5), (7,4), (8,1)],
|
||||
]
|
||||
|
||||
rahmenplan[10] = [
|
||||
[(1,9), (2,5), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,9)],
|
||||
[(3,6), (4,3), (3,2), (4,8), (3,7), (4,1), (4,2), (3,10), (4,7)],
|
||||
[(5,4), (6,10), (5,9), (6,1), (6,4), (5,3), (6,9), (5,8), (6,5)],
|
||||
[(7,2), (8,1), (8,6), (7,5), (8,2), (7,10), (8,7), (7,6), (8,3)],
|
||||
[(10,8), (9,7), (10,4), (9,3), (10,9), (9,8), (10,5), (9,4), (10,1)],
|
||||
]
|
||||
|
||||
rahmenplan[12] = [
|
||||
[(1,11), (2,7), (1,9), (2,3), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,11)],
|
||||
[(3,8), (4,5), (3,4), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,12), (4,9)],
|
||||
[(5,6), (6,3), (5,2), (6,10), (5,9), (6,1), (6,4), (5,3), (6,11), (5,10), (6,7)],
|
||||
[(7,4), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,12), (8,9), (7,8), (8,5)],
|
||||
[(9,2), (10,1), (10,8), (9,7), (10,4), (9,3), (10,11), (9,10), (10,7), (9,6), (10,3)],
|
||||
[(12,10), (11,9), (12,6), (11,5), (12,2), (11,12), (12,9), (11,8), (12,5), (11,4), (12,1)],
|
||||
]
|
||||
|
||||
rahmenplan[14] = [
|
||||
[(1,13), (2,9), (1,11), (2,5), (1,9), (2,14), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,13)],
|
||||
[(3,10), (4,7), (3,6), (4,3), (3,2), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,14), (4,11)],
|
||||
[(5,8), (6,5), (5,4), (6,14), (5,13), (6,10), (5,9), (6,1), (6,4), (5,3), (6,13), (5,12), (6,9)],
|
||||
[(7,6), (8,3), (7,2), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,14), (8,11), (7,10), (8,7)],
|
||||
[(9,4), (10,14), (9,13), (10,1), (10,8), (9,7), (10,4), (9,3), (10,13), (9,12), (10,9), (9,8), (10,5)],
|
||||
[(11,2), (12,1), (12,10), (11,9), (12,6), (11,5), (12,2), (11,14), (12,11), (11,10), (12,7), (11,6), (12,3)],
|
||||
[(14,12), (13,11), (14,8), (13,7), (14,4), (13,3), (14,13), (13,12), (14,9), (13,8), (14,5), (13,4), (14,1)],
|
||||
]
|
||||
|
||||
rahmenplan[16] = [
|
||||
[(1,15), (2,11), (1,13), (2,7), (1,11), (2,3), (1,9), (2,14), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,15)],
|
||||
[(3,12), (4,9), (3,8), (4,5), (3,4), (4,16), (3,15), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,16), (4,13)],
|
||||
[(5,10), (6,7), (5,6), (6,3), (5,2), (6,14), (5,13), (6,10), (5,9), (6,1), (6,4), (5,3), (6,15), (5,14), (6,11)],
|
||||
[(7,8), (8,5), (7,4), (8,16), (7,15), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,16), (8,13), (7,12), (8,9)],
|
||||
[(9,6), (10,3), (9,2), (10,14), (9,13), (10,1), (10,8), (9,7), (10,4), (9,3), (10,15), (9,14), (10,11), (9,10), (10,7)],
|
||||
[(11,4), (12,16), (11,15), (12,1), (12,10), (11,9), (12,6), (11,5), (12,2), (11,16), (12,13), (11,12), (12,9), (11,8), (12,5)],
|
||||
[(13,2), (14,1), (14,12), (13,11), (14,8), (13,7), (14,4), (13,3), (14,15), (13,14), (14,11), (13,10), (14,7), (13,6), (14,3)],
|
||||
[(16,14), (15,13), (16,10), (15,9), (16,6), (15,5), (16,2), (15,16), (16,13), (15,12), (16,9), (15,8), (16,5), (15,4), (16,1)],
|
||||
]
|
||||
|
||||
rahmenplan[18] = [
|
||||
[(1,17), (2,13), (1,15), (2,9), (1,13), (2,5), (1,11), (2,18), (1,9), (2,14), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,17)],
|
||||
[(3,14), (4,11), (3,10), (4,7), (3,6), (4,3), (3,2), (4,16), (3,15), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,18), (4,15)],
|
||||
[(5,12), (6,9), (5,8), (6,5), (5,4), (6,18), (5,17), (6,14), (5,13), (6,10), (5,9), (6,1), (6,4), (5,3), (6,17), (5,16), (6,13)],
|
||||
[(7,10), (8,7), (7,6), (8,3), (7,2), (8,16), (7,15), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,18), (8,15), (7,14), (8,11)],
|
||||
[(9,8), (10,5), (9,4), (10,18), (9,17), (10,14), (9,13), (10,1), (10,8), (9,7), (10,4), (9,3), (10,17), (9,16), (10,13), (9,12), (10,9)],
|
||||
[(11,6), (12,3), (11,2), (12,16), (11,15), (12,1), (12,10), (11,9), (12,6), (11,5), (12,2), (11,18), (12,15), (11,14), (12,11), (11,10), (12,7)],
|
||||
[(13,4), (14,18), (13,17), (14,1), (14,12), (13,11), (14,8), (13,7), (14,4), (13,3), (14,17), (13,16), (14,13), (13,12), (14,9), (13,8), (14,5)],
|
||||
[(15,2), (16,1), (16,14), (15,13), (16,10), (15,9), (16,6), (15,5), (16,2), (15,18), (16,15), (15,14), (16,11), (15,10), (16,7), (15,6), (16,3)],
|
||||
[(18,16), (17,15), (18,12), (17,11), (18,8), (17,7), (18,4), (17,3), (18,17), (17,16), (18,13), (17,12), (18,9), (17,8), (18,5), (17,4), (18,1)],
|
||||
]
|
||||
|
||||
rahmenplan[20] = [
|
||||
[(1,19), (2,15), (1,17), (2,11), (1,15), (2,7), (1,13), (2,3), (1,11), (2,18), (1,9), (2,14), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,19)],
|
||||
[(3,16), (4,13), (3,12), (4,9), (3,8), (4,5), (3,4), (4,20), (3,19), (4,16), (3,15), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,20), (4,17)],
|
||||
[(5,14), (6,11), (5,10), (6,7), (5,6), (6,3), (5,2), (6,18), (5,17), (6,14), (5,13), (6,10), (5,9), (6,1), (6,4), (5,3), (6,19), (5,18), (6,15)],
|
||||
[(7,12), (8,9), (7,8), (8,5), (7,4), (8,20), (7,19), (8,16), (7,15), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,20), (8,17), (7,16), (8,13)],
|
||||
[(9,10), (10,7), (9,6), (10,3), (9,2), (10,18), (9,17), (10,14), (9,13), (10,1), (10,8), (9,7), (10,4), (9,3), (10,19), (9,18), (10,15), (9,14), (10,11)],
|
||||
[(11,8), (12,5), (11,4), (12,20), (11,19), (12,16), (11,15), (12,1), (12,10), (11,9), (12,6), (11,5), (12,2), (11,20), (12,17), (11,16), (12,13), (11,12), (12,9)],
|
||||
[(13,6), (14,3), (13,2), (14,18), (13,17), (14,1), (14,12), (13,11), (14,8), (13,7), (14,4), (13,3), (14,19), (13,18), (14,15), (13,14), (14,11), (13,10), (14,7)],
|
||||
[(15,4), (16,20), (15,19), (16,1), (16,14), (15,13), (16,10), (15,9), (16,6), (15,5), (16,2), (15,20), (16,17), (15,16), (16,13), (15,12), (16,9), (15,8), (16,5)],
|
||||
[(17,2), (18,1), (18,16), (17,15), (18,12), (17,11), (18,8), (17,7), (18,4), (17,3), (18,19), (17,18), (18,15), (17,14), (18,11), (17,10), (18,7), (17,6), (18,3)],
|
||||
[(20,18), (19,17), (20,14), (19,13), (20,10), (19,9), (20,6), (19,5), (20,2), (19,20), (20,17), (19,16), (20,13), (19,12), (20,9), (19,8), (20,5), (19,4), (20,1)],
|
||||
]
|
||||
|
||||
rahmenplan[22] = [
|
||||
[(1,21), (2,17), (1,19), (2,13), (1,17), (2,9), (1,15), (2,5), (1,13), (2,22), (1,11), (2,18), (1,9), (2,14), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,21)],
|
||||
[(3,18), (4,15), (3,14), (4,11), (3,10), (4,7), (3,6), (4,3), (3,2), (4,20), (3,19), (4,16), (3,15), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,22), (4,19)],
|
||||
[(5,16), (6,13), (5,12), (6,9), (5,8), (6,5), (5,4), (6,22), (5,21), (6,18), (5,17), (6,14), (5,13), (6,10), (5,9), (6,1), (6,4), (5,3), (6,21), (5,20), (6,17)],
|
||||
[(7,14), (8,11), (7,10), (8,7), (7,6), (8,3), (7,2), (8,20), (7,19), (8,16), (7,15), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,22), (8,19), (7,18), (8,15)],
|
||||
[(9,12), (10,9), (9,8), (10,5), (9,4), (10,22), (9,21), (10,18), (9,17), (10,14), (9,13), (10,1), (10,8), (9,7), (10,4), (9,3), (10,21), (9,20), (10,17), (9,16), (10,13)],
|
||||
[(11,10), (12,7), (11,6), (12,3), (11,2), (12,20), (11,19), (12,16), (11,15), (12,1), (12,10), (11,9), (12,6), (11,5), (12,2), (11,22), (12,19), (11,18), (12,15), (11,14), (12,11)],
|
||||
[(13,8), (14,5), (13,4), (14,22), (13,21), (14,18), (13,17), (14,1), (14,12), (13,11), (14,8), (13,7), (14,4), (13,3), (14,21), (13,20), (14,17), (13,16), (14,13), (13,12), (14,9)],
|
||||
[(15,6), (16,3), (15,2), (16,20), (15,19), (16,1), (16,14), (15,13), (16,10), (15,9), (16,6), (15,5), (16,2), (15,22), (16,19), (15,18), (16,15), (15,14), (16,11), (15,10), (16,7)],
|
||||
[(17,4), (18,22), (17,21), (18,1), (18,16), (17,15), (18,12), (17,11), (18,8), (17,7), (18,4), (17,3), (18,21), (17,20), (18,17), (17,16), (18,13), (17,12), (18,9), (17,8), (18,5)],
|
||||
[(19,2), (20,1), (20,18), (19,17), (20,14), (19,13), (20,10), (19,9), (20,6), (19,5), (20,2), (19,22), (20,19), (19,18), (20,15), (19,14), (20,11), (19,10), (20,7), (19,6), (20,3)],
|
||||
[(22,20), (21,19), (22,16), (21,15), (22,12), (21,11), (22,8), (21,7), (22,4), (21,3), (22,21), (21,20), (22,17), (21,16), (22,13), (21,12), (22,9), (21,8), (22,5), (21,4), (22,1)],
|
||||
]
|
||||
|
||||
rahmenplan[24] = [
|
||||
[(1,23), (2,19), (1,21), (2,15), (1,19), (2,11), (1,17), (2,7), (1,15), (2,3), (1,13), (2,22), (1,11), (2,18), (1,9), (2,14), (1,7), (2,10), (1,5), (2,6), (1,3), (1,2), (2,23)],
|
||||
[(3,20), (4,17), (3,16), (4,13), (3,12), (4,9), (3,8), (4,5), (3,4), (4,24), (3,23), (4,20), (3,19), (4,16), (3,15), (4,12), (3,11), (4,8), (3,7), (4,1), (4,2), (3,24), (4,21)],
|
||||
[(5,18), (6,15), (5,14), (6,11), (5,10), (6,7), (5,6), (6,3), (5,2), (6,22), (5,21), (6,18), (5,17), (6,14), (5,13), (6,10), (5,9), (6,1), (6,4), (5,3), (6,23), (5,22), (6,19)],
|
||||
[(7,16), (8,13), (7,12), (8,9), (7,8), (8,5), (7,4), (8,24), (7,23), (8,20), (7,19), (8,16), (7,15), (8,12), (7,11), (8,1), (8,6), (7,5), (8,2), (7,24), (8,21), (7,20), (8,17)],
|
||||
[(9,14), (10,11), (9,10), (10,7), (9,6), (10,3), (9,2), (10,22), (9,21), (10,18), (9,17), (10,14), (9,13), (10,1), (10,8), (9,7), (10,4), (9,3), (10,23), (9,22), (10,19), (9,18), (10,15)],
|
||||
[(11,12), (12,9), (11,8), (12,5), (11,4), (12,24), (11,23), (12,20), (11,19), (12,16), (11,15), (12,1), (12,10), (11,9), (12,6), (11,5), (12,2), (11,24), (12,21), (11,20), (12,17), (11,16), (12,13)],
|
||||
[(13,10), (14,7), (13,6), (14,3), (13,2), (14,22), (13,21), (14,18), (13,17), (14,1), (14,12), (13,11), (14,8), (13,7), (14,4), (13,3), (14,23), (13,22), (14,19), (13,18), (14,15), (13,14), (14,11)],
|
||||
[(15,8), (16,5), (15,4), (16,24), (15,23), (16,20), (15,19), (16,1), (16,14), (15,13), (16,10), (15,9), (16,6), (15,5), (16,2), (15,24), (16,21), (15,20), (16,17), (15,16), (16,13), (15,12), (16,9)],
|
||||
[(17,6), (18,3), (17,2), (18,22), (17,21), (18,1), (18,16), (17,15), (18,12), (17,11), (18,8), (17,7), (18,4), (17,3), (18,23), (17,22), (18,19), (17,18), (18,15), (17,14), (18,11), (17,10), (18,7)],
|
||||
[(19,4), (20,24), (19,23), (20,1), (20,18), (19,17), (20,14), (19,13), (20,10), (19,9), (20,6), (19,5), (20,2), (19,24), (20,21), (19,20), (20,17), (19,16), (20,13), (19,12), (20,9), (19,8), (20,5)],
|
||||
[(21,2), (22,1), (22,20), (21,19), (22,16), (21,15), (22,12), (21,11), (22,8), (21,7), (22,4), (21,3), (22,23), (21,22), (22,19), (21,18), (22,15), (21,14), (22,11), (21,10), (22,7), (21,6), (22,3)],
|
||||
[(24,22), (23,21), (24,18), (23,17), (24,14), (23,13), (24,10), (23,9), (24,6), (23,5), (24,2), (23,24), (24,21), (23,20), (24,17), (23,16), (24,13), (23,12), (24,9), (23,8), (24,5), (23,4), (24,1)],
|
||||
]
|
||||
|
||||
|
||||
def get_schluesselzahlen(nTeams):
|
||||
schluessel = {md:[] for md in range(1,nTeams)}
|
||||
for row in rahmenplan[nTeams]:
|
||||
for md,(t1,t2) in enumerate(row):
|
||||
schluessel[nTeams-(md+1)].append((t1,t2))
|
||||
|
||||
pattern = {
|
||||
i: [] for i in range(1,nTeams+1)
|
||||
}
|
||||
opponent = {
|
||||
i: [] for i in range(1,nTeams+1)
|
||||
}
|
||||
|
||||
|
||||
for md in schluessel:
|
||||
for (t1,t2) in schluessel[md]:
|
||||
pattern[t1].append("H")
|
||||
pattern[t2].append("A")
|
||||
opponent[t1].append(t2)
|
||||
opponent[t2].append(t1)
|
||||
|
||||
return pattern, opponent
|
||||
23
dfbnet/serializers.py
Normal file
23
dfbnet/serializers.py
Normal file
@ -0,0 +1,23 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
""" DATA SERIALIZERS """
|
||||
|
||||
class TeamsSerializer(serializers.Serializer):
|
||||
id = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
division = serializers.IntegerField()
|
||||
|
||||
|
||||
class DivisionsSerializer(serializers.Serializer):
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
teams = TeamsSerializer(many=True)
|
||||
nTeams = serializers.IntegerField()
|
||||
ms_art = serializers.CharField()
|
||||
patterns = serializers.DictField()
|
||||
opponents = serializers.DictField()
|
||||
|
||||
|
||||
class ProblemSerializer(serializers.Serializer):
|
||||
divisions = DivisionsSerializer(many=True)
|
||||
143
dfbnet/simulation_1/auswertung_sachsen.py
Normal file
143
dfbnet/simulation_1/auswertung_sachsen.py
Normal file
@ -0,0 +1,143 @@
|
||||
# %%
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
|
||||
|
||||
# %%
|
||||
with open("data/previous_stats_road_distance.json", "r", encoding="utf-8") as f:
|
||||
stats_previous_road = json.load(f)
|
||||
stats_previous_road = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_previous_road.items()}
|
||||
|
||||
with open("data/previous_stats_road_duration.json", "r", encoding="utf-8") as f:
|
||||
stats_previous_duration = json.load(f)
|
||||
stats_previous_duration = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_previous_duration.items()}
|
||||
|
||||
with open("data/new_stats_road_distance.json", "r", encoding="utf-8") as f:
|
||||
stats_new_road = json.load(f)
|
||||
stats_new_road = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_new_road.items()}
|
||||
|
||||
with open("data/new_stats_road_duration.json", "r", encoding="utf-8") as f:
|
||||
stats_new_duration = json.load(f)
|
||||
stats_new_duration = {ast.literal_eval(k) if k != "overall" else k: v for k, v in stats_new_duration.items()}
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
print(stats_previous_road['overall'])
|
||||
print(stats_previous_duration['overall'])
|
||||
print(stats_new_road['overall'])
|
||||
print(stats_new_duration['overall'])
|
||||
|
||||
overall_stats = {
|
||||
"previous": {
|
||||
"road": stats_previous_road['overall'],
|
||||
"duration": stats_previous_duration['overall']
|
||||
},
|
||||
"new": {
|
||||
"road": stats_new_road['overall'],
|
||||
"duration": stats_new_duration['overall']
|
||||
}
|
||||
}
|
||||
|
||||
# %%
|
||||
|
||||
import plotly.graph_objects as go
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
""" create bar plot for overall stats """
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["previous"]["road"]['total_distance'], overall_stats["previous"]["duration"]['total_distance']],
|
||||
name="Previous",
|
||||
marker_color='rgb(55, 83, 109)'
|
||||
))
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["new"]["road"]['total_distance'], overall_stats["new"]["duration"]['total_distance']],
|
||||
name="New",
|
||||
marker_color='rgb(26, 118, 255)'
|
||||
))
|
||||
|
||||
fig.update_layout(
|
||||
title="Total Distances",
|
||||
xaxis_title="",
|
||||
yaxis_title="Distance in km / Time in m",
|
||||
barmode='group'
|
||||
)
|
||||
|
||||
fig.show()
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
""" create bar plot for overall stats """
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["previous"]["road"]['average_distance'], overall_stats["previous"]["duration"]['average_distance']],
|
||||
name="Previous",
|
||||
marker_color='rgb(55, 83, 109)'
|
||||
))
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["new"]["road"]['average_distance'], overall_stats["new"]["duration"]['average_distance']],
|
||||
name="New",
|
||||
marker_color='rgb(26, 118, 255)'
|
||||
))
|
||||
|
||||
fig.update_layout(
|
||||
title="Average Distances per Team",
|
||||
xaxis_title="",
|
||||
yaxis_title="Distance in km / Time in m",
|
||||
barmode='group'
|
||||
)
|
||||
|
||||
fig.show()
|
||||
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
""" create bar plot for overall stats """
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["previous"]["road"]['average_group_distance'], overall_stats["previous"]["duration"]['average_group_distance']],
|
||||
name="Previous",
|
||||
marker_color='rgb(55, 83, 109)'
|
||||
))
|
||||
fig.add_trace(go.Bar(
|
||||
x=["Distance", "Duration"],
|
||||
y=[overall_stats["new"]["road"]['average_group_distance'], overall_stats["new"]["duration"]['average_group_distance']],
|
||||
name="New",
|
||||
marker_color='rgb(26, 118, 255)'
|
||||
))
|
||||
|
||||
fig.update_layout(
|
||||
title="Average Distance per Group",
|
||||
xaxis_title="",
|
||||
yaxis_title="Distance in km / Time in m",
|
||||
barmode='group'
|
||||
)
|
||||
|
||||
fig.show()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
30
dfbnet/spielstaetten.py
Normal file
30
dfbnet/spielstaetten.py
Normal file
@ -0,0 +1,30 @@
|
||||
# %%
|
||||
import pandas as pd
|
||||
import googlemaps
|
||||
|
||||
|
||||
gmaps = googlemaps.Client(key='AIzaSyB76EhR4OqjdXHQUiTkHZC0Svx_7cPGqyU')
|
||||
|
||||
""" LOAD SPIELSTAETTEN FROM CSV"""
|
||||
|
||||
def get_venues():
|
||||
venues = pd.read_excel("data/beispieldaten_spielstaetten.xlsx")
|
||||
|
||||
venues = venues.to_dict(orient='records')
|
||||
|
||||
|
||||
for v in venues:
|
||||
geocode_result = gmaps.geocode("Dresden "+v['SB_SPST_NAME'])
|
||||
latitude =0
|
||||
longitude =0
|
||||
if len(geocode_result)>0:
|
||||
location = geocode_result[0]['geometry']['location']
|
||||
latitude = location['lat']
|
||||
longitude = location['lng']
|
||||
|
||||
v['latitude'] = latitude
|
||||
v['longitude'] = longitude
|
||||
|
||||
return venues
|
||||
|
||||
# %%
|
||||
106
dfbnet/stats_sachsen.py
Normal file
106
dfbnet/stats_sachsen.py
Normal file
@ -0,0 +1,106 @@
|
||||
# %%
|
||||
|
||||
from pulp import (
|
||||
LpVariable,
|
||||
LpProblem,
|
||||
LpMinimize,
|
||||
lpSum,
|
||||
LpStatus,
|
||||
value,
|
||||
LpInteger,
|
||||
LpContinuous,
|
||||
XPRESS,
|
||||
)
|
||||
|
||||
import googlemaps
|
||||
|
||||
from gmplot import GoogleMapPlotter
|
||||
import json
|
||||
import pandas as pd
|
||||
import ast
|
||||
import random
|
||||
import itertools
|
||||
import time
|
||||
|
||||
|
||||
|
||||
with open("data/sachsen.json", "r", encoding="utf-8") as f:
|
||||
competitions = json.load(f)
|
||||
|
||||
competitions = {ast.literal_eval(k): v for k, v in competitions.items()}
|
||||
|
||||
# region
|
||||
# STAFFELN PRO ART UND KLASSE
|
||||
# ('Herren', 'Landesliga') 1
|
||||
# ('Herren', 'Landesklasse') 3
|
||||
# ('Frauen', 'Landesliga') 1
|
||||
# ('Frauen', 'Landesklasse') 3
|
||||
# ('A-Junioren', 'Landesliga') 1
|
||||
# ('A-Junioren', 'Landesklasse') 4
|
||||
# ('Herren', 'Kreisoberliga') 13
|
||||
# ('Herren', '1.Kreisliga (A)') 19
|
||||
# ('Herren', '2.Kreisliga (B)') 8
|
||||
# ('Herren', '3.Kreisliga (C)') 1
|
||||
# ('Herren', '1.Kreisklasse') 21
|
||||
# ('Herren', '2.Kreisklasse') 9
|
||||
# ('A-Junioren', 'Kreisoberliga') 10
|
||||
# ('A-Junioren', '1.Kreisliga (A)') 6
|
||||
# ('Frauen', 'Kreisoberliga') 4
|
||||
# ('Frauen', '1.Kreisliga (A)') 1
|
||||
# ('Frauen', '1.Kreisklasse') 3
|
||||
# ('B-Junioren', 'Landesliga') 1
|
||||
# ('B-Junioren', 'Landesklasse') 4
|
||||
# ('B-Junioren', 'Kreisoberliga') 13
|
||||
# ('B-Junioren', '1.Kreisliga (A)') 13
|
||||
# ('B-Junioren', '1.Kreisklasse') 1
|
||||
# ('C-Junioren', 'Landesliga') 1
|
||||
# ('C-Junioren', 'Landesklasse') 4
|
||||
# ('C-Junioren', 'Kreisoberliga') 16
|
||||
# ('C-Junioren', '1.Kreisliga (A)') 15
|
||||
# ('C-Junioren', '1.Kreisklasse') 9
|
||||
# ('D-Junioren', 'Landesliga') 1
|
||||
# ('D-Junioren', 'Landesklasse') 6
|
||||
# ('D-Junioren', 'Kreisoberliga') 16
|
||||
# ('D-Junioren', '1.Kreisliga (A)') 24
|
||||
# ('D-Junioren', '2.Kreisliga (B)') 8
|
||||
# ('D-Junioren', '3.Kreisliga (C)') 2
|
||||
# ('D-Junioren', '1.Kreisklasse') 33
|
||||
# ('D-Junioren', '2.Kreisklasse') 10
|
||||
# ('B-Juniorinnen', 'Landesliga') 1
|
||||
# ('B-Juniorinnen', 'Landesklasse') 2
|
||||
# ('C-Juniorinnen', 'Landesklasse') 3
|
||||
# ('D-Juniorinnen', 'Kreisoberliga') 1
|
||||
# ('Herren Ü35', 'Kreisoberliga') 4
|
||||
# ('Herren Ü35', '1.Kreisliga (A)') 3
|
||||
# ('Herren Ü35', '1.Kreisklasse') 3
|
||||
# ('Herren Ü35', '2.Kreisklasse') 1
|
||||
# ('Herren Ü40', '1.Kreisliga (A)') 5
|
||||
# ('Herren Ü40', '1.Kreisklasse') 1
|
||||
# ('Herren Ü50', '1.Kreisliga (A)') 1
|
||||
# ('Herren Ü50', '1.Kreisklasse') 1
|
||||
# ('Freizeitsport', '1.Kreisliga (A)') 3
|
||||
# ('Freizeitsport', '1.Kreisklasse') 2
|
||||
# endregion
|
||||
|
||||
previous_statistics = {}
|
||||
|
||||
competition_details = {}
|
||||
color = None
|
||||
for staffel, attr in competitions.items():
|
||||
competitions[staffel]["distance"] = []
|
||||
|
||||
if (staffel[0], staffel[1]) not in competition_details:
|
||||
competition_details[(staffel[0], staffel[1])] = {
|
||||
"nStaffeln": 1,
|
||||
"nTeams": 0,
|
||||
"previous_distances": [],
|
||||
"teams": [],
|
||||
}
|
||||
else:
|
||||
competition_details[(staffel[0], staffel[1])]["nStaffeln"] += 1
|
||||
|
||||
|
||||
for key, val in competitions.items():
|
||||
print(key, val)
|
||||
|
||||
# %%
|
||||
6
fastapi/mock/Dockerfile
Normal file
6
fastapi/mock/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
FROM python:3.13
|
||||
WORKDIR /www
|
||||
COPY requirements.txt requirements.txt
|
||||
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
||||
COPY app api
|
||||
CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "4321", "--reload"]
|
||||
0
fastapi/mock/app/__init__.py
Normal file
0
fastapi/mock/app/__init__.py
Normal file
89
fastapi/mock/app/main.py
Normal file
89
fastapi/mock/app/main.py
Normal file
@ -0,0 +1,89 @@
|
||||
from fastapi import FastAPI, Depends, HTTPException, Security
|
||||
from fastapi.security.api_key import APIKeyHeader
|
||||
|
||||
from fastapi.openapi.models import APIKey
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
|
||||
from pydantic import BaseModel
|
||||
from typing import Dict
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
|
||||
API_KEY = "your-secret-api-key"
|
||||
API_KEY_NAME = "X-API-Key"
|
||||
|
||||
api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False)
|
||||
|
||||
def get_api_key(api_key: str = Depends(api_key_header)):
|
||||
if api_key == API_KEY:
|
||||
return api_key
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="Invalid or missing API Key",
|
||||
)
|
||||
|
||||
|
||||
def custom_openapi():
|
||||
if app.openapi_schema:
|
||||
return app.openapi_schema
|
||||
openapi_schema = get_openapi(
|
||||
title="FastAPI with API Key Authentication",
|
||||
version="1.0.0",
|
||||
description="API documentation with API Key authentication",
|
||||
routes=app.routes,
|
||||
)
|
||||
openapi_schema["components"]["securitySchemes"] = {
|
||||
"APIKeyHeader": {
|
||||
"type": "apiKey",
|
||||
"name": API_KEY_NAME,
|
||||
"in": "header",
|
||||
}
|
||||
}
|
||||
openapi_schema["security"] = [{"APIKeyHeader": []}]
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
app.openapi = custom_openapi
|
||||
|
||||
|
||||
|
||||
|
||||
# In-memory "database"
|
||||
items_db: Dict[int, dict] = {}
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
price: float
|
||||
|
||||
@app.get("/items3/{item_id}", response_model=Item, dependencies=[Depends(get_api_key)])
|
||||
async def get_item(item_id: int):
|
||||
item = items_db.get(item_id)
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
return item
|
||||
|
||||
@app.post("/items/", response_model=Item, status_code=201)
|
||||
async def create_item(item_id: int, item: Item):
|
||||
if item_id in items_db:
|
||||
raise HTTPException(status_code=400, detail="Item ID already exists")
|
||||
items_db[item_id] = item.dict()
|
||||
return item
|
||||
|
||||
@app.put("/items/{item_id}", response_model=Item)
|
||||
async def update_item(item_id: int, item: Item):
|
||||
if item_id not in items_db:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
items_db[item_id] = item.dict()
|
||||
return item
|
||||
|
||||
@app.delete("/items/{item_id}", status_code=204)
|
||||
async def delete_item(item_id: int):
|
||||
if item_id not in items_db:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
del items_db[item_id]
|
||||
14
fastapi/mock/docker-compose.yml
Normal file
14
fastapi/mock/docker-compose.yml
Normal file
@ -0,0 +1,14 @@
|
||||
version: "3"
|
||||
services:
|
||||
api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
container_name: fastapi-mock
|
||||
ports:
|
||||
- "4321:4321"
|
||||
user: "1002:1002"
|
||||
environment:
|
||||
- WATCHFILES_FORCE_POLLING=true # This is needed for hot reloading to work on windows (fix watch feature) for python
|
||||
- WATCHPACK_POLLING=true # This is needed for hot reloading to work on windows (fix watch feature)
|
||||
Loading…
x
Reference in New Issue
Block a user