Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BI-1914 - Improve exp dataset sort #303

Merged
merged 11 commits into from
Nov 8, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
import org.brapi.v2.model.core.*;
import org.brapi.v2.model.core.response.BrAPIListsSingleResponse;
import org.brapi.v2.model.germ.BrAPIGermplasm;

import org.brapi.v2.model.pheno.*;
import org.breedinginsight.brapi.v2.constants.BrAPIAdditionalInfoFields;
import org.breedinginsight.brapi.v2.dao.BrAPIGermplasmDAO;
import org.breedinginsight.brapi.v2.model.request.query.ExperimentExportQuery;
import org.breedinginsight.brapps.importer.daos.*;
import org.breedinginsight.brapps.importer.model.exports.FileType;
import org.breedinginsight.brapps.importer.model.imports.experimentObservation.ExperimentObservation;
import org.breedinginsight.brapps.importer.model.imports.experimentObservation.ExperimentObservation.Columns;
import org.breedinginsight.brapps.importer.services.ExternalReferenceSource;
import org.breedinginsight.brapps.importer.services.FileMappingUtil;
import org.breedinginsight.model.BrAPIConstants;
Expand All @@ -29,7 +31,9 @@
import org.breedinginsight.services.parsers.experiment.ExperimentFileColumns;
import org.breedinginsight.services.writers.CSVWriter;
import org.breedinginsight.services.writers.ExcelWriter;
import org.breedinginsight.utilities.IntOrderComparator;
import org.breedinginsight.utilities.Utilities;
import org.jetbrains.annotations.NotNull;

