From d896555938e7782a38d22ce83c93d4141b73fbef Mon Sep 17 00:00:00 2001 From: shiying Date: Tue, 14 Jan 2025 11:23:16 +0000 Subject: [PATCH 1/6] Left align name column --- shortlister/model.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/shortlister/model.py b/shortlister/model.py index 15cd19a..d4eddc9 100644 --- a/shortlister/model.py +++ b/shortlister/model.py @@ -405,7 +405,8 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion # Styling # Auto adjust width for name column max_length = 0 - for cell in ws["B"]: + name_column = [ws[f"B{i}"] for i in range(1, ws.max_row + 1)] + for cell in name_column: try: if len(str(cell.value)) > max_length: max_length = len(cell.value) @@ -427,8 +428,11 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion # change colour/style of headings for col in range(1, ws.max_column+1): - heading_cell = ws[get_column_letter(col) + "1"] - heading_cell.alignment = Alignment(horizontal="center") + heading_cell = ws[get_column_letter(col) + "1"] + if heading_cell.column_letter == "B": + heading_cell.alignment = Alignment(horizontal="left") + else: + heading_cell.alignment = Alignment(horizontal="center") heading_cell.font = Font(bold=True) heading_cell.fill = PatternFill( start_color="8DB4E2", fill_type="solid" @@ -442,7 +446,10 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion # add colour for cells depending on the score: U(red),M(yellow),S,E(green) for row in ws.iter_rows(2): for cell in row: - cell.alignment = Alignment(horizontal="center") + if cell.column_letter == "B": + cell.alignment = Alignment(horizontal="left") + else: + cell.alignment = Alignment(horizontal="center") if str(cell.value) in RANK_COLOUR_EXCEL: colour_parameter = RANK_COLOUR_EXCEL.get(cell.value) cell.fill = PatternFill(**colour_parameter) From 02669a4df2cdc0167f4223a3ae0d4d2203a587b1 Mon Sep 17 00:00:00 2001 From: shiying Date: Tue, 14 Jan 2025 13:19:02 +0000 Subject: [PATCH 2/6] Use conditional formatting to dynamically update score colours --- shortlister/model.py | 67 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/shortlister/model.py b/shortlister/model.py index d4eddc9..ea5162c 100644 --- a/shortlister/model.py +++ b/shortlister/model.py @@ -5,8 +5,10 @@ import pickle from openpyxl import Workbook from openpyxl.utils import get_column_letter -from openpyxl.styles import PatternFill, Font, Alignment +from openpyxl.styles import PatternFill, Font, Alignment, Color from openpyxl.worksheet.table import Table,TableStyleInfo +from openpyxl.formatting.rule import ColorScaleRule, ColorScale, FormatObject, FormulaRule, Rule +from openpyxl.styles.differential import DifferentialStyle import pymupdf import re @@ -76,22 +78,10 @@ class Shortlist: } RANK_COLOUR_EXCEL = { - "U":{ - "start_color":"FF3300", - "fill_type":"solid" - }, - "M":{ - "start_color":"FFFF00", - "fill_type":"solid" - }, - "S":{ - "start_color":"C4D79B", - "fill_type":"solid" - }, - "E":{ - "start_color":"92D050", - "fill_type":"solid" - }, + "U":DifferentialStyle(font=Font(color="9C0006"), fill=PatternFill(bgColor="FFC7CE",fill_type="solid")), + "M": DifferentialStyle(font=Font(color="000000"),fill=PatternFill(bgColor="FFFF00", fill_type="solid")), + "S": DifferentialStyle(font=Font(color="000000"),fill=PatternFill(bgColor="C4D79B", fill_type="solid")), + "E": DifferentialStyle(font=Font(color="000000"),fill=PatternFill(bgColor="92D050", fill_type="solid")), } # Functions @@ -403,6 +393,7 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion ws.append(flat_list) # Styling + # Auto adjust width for name column max_length = 0 name_column = [ws[f"B{i}"] for i in range(1, ws.max_row + 1)] @@ -415,16 +406,6 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion adjusted_width = (max_length + 1.5) * 1.2 ws.column_dimensions["B"].width = adjusted_width - # table styling - table_range = f"A1:{get_column_letter(ws.max_column)}{ws.max_row}" - - table = Table(displayName="DynamicTable", ref=table_range) - table.tableStyleInfo = TableStyleInfo(name="TableStyleMedium9", - showFirstColumn=False, - showLastColumn=False, - showRowStripes=True, - showColumnStripes=False,) - ws.add_table(table) # change colour/style of headings for col in range(1, ws.max_column+1): @@ -443,20 +424,38 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion heading_score_cell = ws[get_column_letter(col)+"1"] heading_score_cell.alignment = Alignment(horizontal="center",textRotation=90) - # add colour for cells depending on the score: U(red),M(yellow),S,E(green) + # alignment for row in ws.iter_rows(2): for cell in row: if cell.column_letter == "B": cell.alignment = Alignment(horizontal="left") else: cell.alignment = Alignment(horizontal="center") - if str(cell.value) in RANK_COLOUR_EXCEL: - colour_parameter = RANK_COLOUR_EXCEL.get(cell.value) - cell.fill = PatternFill(**colour_parameter) - else: - pass - wb.save(filename) + # table styling + table_range = f"A1:{get_column_letter(ws.max_column)}{ws.max_row}" + + table = Table(displayName="DynamicTable", ref=table_range) + table.tableStyleInfo = TableStyleInfo(name="TableStyleMedium9", + showFirstColumn=False, + showLastColumn=False, + showRowStripes=True, + showColumnStripes=False,) + ws.add_table(table) + + # add colour for cells depending on the score: U(red),M(yellow),S,E(green) + + for score in RANK_COLOUR_EXCEL: + ws.conditional_formatting.add( + range_string=table_range, + cfRule=Rule( + type="containsText", + operator="containsText", + text=score, + dxf=RANK_COLOUR_EXCEL[score], + formula=[f'EXACT("{score}",A1)'] + ) + ) def abbreviate(list_of_strings: List[str]) -> list[str]: From 0a51649adbe91515f2c49cfbca33c330c87456a9 Mon Sep 17 00:00:00 2001 From: shiying Date: Tue, 14 Jan 2025 13:23:19 +0000 Subject: [PATCH 3/6] Revert accident deletion --- shortlister/model.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shortlister/model.py b/shortlister/model.py index ea5162c..4d1c841 100644 --- a/shortlister/model.py +++ b/shortlister/model.py @@ -7,7 +7,7 @@ from openpyxl.utils import get_column_letter from openpyxl.styles import PatternFill, Font, Alignment, Color from openpyxl.worksheet.table import Table,TableStyleInfo -from openpyxl.formatting.rule import ColorScaleRule, ColorScale, FormatObject, FormulaRule, Rule +from openpyxl.formatting.rule import ColorScaleRule, ColorScale, FormatObject, FormulaRule, Rule, IconSet from openpyxl.styles.differential import DifferentialStyle import pymupdf import re @@ -393,7 +393,7 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion ws.append(flat_list) # Styling - + # Auto adjust width for name column max_length = 0 name_column = [ws[f"B{i}"] for i in range(1, ws.max_row + 1)] @@ -456,7 +456,8 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion formula=[f'EXACT("{score}",A1)'] ) ) - + + wb.save(filename) def abbreviate(list_of_strings: List[str]) -> list[str]: """Create abbreviations for all strings in a list.""" From 604d63c1dd43501512d963eef55585497affdc85 Mon Sep 17 00:00:00 2001 From: shiying Date: Tue, 14 Jan 2025 14:05:37 +0000 Subject: [PATCH 4/6] Tidy up imports --- shortlister/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shortlister/model.py b/shortlister/model.py index 4d1c841..e72c17d 100644 --- a/shortlister/model.py +++ b/shortlister/model.py @@ -5,9 +5,9 @@ import pickle from openpyxl import Workbook from openpyxl.utils import get_column_letter -from openpyxl.styles import PatternFill, Font, Alignment, Color +from openpyxl.styles import PatternFill, Font, Alignment from openpyxl.worksheet.table import Table,TableStyleInfo -from openpyxl.formatting.rule import ColorScaleRule, ColorScale, FormatObject, FormulaRule, Rule, IconSet +from openpyxl.formatting.rule import Rule from openpyxl.styles.differential import DifferentialStyle import pymupdf import re From 300a8e07ff2eb1f22d2daf97be22e86dafb18868 Mon Sep 17 00:00:00 2001 From: shiying Date: Tue, 14 Jan 2025 15:36:18 +0000 Subject: [PATCH 5/6] Add iconset rules for rtw and score percentage --- shortlister/model.py | 52 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/shortlister/model.py b/shortlister/model.py index e72c17d..1a43684 100644 --- a/shortlister/model.py +++ b/shortlister/model.py @@ -7,7 +7,7 @@ from openpyxl.utils import get_column_letter from openpyxl.styles import PatternFill, Font, Alignment from openpyxl.worksheet.table import Table,TableStyleInfo -from openpyxl.formatting.rule import Rule +from openpyxl.formatting.rule import Rule,IconSetRule from openpyxl.styles.differential import DifferentialStyle import pymupdf import re @@ -297,7 +297,7 @@ def extract_info_from_text(lines: List[str]): # creating tabular data def get_headings(criteria:List[Criterion]): """Get headings for table""" - header = ["No.", "NAME", "Σ", "RtW"] + header = ["No.", "NAME", "Σ","%","RtW"] criteria_headings = [criterion.name for criterion in criteria] return header,criteria_headings @@ -306,12 +306,17 @@ def get_applicant_information(applicants:List[Applicant],criteria:List[Criterion rows = [] scores =[] i = 0 + denominator = RANK_AND_SCORE["Excellent"]*len(criteria) + for applicant in applicants: i = i + 1 + amount_scored = total_score(applicant.scores) + percentage_scored = round(amount_scored/denominator,2)*100 row = [ i, applicant.name, - total_score(applicant.scores), + amount_scored, + percentage_scored, "Y" if applicant.right_to_work else "N", ] score = [] @@ -337,6 +342,8 @@ def applicant_table( header = header + criteria_headings else: header = header + ["SCORES"] + + RANK_AND_SCORE["Excellent"]*len(criteria_headings) # creates rows of applicant data @@ -420,7 +427,7 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion ) # rotate score headings - for col in range(5, ws.max_column+1): + for col in range(6, ws.max_column+1): heading_score_cell = ws[get_column_letter(col)+"1"] heading_score_cell.alignment = Alignment(horizontal="center",textRotation=90) @@ -443,8 +450,39 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion showColumnStripes=False,) ws.add_table(table) - # add colour for cells depending on the score: U(red),M(yellow),S,E(green) + # Icon rules + + # right to work column + rtw_to_num = { + "N": 0, + "?": 2, + "Y": 1 + } + + for row in ws.iter_rows(min_row=2, max_row=ws.max_row, min_col=5, max_col=5): + for cell in row: + if cell.value in rtw_to_num: + # map string to value + cell.value = rtw_to_num[cell.value] + + rtw_icon_rule = IconSetRule( + type="num", + icon_style="3Symbols", + showValue=False, + percent=True, + values=[0, 2, 1] + ) + + # total score column + total_score_icon_rule = IconSetRule( + type="num", + icon_style="3Arrows", + showValue=True, + percent=True, + values=[0,50,75] + ) + # conditional formatting for score in RANK_COLOUR_EXCEL: ws.conditional_formatting.add( range_string=table_range, @@ -456,7 +494,9 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion formula=[f'EXACT("{score}",A1)'] ) ) - + ws.conditional_formatting.add(f"D2:D{ws.max_row}", total_score_icon_rule) + ws.conditional_formatting.add(f"E2:E{ws.max_row}", rtw_icon_rule) + wb.save(filename) def abbreviate(list_of_strings: List[str]) -> list[str]: From a202463a228505f43fdec6cdf82c279010b3b1fa Mon Sep 17 00:00:00 2001 From: shiying Date: Thu, 16 Jan 2025 15:43:53 +0000 Subject: [PATCH 6/6] Revert "Add iconset rules for rtw and score percentage" This reverts commit 300a8e07ff2eb1f22d2daf97be22e86dafb18868. --- shortlister/model.py | 52 +++++--------------------------------------- 1 file changed, 6 insertions(+), 46 deletions(-) diff --git a/shortlister/model.py b/shortlister/model.py index 1a43684..e72c17d 100644 --- a/shortlister/model.py +++ b/shortlister/model.py @@ -7,7 +7,7 @@ from openpyxl.utils import get_column_letter from openpyxl.styles import PatternFill, Font, Alignment from openpyxl.worksheet.table import Table,TableStyleInfo -from openpyxl.formatting.rule import Rule,IconSetRule +from openpyxl.formatting.rule import Rule from openpyxl.styles.differential import DifferentialStyle import pymupdf import re @@ -297,7 +297,7 @@ def extract_info_from_text(lines: List[str]): # creating tabular data def get_headings(criteria:List[Criterion]): """Get headings for table""" - header = ["No.", "NAME", "Σ","%","RtW"] + header = ["No.", "NAME", "Σ", "RtW"] criteria_headings = [criterion.name for criterion in criteria] return header,criteria_headings @@ -306,17 +306,12 @@ def get_applicant_information(applicants:List[Applicant],criteria:List[Criterion rows = [] scores =[] i = 0 - denominator = RANK_AND_SCORE["Excellent"]*len(criteria) - for applicant in applicants: i = i + 1 - amount_scored = total_score(applicant.scores) - percentage_scored = round(amount_scored/denominator,2)*100 row = [ i, applicant.name, - amount_scored, - percentage_scored, + total_score(applicant.scores), "Y" if applicant.right_to_work else "N", ] score = [] @@ -342,8 +337,6 @@ def applicant_table( header = header + criteria_headings else: header = header + ["SCORES"] - - RANK_AND_SCORE["Excellent"]*len(criteria_headings) # creates rows of applicant data @@ -427,7 +420,7 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion ) # rotate score headings - for col in range(6, ws.max_column+1): + for col in range(5, ws.max_column+1): heading_score_cell = ws[get_column_letter(col)+"1"] heading_score_cell.alignment = Alignment(horizontal="center",textRotation=90) @@ -450,39 +443,8 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion showColumnStripes=False,) ws.add_table(table) - # Icon rules - - # right to work column - rtw_to_num = { - "N": 0, - "?": 2, - "Y": 1 - } - - for row in ws.iter_rows(min_row=2, max_row=ws.max_row, min_col=5, max_col=5): - for cell in row: - if cell.value in rtw_to_num: - # map string to value - cell.value = rtw_to_num[cell.value] - - rtw_icon_rule = IconSetRule( - type="num", - icon_style="3Symbols", - showValue=False, - percent=True, - values=[0, 2, 1] - ) - - # total score column - total_score_icon_rule = IconSetRule( - type="num", - icon_style="3Arrows", - showValue=True, - percent=True, - values=[0,50,75] - ) + # add colour for cells depending on the score: U(red),M(yellow),S,E(green) - # conditional formatting for score in RANK_COLOUR_EXCEL: ws.conditional_formatting.add( range_string=table_range, @@ -494,9 +456,7 @@ def export_excel(filename, applicants: List[Applicant], criteria: List[Criterion formula=[f'EXACT("{score}",A1)'] ) ) - ws.conditional_formatting.add(f"D2:D{ws.max_row}", total_score_icon_rule) - ws.conditional_formatting.add(f"E2:E{ws.max_row}", rtw_icon_rule) - + wb.save(filename) def abbreviate(list_of_strings: List[str]) -> list[str]: