Skip to content

Commit

Permalink
Brought CSV Transpose to Java
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeByDrescher committed Jan 21, 2025
1 parent 2ba740d commit bc846c5
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 48 deletions.
3 changes: 1 addition & 2 deletions vcell-cli/src/main/java/org/vcell/cli/run/ExecuteImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@ public static void singleExecVcml(File vcmlFile, File outputDir, CLIRecordable c

for (String simName : resultsHash.keySet()) {
String CSVFilePath = Paths.get(outDirForCurrentVcml.toString(), simName + ".csv").toString();
RunUtils.createCSVFromODEResultSet(resultsHash.get(simName), new File(CSVFilePath));
PythonCalls.transposeVcmlCsv(CSVFilePath);
RunUtils.createCSVFromODEResultSet(resultsHash.get(simName), new File(CSVFilePath), true);
}
} catch (IOException e) {
Tracer.failure(e, "IOException while processing VCML " + vcmlFile.getName());
Expand Down
99 changes: 53 additions & 46 deletions vcell-cli/src/main/java/org/vcell/cli/run/RunUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.jlibsedml.*;
import org.jlibsedml.execution.IXPathToVariableIDResolver;
import org.jlibsedml.modelsupport.SBMLSupport;
import org.vcell.cli.CLIUtils;
import org.vcell.sbml.vcell.SBMLNonspatialSimResults;
import org.vcell.util.DataAccessException;
import org.vcell.util.GenericExtensionFilter;
Expand Down Expand Up @@ -511,75 +510,83 @@ public static boolean removeAndMakeDirs(File f) {
return true;
}

public static void createCSVFromODEResultSet(ODESolverResultSet resultSet, File f) throws ExpressionException {
public static void createCSVFromODEResultSet(ODESolverResultSet resultSet, File f, boolean shouldTranspose) throws ExpressionException {
ColumnDescription[] descriptions = resultSet.getColumnDescriptions();
StringBuilder sb = new StringBuilder();


int numberOfColumns = descriptions.length;
int numberOfRows = resultSet.getRowCount();
Map<String, List<Double>> resultsMapping = new LinkedHashMap<>();

double[][] dataPoints = new double[numberOfColumns][];
// Write headers
for (ColumnDescription description : descriptions) {
sb.append(description.getDisplayName());
sb.append(",");
for (int i = 0; i < descriptions.length; i++){
resultsMapping.put(descriptions[i].getDisplayName(), Arrays.stream(resultSet.extractColumn(i)).boxed().toList());
}
sb.deleteCharAt(sb.lastIndexOf(","));
sb.append("\n");

try (PrintWriter out = new PrintWriter(f)) {
out.print(RunUtils.formatCSVContents(resultsMapping, !shouldTranspose));
out.flush();
} catch (FileNotFoundException e) {
logger.error("Unable to find path, failed with err: " + e.getMessage(), e);
}
}

// Write rows
for (int i = 0; i < numberOfColumns; i++) {
dataPoints[i] = resultSet.extractColumn(i);
public static <T> String formatCSVContents(Map<String, List<T>> csvContents, boolean organizeDataVertically){
if (!(csvContents instanceof LinkedHashMap<String, List<T>>))
logger.warn("Warning; using a non-linked hash map will result in random ordering of lines!");
List<List<String>> csvLines = new ArrayList<>();
int numTopics = csvContents.size();
int maxNumValuesPerTopic = 0;
for (List<T> values : csvContents.values())
if (values.size() > maxNumValuesPerTopic)
maxNumValuesPerTopic = values.size();

// Initialize with empties
for (int i = 0; i < (organizeDataVertically ? maxNumValuesPerTopic + 1 : numTopics); i++){
csvLines.add(new ArrayList<>());
}

for (int rowNum = 0; rowNum < numberOfRows; rowNum++) {
for (int colNum = 0; colNum < numberOfColumns; colNum++) {
sb.append(dataPoints[colNum][rowNum]);
sb.append(",");
// Fill out lines
List<String> topics = new ArrayList<>(csvContents.keySet());
if (organizeDataVertically){
for (String topic : topics) csvLines.get(0).add(topic);
} else {
for (int topicNum = 0; topicNum < topics.size(); topicNum++){
csvLines.get(topicNum).add(topics.get(topicNum));
}
}
for (int topicNum = 0; topicNum < topics.size(); topicNum++){
String topic = topics.get(topicNum);
List<T> data = csvContents.get(topic);

sb.deleteCharAt(sb.lastIndexOf(","));
sb.append("\n");
for (int i = 0; i < maxNumValuesPerTopic; i++){
String value = i < data.size() ? data.get(i).toString() : "";
csvLines.get(organizeDataVertically ? i + 1 : topicNum).add(value);
}
}

PrintWriter out = null;
try {
out = new PrintWriter(f);
out.print(sb.toString());
out.flush();
} catch (FileNotFoundException e) {
logger.error("Unable to find path, failed with err: " + e.getMessage(), e);
} finally {
if (out != null) out.close();
// Build CSV
StringBuilder sb = new StringBuilder();
for (List<String> row : csvLines){
for (String value : row){
sb.append(value).append(",");
}
sb.deleteCharAt(sb.lastIndexOf(",")).append("\n");
}

return sb.deleteCharAt(sb.lastIndexOf("\n")).toString();
}

@SuppressWarnings({"ConstantConditions", "ResultOfMethodCallIgnored"})
public static void removeIntermediarySimFiles(File path) {
if (!path.isDirectory()) throw new IllegalArgumentException("Provided path does not lead to a directory!");
File[] files = path.listFiles();
for (File f : files) {
if (f.getName().endsWith(".csv")) {
// Do nothing
continue;
} else {
f.delete();
}
if (f.getName().endsWith(".csv")) continue;
f.delete();
}
}

@SuppressWarnings("ConstantConditions")
public static boolean containsExtension(String folder, String ext) {
GenericExtensionFilter filter = new GenericExtensionFilter(ext);
File dir = new File(folder);
if (dir.isDirectory() == false) {
return false;
}
String[] list = dir.list(filter);
if (list.length > 0) {
return true;
}
return false;
return dir.isDirectory() && dir.list(filter).length > 0;
}

private static List<String> getListOfVariableNames(DataIdentifier... dataIDArr){
Expand Down
34 changes: 34 additions & 0 deletions vcell-cli/src/test/java/org/vcell/cli/run/RunUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.vcell.cli.run;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Tag("Fast")
public class RunUtilsTest {
private final String VERTICAL_CSV = """
Street-based,Sea-based,Snow-based
Skateboard,Wake Board,Snowboard
Rollerblades,Water Skis,Alpine / Cross-country Skis
Bike,Water Bike,<None>
Motorcycle,Boatercycle (Jet-Ski),Snow Bike / Snowmobile""";
private final String HORIZONTAL_CSV = """
Street-based,Skateboard,Rollerblades,Bike,Motorcycle
Sea-based,Wake Board,Water Skis,Water Bike,Boatercycle (Jet-Ski)
Snow-based,Snowboard,Alpine / Cross-country Skis,<None>,Snow Bike / Snowmobile""";

@Test
public void testCSVFormatting(){
Map<String, List<String>> csvContents = new LinkedHashMap<>();
csvContents.put("Street-based", List.of("Skateboard", "Rollerblades", "Bike", "Motorcycle"));
csvContents.put("Sea-based", List.of("Wake Board", "Water Skis", "Water Bike", "Boatercycle (Jet-Ski)"));
csvContents.put("Snow-based", List.of("Snowboard", "Alpine / Cross-country Skis", "<None>", "Snow Bike / Snowmobile"));
Assertions.assertEquals(VERTICAL_CSV, RunUtils.formatCSVContents(csvContents, true));
Assertions.assertEquals(HORIZONTAL_CSV, RunUtils.formatCSVContents(csvContents, false));
}
}

0 comments on commit bc846c5

Please sign in to comment.