import javax.inject.Inject;
import javax.inject.Singleton;
Expand Down Expand Up @@ -57,6 +61,7 @@ public class BrAPITrialService {
private final BrAPIObservationUnitDAO ouDAO;
private final BrAPIGermplasmDAO germplasmDAO;
private final FileMappingUtil fileMappingUtil;
private static final String SHEET_NAME = "Data";

@Inject
public BrAPITrialService(@Property(name = "brapi.server.reference-source") String referenceSource,
Expand Down Expand Up @@ -227,15 +232,17 @@ public DownloadFile exportObservations(
// Initialize key with empty list if it is not present.
if (!rowsByStudyId.containsKey(studyId))
{
rowsByStudyId.put(studyId, new ArrayList<Map<String, Object>>());
rowsByStudyId.put(studyId, new ArrayList<>());
}
// Add row to appropriate list in rowsByStudyId.
rowsByStudyId.get(studyId).add(row);
}
List<DownloadFile> files = new ArrayList<>();
// Generate a file for each study.
for (Map.Entry<String, List<Map<String, Object>>> entry: rowsByStudyId.entrySet()) {
StreamedFile streamedFile = writeToStreamedFile(columns, entry.getValue(), fileType, "Experiment Data");
List<Map<String, Object>> rows = entry.getValue();
sortDefaultForExportRows(rows);
StreamedFile streamedFile = writeToStreamedFile(columns, rows, fileType, SHEET_NAME);
String name = makeFileName(experiment, program, studyByDbId.get(entry.getKey()).getStudyName()) + fileType.getExtension();
// Add to file list.
files.add(new DownloadFile(name, streamedFile));
Expand All @@ -252,8 +259,9 @@ public DownloadFile exportObservations(
}
} else {
List<Map<String, Object>> exportRows = new ArrayList<>(rowByOUId.values());
sortDefaultForExportRows(exportRows);
// write export data to requested file format
StreamedFile streamedFile = writeToStreamedFile(columns, exportRows, fileType, "Experiment Data");
StreamedFile streamedFile = writeToStreamedFile(columns, exportRows, fileType, SHEET_NAME);
// Set filename.
String envFilenameFragment = params.getEnvironments() == null ? "All Environments" : params.getEnvironments();
String fileName = makeFileName(experiment, program, envFilenameFragment) + fileType.getExtension();
Expand Down Expand Up @@ -308,6 +316,7 @@ public Dataset getDatasetData(Program program, UUID experimentId, UUID datsetId,
log.debug("fetching observations for dataset: " + datsetId);
List<BrAPIObservation> data = observationDAO.getObservationsByObservationUnitsAndVariables(ouDbIds, obsVarDbIds, program);
log.debug("building dataset object for dataset: " + datsetId);
sortDefaultForObservationUnit(datasetOUs);
Dataset dataset = new Dataset(experimentId.toString(), data, datasetOUs, datasetObsVars);
if (stats) {
Integer ouCount = datasetOUs.size();
Expand Down Expand Up @@ -551,4 +560,17 @@ private List<BrAPIObservation> filterDatasetByEnvironment(
.collect(Collectors.toList());
}

}
private void sortDefaultForObservationUnit(List<BrAPIObservationUnit> ous) {
Comparator<BrAPIObservationUnit> studyNameComparator = Comparator.comparing(BrAPIObservationUnit::getStudyName, new IntOrderComparator());
Comparator<BrAPIObservationUnit> ouNameComparator = Comparator.comparing(BrAPIObservationUnit::getObservationUnitName, new IntOrderComparator());
ous.sort( (studyNameComparator).thenComparing(ouNameComparator));
}

private void sortDefaultForExportRows(@NotNull List<Map<String, Object>> exportRows) {
Comparator<Map<String, Object>> envComparator = Comparator.comparing(row -> (row.get(Columns.ENV).toString()), new IntOrderComparator());
Comparator<Map<String, Object>> expUnitIdComparator =
Comparator.comparing(row -> (row.get(Columns.EXP_UNIT_ID).toString()), new IntOrderComparator());

exportRows.sort(envComparator.thenComparing(expUnitIdComparator));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.breedinginsight.utilities;

import java.math.BigInteger;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
If you have text(optional), followed by some digits(optional), followed by more text(optional), this Comparator
will sort the digits in numeric order. The trailing text (and any subsequent digits) will be in
alpha-numeric order.

In other words; this comparator will assume that strings being compared are comprised of a text _prefix_, followed by
_digits_, followed by a _suffix_.

This comparator will fist compare the prefix as an alpha-numeric, the digits as a numeric and
then the the suffix as an alpha-numeric.
For Example:
1) if a string is 'big4team', then prefix='big', digits=4, suffix='team'
2) if a string is '12monkeys', then prefix='', digits=12, suffix='monkeys'
3) if a string is 'abcd', then prefix='abcd', digits=null, suffix=''
4) if a string is 'libnum14.3', then prefix='libnum', digits=14, suffix='.4'
*/
public class IntOrderComparator implements Comparator<String> {
@Override
public int compare(String str1, String str2) {
//static finals to make the Matcher::group code more readable
final int PREFIX = 1;
final int DIGITS = 2;
final int SUFFIX = 3;

// convert null strings to blank
str1 = (str1 == null) ? "" : str1;
str2 = (str2 == null) ? "" : str2;

//The real work begins

// NOTE: The last group includes all remaining text and digits
Pattern p = Pattern.compile("^([^\\d]*)(\\d*)(.*)$");

Matcher m1 = p.matcher(str1);
Matcher m2 = p.matcher(str2);

m1.find(); // needed to let m1.group() work
m2.find(); // needed to let m2.group() work

String prefix1 = m1.group(PREFIX);
String prefix2 = m2.group(PREFIX);
BigInteger digits1 = m1.group(DIGITS).length() > 0 ? new BigInteger(m1.group(DIGITS)) : null;
BigInteger digits2 = m2.group(DIGITS).length() > 0 ? new BigInteger(m2.group(DIGITS)) : null;
String suffix1 = m1.group(SUFFIX);
String suffix2 = m2.group(SUFFIX);

if (!prefix1.equals(prefix2)) {
return prefix1.compareTo(prefix2);
}
/*if the prefixes are equal, sort by digits and suffixes.*/

// an empty digit is less than any digit (EX. 'a' is less than 'a1')
if( digits1 == null){
if(digits2 == null){
return 0; //if both digits are null (equal)
}
else {
return -1; //if there are no digits in str1 but digits in str2 (str1 < str2)
}
}
if( digits2 == null){
return 1; //if there are digits in str1 but no digits in str2 (str1 > str2)
}
if (!digits1.equals(digits2)) {
return digits1.compareTo(digits2);
}
/*if the prefixes and digits are equal, sort by suffixes.*/
if (!suffix1.equals(suffix2)) {
return suffix1.compareTo(suffix2);
}

/* if all else fails, compare the strings
(I think this will always return 0)*/
return str1.compareTo(str2);
}
}


Loading