Add mixed dataviz. CLI not operational yet.

This commit is contained in:
Jean-Christophe Dubacq 2024-10-27 20:50:51 +01:00
parent b33370daaf
commit 3b7a3df51c

148
get.py
View File

@ -97,7 +97,6 @@ def cli_check():
global depts
parser = argparse.ArgumentParser(description="Process some departments.")
parser.add_argument("--techno", action="store_true", help="Enable TECHNO mode")
parser.add_argument("depts", nargs="*", help="List of departments")
parser.add_argument(
"--base",
@ -146,7 +145,6 @@ def cli_check():
args.depts.insert(0, args.optimize)
Options.base_year = args.base
Options.techno = args.techno
depts = args.depts
orderkey = "_".join(depts)
@ -181,32 +179,37 @@ def write_conf(key, obj):
conf = read_conf(orderkey)
defaults = {
"spacing": 14,
"thickness": 6,
"fontsize_name": 10,
"fontsize_count": 14,
"width": 1300,
"height": 0,
"hmargin": 20,
"parcours_separator": "/",
"year_separator": " ",
"rank_separator": "",
"diplome_separator": "",
"reuse": "yes",
"optimize": "yes",
"main_filter": 0,
"secondary_filter": 1,
}
def conf_value(xkey: str):
"""Manage default values"""
defaults = {
"spacing": 14,
"thickness": 6,
"fontsize_name": 10,
"fontsize_count": 14,
"width": 1300,
"height": 0,
"hmargin": 20,
"parcours_separator": "/",
"year_separator": " ",
"rank_separator": "",
"diplome_separator": "",
"reuse": "yes",
"optimize": "yes",
}
if xkey in conf:
return conf[xkey]
if xkey in defaults:
return defaults[xkey]
if xkey[-9:] == "separator":
return " "
if xkey == "nick" or xkey == "displayname":
if xkey == "nick":
return "{diplome}{rank}{multidepartment}{modalite}{parcours}{year}"
if xkey == "displayname":
return "{diplome}{rank}{multidepartment}{modaliteshort}{parcours}"
if xkey == "extnick":
return "{ext}{rank}{multidepartment}{diplomenobut}{modaliteshort}"
if xkey == "orders":
@ -588,12 +591,6 @@ def analyse_depts():
else:
studentsummary["civilite"] = "?"
bacs.add(studentsummary["bac"])
# We skip non-techno students if we are in techno mode
# If we want a mixed reporting, maybe we should change this
if (
Options.techno and studentsummary["bac"][:2] != "ST"
): # TODO: change this
continue
if bucket in studentsummary["cursus"]:
semestreerreur = int(bucket) + 1
warning(
@ -1007,7 +1004,9 @@ for etudid in student.keys():
goodred[ddd] += 1
output = finaloutput + " " + etud["nickshort"][lastyear]
etud["nickshort"][lastyear + 1] = output
displaynames[output] = finals[finaloutput] + etud["nickshort"][lastyear]
displaynames[output] = (
finals[finaloutput] + displaynames[etud["nickshort"][lastyear]]
)
(firstsem, firstyear) = (
(etud["short"][1], 1)
if etud["short"][1] != None
@ -1054,8 +1053,15 @@ for etudid in student.keys():
class Filter:
# Filter on students to be considered
# 1 consider only technological baccalaureates, statistics are always asked
# 2 consider only women, because gender statistics are frequently asked
# 4 consider only incoming students (primo-entrants) in first year of the cohort
# 8 consider only people having a first year, not parallel entries
TECHNO = 1
WOMAN = 2
PRIMO = 4
MAIN = 8
def bags_from_students(student, filter=0):
@ -1253,32 +1259,31 @@ def get_layer_structure(newls, node_structure, spacing, hmargin, height):
for j in ls["olayer"]:
lhi = 0
lho = 0
slhi = 0
slho = 0
k = node_structure[j]
for prev_node in k["prev"]:
lhi += prev_node[1]
slhi += prev_node[2]
for next_node in k["next"]:
lho += next_node[1]
slho += next_node[2]
k["size"] = max(lhi, lho)
k["ssize"] = max(slhi, slho)
k["in"] = lhi
k["out"] = lho
if lhi != lho and lhi * lho != 0:
print(f"BUG1: {j} {k} {lhi} {lho}")
print(json.dumps(layer_structure, indent=2))
print(json.dumps(node_structure, indent=2))
warning(f"BUG1: {j} {k} {lhi} {lho}")
ls["inout"] += k["size"]
layer_structure.append(ls)
if height == 0:
debug("coucou")
minheight = 0
for i in range(5):
ls = layer_structure[i]
new_minheight = spacing * (ls["num"] - 1) + 2 * hmargin + 2 * ls["inout"]
debug(f"{new_minheight} / {minheight}")
if new_minheight > minheight:
minheight = new_minheight
height = (1 + (minheight // 150)) * 150
debug(f"{height}")
for i in range(5):
ls = layer_structure[i]
ls["density"] = ls["inout"] / (
@ -1300,6 +1305,8 @@ def get_layer_structure(newls, node_structure, spacing, hmargin, height):
ns = node_structure[j]
ns["top"] = supp_spacing + spacing + cs
h = ns["size"] / realdensity
sh = ns["ssize"] / realdensity
ns["middle"] = ns["top"] + sh
cs = ns["bottom"] = ns["top"] + h
return realdensity, height, layer_structure
@ -1308,6 +1315,14 @@ def nodestructure_from_bags(bags, sbags=None):
node_structure = {}
layers = [[], [], [], [], []]
edges = []
union_sbag = {}
if sbags is not None:
for layer, layernodes in enumerate(sbags):
for startnode in layernodes:
for endnode in layernodes[startnode]:
if startnode not in union_sbag:
union_sbag[startnode] = {}
union_sbag[startnode][endnode] = layernodes[startnode][endnode]
for layer, layernodes in enumerate(bags):
for startnode in layernodes:
# if startnode[-1] == "*":
@ -1316,24 +1331,30 @@ def nodestructure_from_bags(bags, sbags=None):
# if endnode[-1] == "*":
# continue
weight = layernodes[startnode][endnode]
if startnode in union_sbag and endnode in union_sbag[startnode]:
sweight = union_sbag[startnode][endnode]
elif sbags is None:
sweight = -1
else:
sweight = 0
if endnode not in node_structure:
node_structure[endnode] = {
"prev": [[startnode, weight]],
"prev": [[startnode, weight, sweight]],
"next": [],
"layer": layer + 1,
}
layers[layer + 1].append(endnode)
else:
node_structure[endnode]["prev"].append([startnode, weight])
node_structure[endnode]["prev"].append([startnode, weight, sweight])
if startnode not in node_structure:
node_structure[startnode] = {
"prev": [],
"next": [[endnode, weight]],
"next": [[endnode, weight, sweight]],
"layer": layer,
}
layers[layer].append(startnode)
else:
node_structure[startnode]["next"].append([endnode, weight])
node_structure[startnode]["next"].append([endnode, weight, sweight])
edges.append([startnode, endnode, weight])
return node_structure, layers, edges
@ -1366,6 +1387,17 @@ def compute_svg(height, padding, realdensity, node_structure):
2 * thickness,
ns["bottom"] - ns["top"],
fill=col,
opacity=0.5,
stroke_width=0.1,
stroke="#808080",
)
g1.append(r)
r = drawsvg.Rectangle(
xpos - thickness,
ns["top"],
2 * thickness,
ns["middle"] - ns["top"],
fill=col,
stroke_width=0.2,
stroke="black",
)
@ -1426,16 +1458,20 @@ def compute_svg(height, padding, realdensity, node_structure):
ns["next"].sort(key=lambda x: node_structure[x[0]]["top"])
start = ns["top"]
for link in ns["prev"]:
ysize = link[-1]
ysize = link[1]
sysize = link[2]
link.append(start)
link.append(start + sysize / realdensity)
start += ysize / realdensity
link.append(start)
for n in node_structure:
ns = node_structure[n]
start = ns["top"]
for link in ns["next"]:
ysize = link[-1]
ysize = link[1]
sysize = link[2]
link.append(start)
link.append(start + sysize / realdensity)
start += ysize / realdensity
link.append(start)
targets = node_structure[link[0]]
@ -1446,7 +1482,7 @@ def compute_svg(height, padding, realdensity, node_structure):
if target == None:
print(f"BUG: {n},{ns},{t}")
sys.exit(5)
# At this point, link has values target_name, size, secondary_size, top, middle, bottom
posxa = columns[ns["layer"]] + thickness
posxb = columns[targets["layer"]] - thickness
posxc = (3 * posxa + posxb) / 4
@ -1454,12 +1490,31 @@ def compute_svg(height, padding, realdensity, node_structure):
grad = drawsvg.LinearGradient(posxa, 0, posxb, 0)
grad.add_stop(0, ns["color"], opacity=0.5)
grad.add_stop(1, targets["color"], opacity=0.5)
p = drawsvg.Path(fill=grad, stroke_width=0)
p.M(posxa, link[-2])
p.C(posxc, link[-2], posxd, target[-2], posxb, target[-2])
p.L(posxb, target[-1])
p.C(posxd, target[-1], posxc, link[-1], posxa, link[-1])
posyat = link[3]
posyam = link[4]
posyab = link[5]
posybt = target[3]
posybm = target[4]
posybb = target[5]
p = drawsvg.Path(fill=grad, stroke="#000", stroke_width=0, opacity=0.8)
p.M(posxa, posyab)
p.C(posxc, posyab, posxd, posybb, posxb, posybb)
p.L(posxb, posybt)
p.C(posxd, posybt, posxc, posyat, posxa, posyat)
p.Z()
p.append_title(
f"{displaynames[n]}=>{displaynames[link[0]]}: {link[2]}/{link[1]}"
)
g2.append(p)
p = drawsvg.Path(fill=grad, stroke="#000", stroke_width=0)
p.M(posxa, posyam)
p.C(posxc, posyam, posxd, posybm, posxb, posybm)
p.L(posxb, posybt)
p.C(posxd, posybt, posxc, posyat, posxa, posyat)
p.Z()
p.append_title(
f"{displaynames[n]}=>{displaynames[link[0]]}: {link[2]}/{link[1]}"
)
g2.append(p)
d.append(g2)
d.append(g1)
@ -1473,8 +1528,9 @@ def printsvg():
spacing = conf_value("spacing")
height = conf_value("height")
hmargin = conf_value("hmargin")
bags = bags_from_students(student, 0)
node_structure, layers, edges = nodestructure_from_bags(bags)
bags = bags_from_students(student, conf_value("main_filter"))
sbags = bags_from_students(student, conf_value("secondary_filter"))
node_structure, layers, edges = nodestructure_from_bags(bags, sbags)
filename = "best-" + orderkey
if Options.restart:
try: