Skip to content

Commit

Permalink
Created two examples as tests
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeByDrescher committed Jan 15, 2025
1 parent 7c095ac commit 683226a
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 7 deletions.
5 changes: 5 additions & 0 deletions vcell-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@
</exclusions>

</dependency>
<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
Expand Down
34 changes: 27 additions & 7 deletions vcell-core/src/main/java/cbit/vcell/publish/ITextWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.awt.print.PageFormat;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.imageio.IIOImage;
Expand Down Expand Up @@ -905,20 +905,40 @@ protected void createDocument(PageFormat pageFormat) {
this.document = new Document(pageSize, (float) marginL, (float) marginR, (float) marginT, (float) marginB);
}

public void writePlotImageDocument(String docTitle, FileOutputStream fos, PageFormat pageFormat, BufferedImage... plotImages) throws DocumentException, IOException {
if (plotImages == null) throw new IllegalArgumentException("No plot images provided");
if (fos == null) throw new IllegalArgumentException("No outputstream for plot-document provided");
if (pageFormat == null) throw new IllegalArgumentException("No page format provided");

this.createDocument(pageFormat);
this.createDocWriter(fos);
this.document.addTitle(docTitle);
this.document.addCreator("Virtual Cell");
this.document.addCreationDate();
this.document.open();
for (BufferedImage plotImage : plotImages){
com.lowagie.text.Image image = com.lowagie.text.Image.getInstance(plotImage, null);
image.setAlignment(Table.ALIGN_LEFT);
this.document.add(image);
if (this.document.getPageNumber() != plotImages.length) this.document.newPage();
}
this.document.close();
}


public void writeBioModel(BioModel biomodel, FileOutputStream fos, PageFormat pageFormat) throws Exception {
public void writeBioModel(BioModel biomodel, FileOutputStream fos, PageFormat pageFormat) throws DocumentException {

writeBioModel(biomodel, fos, pageFormat, PublishPreferences.DEFAULT_BIO_PREF);
}


public void writeBioModel(BioModel bioModel, FileOutputStream fos, PageFormat pageFormat, PublishPreferences preferences) throws Exception {
public void writeBioModel(BioModel bioModel, FileOutputStream fos, PageFormat pageFormat, PublishPreferences preferences) throws DocumentException {

if (bioModel == null || fos == null || pageFormat == null || preferences == null) {
throw new IllegalArgumentException("One or more null params while publishing BioModel.");
}
createDocument(pageFormat);
createDocWriter(fos);
this.createDocument(pageFormat);
this.createDocWriter(fos);
// Add metadata before you open the document...
String name = bioModel.getName().trim();
String userName = "Unknown";
Expand Down Expand Up @@ -2079,7 +2099,7 @@ protected void writeSimulation(Section container, Simulation sim) throws Documen

//SimulationContext: ignored the constraints (steady/unsteady).
//Electrical Stimulus: ignored the Ground Electrode,
protected void writeSimulationContext(Chapter simContextsChapter, SimulationContext simContext, PublishPreferences preferences) throws Exception {
protected void writeSimulationContext(Chapter simContextsChapter, SimulationContext simContext, PublishPreferences preferences) throws DocumentException {

Section simContextSection = simContextsChapter.addSection("Application: " + simContext.getName(), simContextsChapter.getNumberDepth() + 1);
writeMetadata(simContextSection, simContext.getName(), simContext.getDescription(), null, "Application ");
Expand Down
67 changes: 67 additions & 0 deletions vcell-core/src/main/java/org/vcell/plotting/Results2DLinePlot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.vcell.plotting;

import java.io.File;

/**
* Stores all relevant info to create a 2D plot, and lazily builds a PDF on request
*/
public class Results2DLinePlot implements ResultsLinePlot {
private String plotTitle;
private double[] xData, yData;
private String xLabel, yLabel;

public Results2DLinePlot(){
this.plotTitle = "";
this.xData = new double[0];
this.yData = new double[0];
this.xLabel = "";
this.yLabel = "";
}

@Override
public void setTitle(String newTitle) {
this.plotTitle = newTitle;
}

@Override
public String getTitle() {
return this.plotTitle;
}

public void setXData(double[] newXData){
this.xData = newXData;
}

public double[] getXData(){
return this.xData;
}

public void setYData(double[] newYData){
this.yData = newYData;
}

public double[] getYData(){
return this.yData;
}

public void setXLabel(String newXLabel){
this.xLabel = newXLabel;
}

public String getXLabel(){
return this.xLabel;
}

public void setYLabel(String newYLabel){
this.yLabel = newYLabel;
}

public String getYLabel(){
return this.yLabel;
}

@Override
public void generatePdf(String desiredFileName, File desiredParentDirectory) {

}
}
29 changes: 29 additions & 0 deletions vcell-core/src/main/java/org/vcell/plotting/ResultsLinePlot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.vcell.plotting;

import java.io.File;

/**
* Describes the basic functionality all LinePlots displaying simulation results should have.
*/
public interface ResultsLinePlot {

/**
* Generates a PDF copy of the current plot state, and exports it as PDF at the desired location.
* @param desiredFileName name of the plot file; needs no file suffix: ".pdf" will be appended.
* @param desiredParentDirectory directory to place the new pdf into.
*/
void generatePdf(String desiredFileName, File desiredParentDirectory);

/**
* Setter for the title of the plot
* @param newTitle the desired new title as a String
*/
void setTitle(String newTitle);

/**
* Getter for the title of the plot
* @return the title as a String
*/
String getTitle();

}
149 changes: 149 additions & 0 deletions vcell-core/src/test/java/org/vcell/plotting/TestJFreeChartLibrary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package org.vcell.plotting;

import cbit.vcell.publish.PDFWriter;
import com.lowagie.text.DocumentException;
import org.jfree.chart.*;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.*;
import org.jfree.data.xy.*;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DefaultKeyedValues2DDataset;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.vcell.sbml.BMDB_SBML_Files;
import org.vcell.util.Pair;
import scala.collection.immutable.Page;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;


@Tag("Fast")
public class TestJFreeChartLibrary {

private static List<XYDataItem> testData = List.of(
new XYDataItem(0.0, 0.0),
new XYDataItem(0.5, 0.25),
new XYDataItem(1.0, 1.0),
new XYDataItem(1.5, 2.25),
new XYDataItem(2.0, 4.0),
new XYDataItem(2.5, 6.25),
new XYDataItem(3.0, 9.0),
new XYDataItem(3.5, 12.25),
new XYDataItem(4.0, 16.0),
new XYDataItem(4.5, 20.25),
new XYDataItem(5.0, 25.0),
new XYDataItem(5.5, 30.25)
);

@Test
public void testDirectChartCreation() throws IOException, DocumentException {
PageFormat pageFormat = TestJFreeChartLibrary.generateAlternatePageFormat();

// Build Chart
XYSeries xySeries = new XYSeries("Ka+", true, false); // The "key" field is what to name the curve itself, when shown in a Legend
for (XYDataItem valuePair: TestJFreeChartLibrary.testData){
xySeries.add(valuePair);
}
XYDataset dataset2D = new XYSeriesCollection(xySeries);
this.generateChart(dataset2D, pageFormat, "Time");
}

@Test
public void testDirectChartCreationFromCSV() throws IOException, DocumentException {
PageFormat pageFormat = TestJFreeChartLibrary.generateAlternatePageFormat();
Pair<String, XYDataset> datasetPair = TestJFreeChartLibrary.csvToXYDataset();
this.generateChart(datasetPair.two, pageFormat, datasetPair.one);
}

private void generateChart(XYDataset dataset2D, PageFormat pageFormat, String xAxisLabel) throws IOException, DocumentException {
int AXIS_LABEL_FONT_SIZE = 15;
String yAxisLabel = "";
JFreeChart chart = ChartFactory.createXYLineChart("Test Sim Results", xAxisLabel, yAxisLabel, dataset2D);

// Tweak Chart so it looks better
chart.setBorderVisible(true);
XYPlot chartPlot = chart.getXYPlot();
chartPlot.getDomainAxis().setLabelFont(new Font(xAxisLabel, Font.PLAIN, AXIS_LABEL_FONT_SIZE));
chartPlot.getRangeAxis().setLabelFont(new Font(yAxisLabel, Font.PLAIN, AXIS_LABEL_FONT_SIZE));
if (dataset2D.getItemCount(0) <= 10) { // if it's too crowded, having data point labels is bad
for (int i = 0; i < dataset2D.getSeriesCount(); i++){
//DecimalFormat decimalformat1 = new DecimalFormat("##");
chartPlot.getRenderer().setSeriesItemLabelGenerator(0,
new StandardXYItemLabelGenerator("({1}, {2})"));
chartPlot.getRenderer().setSeriesItemLabelFont(i, new Font(null, Font.PLAIN, 8));
chartPlot.getRenderer().setSeriesItemLabelsVisible(i, true);
}
}

// Prepare for export
PDFWriter pdfWriter = new PDFWriter();

File testfile = File.createTempFile("VCell::TestJFreeChartLibrary::testDirectChartCreation::", ".pdf");
if (!testfile.exists()) throw new IllegalArgumentException("Unable to create the testfile, somehow.");
try (FileOutputStream fos = new FileOutputStream(testfile)){
BufferedImage bfi = chart.createBufferedImage((int)pageFormat.getImageableWidth(), (int)pageFormat.getImageableHeight());
pdfWriter.writePlotImageDocument("Test Document", fos, pageFormat, bfi);
}
}

private static PageFormat generateAlternatePageFormat(){
java.awt.print.PageFormat pageFormat = java.awt.print.PrinterJob.getPrinterJob().defaultPage();
Paper alternatePaper = new Paper(); // We want to try and increase the margins
double altOriginX = alternatePaper.getImageableX() / 2, altOriginY = alternatePaper.getImageableY() / 2;
double altWidth = alternatePaper.getWidth() - 2 * altOriginX, altHeight = alternatePaper.getHeight() - 2 * altOriginY;
alternatePaper.setImageableArea(altOriginX, altOriginY, altWidth, altHeight);
pageFormat.setPaper(alternatePaper);
pageFormat.setOrientation(PageFormat.LANDSCAPE);
return pageFormat;
}

private static Pair<String, XYDataset> csvToXYDataset() throws IOException {
String CSV_DATA_FILE_LOCAL_PATH = "plot2d_SimpleSimulation.csv";
InputStream inputStream = TestJFreeChartLibrary.class.getResourceAsStream(CSV_DATA_FILE_LOCAL_PATH);
if (inputStream == null)
throw new FileNotFoundException(String.format("can not find `%s`; maybe it moved?", CSV_DATA_FILE_LOCAL_PATH));
XYSeriesCollection dataset2D = new XYSeriesCollection();
List<String> linesOfData;
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))){
linesOfData = br.lines().toList();
}
String[] indepDataParts = linesOfData.get(linesOfData.size() - 1).split(",");
List<Double> xSeriesData = new ArrayList<>();
for (int partNum = 3; partNum < indepDataParts.length; partNum++){ // Skip first three; no need for them
xSeriesData.add(Double.parseDouble(indepDataParts[partNum]));
}

for (int lineNum = 0; lineNum < linesOfData.size() - 1; lineNum++){ // Skip last line; that's our independent-var data
XYSeries series = getXySeries(linesOfData, lineNum, xSeriesData);
dataset2D.addSeries(series);
}

return new Pair<>(indepDataParts[2], dataset2D);
}

private static XYSeries getXySeries(List<String> linesOfData, int lineNum, List<Double> xSeriesData) {
String[] parts = linesOfData.get(lineNum).split(",");
String ySeriesName = parts[2];
XYSeries series = new XYSeries(ySeriesName, true);
if (parts.length - 3 != xSeriesData.size()) throw new RuntimeException("Mismatched data length!");
for (int partNum = 3; partNum < parts.length; partNum++){ // Skip first two; third we've already grabbed
double xData = xSeriesData.get(partNum - 3), yData = Double.parseDouble(parts[partNum]);
series.add(xData, yData);
}
return series;
}
}
Loading

0 comments on commit 683226a

Please sign in to comment.