Skip to content

Commit

Permalink
Merge pull request #222 from DemocracyDevelopers/206-various-small-im…
Browse files Browse the repository at this point in the history
…provements-to-reports

206 various small improvements to reports
  • Loading branch information
vteague authored Nov 22, 2024
2 parents 2b512e4 + a7981b0 commit 2ee014c
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 73 deletions.
4 changes: 2 additions & 2 deletions client/src/component/AuditReportForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ const REPORT_TYPES: ReportType[] = [
{key:'contest_selection', label:'Contest selection'},
{key:'contests_by_county', label:'Contests by county'},
{key:'seed', label:'Seed'},
{key:'tabulate', label:'Tabulate'},
{key:'tabulate_county', label:'Tabulate county'},
{key:'tabulate_plurality', label:'Tabulate'},
{key:'tabulate_county_plurality', label:'Tabulate county'},
{key:'upload_status', label:'Upload status'},
{key:'ResultReport', label:'Result Report'},
{key:'ActivityReport', label:'Activity Report'},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public static List<String> getSqlFolderFiles() {
final String folder = "sql";
final String[] fileNames = {"batch_count_comparison.sql", "contest.sql",
"contest_comparison.sql", "contest_selection.sql", "contests_by_county.sql",
"tabulate.sql", "tabulate_county.sql", "upload_status.sql", "seed.sql",
"tabulate_plurality.sql", "tabulate_county_plurality.sql", "upload_status.sql", "seed.sql",
"summarize_IRV.sql", "ranked_ballot_interpretation.sql"};
for (final String f : fileNames) {
paths.add(String.format("%s/%s", folder, f));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ public Workbook generateExcelWorkbook() {

max_cell_number = Math.max(max_cell_number, cell_number);
row_number = row_number - 1; // don't skip a line for the first contest
// Print the county contest results. These do not need IRV summaries.
for (final CountyContestResult ccr : my_driving_contest_results) {

StateReport.CellStatus status = StateReport.makeContestSummary(row_number, max_cell_number, ccr, summary_sheet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ public Workbook generateExcelWorkbook() {

// County-level results really don't make sense for IRV. Therefore print a
// very brief summary and a reference to the assertions csv.
// At this stage, we don't want to print IRV choices.
for (final CountyContestResult ccr : e.getValue().drivingContestResults()) {

final CellStatus status = makeContestSummary(row_number, max_cell_number, ccr, summary_sheet,
Expand Down Expand Up @@ -684,15 +685,15 @@ public Workbook generateExcelWorkbook() {

/**
* Make the cells for one contest's worth of summary data. For IRV, this just prints the
* contest name, choices, and the fact that it's IRV. For plurality, it outputs much more
* detailed data.
* @param row_number Number of the current row, which is incremented as we progress and
* included in Cell Status on return.
* @param max_cell_number The maximum cell number used, which is included in Cell Status on return.
* @param ccr The County Contest Result to be summarized.
* @param summary_sheet The sheet to be added to.
* @param bold_style All these styles are included (though they could be class-level finals)
* in case a caller from another class wants different styles.
* contest name, the fact that it's IRV, and a message about where to find more information.
* For plurality, it outputs much more detailed data.
* @param row_number Number of the current row, which is incremented as we progress and
* included in Cell Status on return.
* @param max_cell_number The maximum cell number used, which is included in Cell Status on return.
* @param ccr The County Contest Result to be summarized.
* @param summary_sheet The sheet to be added to.
* @param bold_style All these styles are included (though they could be class-level finals)
* in case a caller from another class wants different styles.
* @param integer_style "
* @param bold_right_style "
* @param decimal_style "
Expand All @@ -704,52 +705,50 @@ public Workbook generateExcelWorkbook() {
protected static CellStatus makeContestSummary(int row_number, int max_cell_number, final CountyContestResult ccr,
final Sheet summary_sheet, final CellStyle bold_style, final CellStyle integer_style, final CellStyle bold_right_style,
final CellStyle decimal_style, final CellStyle standard_style, final CellStyle standard_right_style) {
row_number++;
Row row = summary_sheet.createRow(row_number++);
int cell_number = 0;
row_number++;
Row row = summary_sheet.createRow(row_number++);
int cell_number = 0;

Cell cell = row.createCell(cell_number++);
cell.setCellStyle(bold_style);
Cell cell = row.createCell(cell_number++);
cell.setCellStyle(bold_style);

final boolean isIRV = ccr.contest().description().equals(ContestType.IRV.toString());
final boolean isIRV = ccr.contest().description().equals(ContestType.IRV.toString());

if (isIRV) {
cell.setCellValue(ccr.contest().name() + " - IRV");
} else {
cell.setCellValue(ccr.contest().name() + " - Vote For " + ccr.contest().votesAllowed());
}
// Print the contest name, with a summary message about the contest type
final String contestname = ccr.contest().name() + (isIRV ? " - IRV" : " - Vote For " + ccr.contest().votesAllowed());
cell.setCellValue(contestname);

// Keep the choices column, for both IRV and plurality.
if (isIRV) {
// If it's IRV, the summary data is in the assertions csv. Add a message, that's all.
cell = row.createCell(cell_number++);
cell.setCellStyle(standard_style);
cell.setCellValue("See assertions csv");
} else {
// Plurality.
// Data headers - choices, winners, vote tallies, margins.
cell = row.createCell(cell_number++);
cell.setCellStyle(bold_style);
cell.setCellValue("Choice");

if (isIRV) {
// If it's IRV, the summary data is in the assertions csv. Add a message.
cell = row.createCell(cell_number++);
cell.setCellStyle(standard_style);
cell.setCellValue("See assertions csv");
} else {
// Plurality. Print the other data - winners, vote tallies, margins.
cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("W/L");
cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("W/L");

cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("Votes");
cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("Votes");

cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("Margin");
cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("Margin");

cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("Diluted Margin %");
}
cell = row.createCell(cell_number++);
cell.setCellStyle(bold_right_style);
cell.setCellValue("Diluted Margin %");

// Now print the actual data.
for (final String choice : ccr.rankedChoices()) {
// List all the choices, for both IRV and plurality.
// List all the choices.
row = summary_sheet.createRow(row_number++);
max_cell_number = Math.max(max_cell_number, cell_number);

Expand All @@ -758,40 +757,39 @@ protected static CellStatus makeContestSummary(int row_number, int max_cell_numb
cell.setCellStyle(standard_style);
cell.setCellValue(choice);

if (!isIRV) {
// Print the other data - winners, vote tallies, margins - only for plurality, not IRV.
cell = row.createCell(cell_number++);
cell.setCellStyle(standard_right_style);
if ((ccr.winners().stream().anyMatch(w -> w.equalsIgnoreCase(choice)))) {
cell.setCellValue("W");
} else {
cell.setCellValue("L");
}
// Winners, vote tallies, margins.
cell = row.createCell(cell_number++);
cell.setCellStyle(standard_right_style);
if ((ccr.winners().stream().anyMatch(w -> w.equalsIgnoreCase(choice)))) {
cell.setCellValue("W");
} else {
cell.setCellValue("L");
}

cell = row.createCell(cell_number++);
cell.setCellStyle(integer_style);
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(ccr.voteTotals().get(choice));

if (ccr.winners().contains(choice)) {
cell = row.createCell(cell_number++);
cell.setCellStyle(integer_style);
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(ccr.voteTotals().get(choice));

if (ccr.winners().contains(choice)) {
cell = row.createCell(cell_number++);
cell.setCellStyle(integer_style);
cell.setCellType(CellType.NUMERIC);
final OptionalInt margin = ccr.marginToNearestLoser(choice);
if (margin.isPresent()) {
cell.setCellValue(margin.getAsInt());
}
final OptionalInt margin = ccr.marginToNearestLoser(choice);
if (margin.isPresent()) {
cell.setCellValue(margin.getAsInt());
}

cell = row.createCell(cell_number++);
cell.setCellStyle(decimal_style);
cell.setCellType(CellType.NUMERIC);
final BigDecimal diluted_margin = ccr.countyDilutedMarginToNearestLoser(choice);
if (diluted_margin != null) {
cell.setCellValue(diluted_margin.doubleValue() * 100);
}
cell = row.createCell(cell_number++);
cell.setCellStyle(decimal_style);
cell.setCellType(CellType.NUMERIC);
final BigDecimal diluted_margin = ccr.countyDilutedMarginToNearestLoser(choice);
if (diluted_margin != null) {
cell.setCellValue(diluted_margin.doubleValue() * 100);
}
}
}
}
return new CellStatus(row_number, max_cell_number);
}

Expand Down
26 changes: 24 additions & 2 deletions server/eclipse-project/src/main/resources/sql/summarize_IRV.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
-- Show the IRV summaries, sorted by contest name.
-- This is usually a (unique) winner and an empty error, but may also be a
-- blank winner and a non-empty error with an explanatory message.
-- This also adds a column to indicate whether the contest was targeted for audit. This requires
-- a join with the contest_to_audit table, which is slightly complicated by the fact that that table
-- stores _one of_ the contest ids for multi-county contests, so we have to check whether there is
-- _any_ contest of the same name with an ID in the contest_to_audit table. This simply selects the
-- first audit reason, in the very unlikely event that one contest is selected for both COUNTY_WIDE
-- and STATE_WIDE reasons.

SELECT gas.contest_name, gas.winner, gas.error, gas.message
SELECT gas.contest_name, COALESCE(targets.targeted_reason, 'Not targeted') as target_reason, gas.winner, gas.error, gas.message
FROM generate_assertions_summary as gas
ORDER BY contest_name;
-- This sub-query attaches audit target reasons (aggregated), if any, to contest names, and
-- 'Not targeted' otherwise.
-- Inner join because we only want the ones in the generate_assertions_summary table.
LEFT JOIN (
SELECT contest.name as name, contest_to_audit.reason as targeted_reason
FROM contest_to_audit
-- Again an inner join, because we only want the ones in the table of targeted contests.
-- This will give us the one row of the contest table that happens to have been identified in the
-- contest_to_audit table
INNER JOIN contest
ON contest_to_audit.contest_id = contest.id
) AS targets
ON gas.contest_name = targets.name;




0 comments on commit 2ee014c

Please sign in to comment.