3506 |
23 Sep 15 |
nicklas |
1 |
package net.sf.basedb.reggie.pdf; |
3506 |
23 Sep 15 |
nicklas |
2 |
|
3535 |
08 Oct 15 |
nicklas |
3 |
import java.io.BufferedReader; |
3506 |
23 Sep 15 |
nicklas |
4 |
import java.io.File; |
3506 |
23 Sep 15 |
nicklas |
5 |
import java.io.FileInputStream; |
3506 |
23 Sep 15 |
nicklas |
6 |
import java.io.IOException; |
3533 |
08 Oct 15 |
nicklas |
7 |
import java.io.InputStream; |
3542 |
14 Oct 15 |
nicklas |
8 |
import java.io.InputStreamReader; |
3506 |
23 Sep 15 |
nicklas |
9 |
import java.io.OutputStream; |
3525 |
05 Oct 15 |
nicklas |
10 |
import java.text.DecimalFormat; |
3525 |
05 Oct 15 |
nicklas |
11 |
import java.text.DecimalFormatSymbols; |
3525 |
05 Oct 15 |
nicklas |
12 |
import java.text.NumberFormat; |
3506 |
23 Sep 15 |
nicklas |
13 |
import java.util.Date; |
3525 |
05 Oct 15 |
nicklas |
14 |
import java.util.HashMap; |
3525 |
05 Oct 15 |
nicklas |
15 |
import java.util.List; |
3506 |
23 Sep 15 |
nicklas |
16 |
import java.util.Map; |
3533 |
08 Oct 15 |
nicklas |
17 |
import java.util.regex.Pattern; |
3506 |
23 Sep 15 |
nicklas |
18 |
|
7024 |
07 Feb 23 |
nicklas |
19 |
import org.apache.commons.lang3.time.FastDateFormat; |
7024 |
07 Feb 23 |
nicklas |
20 |
|
3506 |
23 Sep 15 |
nicklas |
21 |
import net.sf.basedb.core.BioMaterial; |
3506 |
23 Sep 15 |
nicklas |
22 |
import net.sf.basedb.core.BioSource; |
3506 |
23 Sep 15 |
nicklas |
23 |
import net.sf.basedb.core.DbControl; |
3525 |
05 Oct 15 |
nicklas |
24 |
import net.sf.basedb.core.Extract; |
4537 |
21 Jun 17 |
nicklas |
25 |
import net.sf.basedb.core.RawBioAssay; |
3506 |
23 Sep 15 |
nicklas |
26 |
import net.sf.basedb.core.Sample; |
6031 |
29 Oct 20 |
nicklas |
27 |
import net.sf.basedb.core.plugin.ExportOutputStream; |
3506 |
23 Sep 15 |
nicklas |
28 |
import net.sf.basedb.reggie.Reggie; |
3506 |
23 Sep 15 |
nicklas |
29 |
import net.sf.basedb.reggie.Site; |
3506 |
23 Sep 15 |
nicklas |
30 |
import net.sf.basedb.reggie.converter.DateToStringConverter; |
3506 |
23 Sep 15 |
nicklas |
31 |
import net.sf.basedb.reggie.dao.Annotationtype; |
3506 |
23 Sep 15 |
nicklas |
32 |
import net.sf.basedb.reggie.dao.Rawbioassay; |
3525 |
05 Oct 15 |
nicklas |
33 |
import net.sf.basedb.reggie.dao.Rna; |
3525 |
05 Oct 15 |
nicklas |
34 |
import net.sf.basedb.reggie.dao.RnaQc; |
3506 |
23 Sep 15 |
nicklas |
35 |
import net.sf.basedb.reggie.dao.Subtype; |
6060 |
17 Nov 20 |
nicklas |
36 |
import net.sf.basedb.reggie.pdf.PdfUtil7.Align; |
6070 |
20 Nov 20 |
nicklas |
37 |
import net.sf.basedb.reggie.pdf.PdfUtil7.Options; |
6035 |
29 Oct 20 |
nicklas |
38 |
import net.sf.basedb.reggie.script.PilotReport; |
6036 |
02 Nov 20 |
nicklas |
39 |
import net.sf.basedb.reggie.script.ScriptResult; |
3533 |
08 Oct 15 |
nicklas |
40 |
import net.sf.basedb.util.FileUtil; |
3525 |
05 Oct 15 |
nicklas |
41 |
import net.sf.basedb.util.MD5; |
3533 |
08 Oct 15 |
nicklas |
42 |
import net.sf.basedb.util.parser.FlatFileParser; |
3533 |
08 Oct 15 |
nicklas |
43 |
import net.sf.basedb.util.parser.Mapper; |
3506 |
23 Sep 15 |
nicklas |
44 |
|
3506 |
23 Sep 15 |
nicklas |
45 |
/** |
3506 |
23 Sep 15 |
nicklas |
Worker implementation that runs the 'PilotReport' R script and |
3506 |
23 Sep 15 |
nicklas |
generates a PDF document with the plots and other information. |
3506 |
23 Sep 15 |
nicklas |
48 |
|
3506 |
23 Sep 15 |
nicklas |
@author nicklas |
3506 |
23 Sep 15 |
nicklas |
@since 3.7 |
3506 |
23 Sep 15 |
nicklas |
51 |
*/ |
3506 |
23 Sep 15 |
nicklas |
52 |
public class PilotReportWorker |
3506 |
23 Sep 15 |
nicklas |
53 |
extends PdfReportWorker |
3506 |
23 Sep 15 |
nicklas |
54 |
{ |
3506 |
23 Sep 15 |
nicklas |
55 |
|
3506 |
23 Sep 15 |
nicklas |
56 |
/** |
3506 |
23 Sep 15 |
nicklas |
The default file name for the generated pdf. |
3506 |
23 Sep 15 |
nicklas |
58 |
*/ |
3506 |
23 Sep 15 |
nicklas |
59 |
public static final String DEFAULT_PDF_NAME = "pilotreport.pdf"; |
3506 |
23 Sep 15 |
nicklas |
60 |
|
3506 |
23 Sep 15 |
nicklas |
61 |
public static final DateToStringConverter DATE_FORMAT = |
7024 |
07 Feb 23 |
nicklas |
62 |
new DateToStringConverter(FastDateFormat.getInstance("yyyy-MM-dd")); |
3506 |
23 Sep 15 |
nicklas |
63 |
|
3525 |
05 Oct 15 |
nicklas |
64 |
private static final float MARGIN_RIGHT = 579; |
3525 |
05 Oct 15 |
nicklas |
65 |
private static final float MARGIN_LEFT = 14; |
3506 |
23 Sep 15 |
nicklas |
66 |
|
3525 |
05 Oct 15 |
nicklas |
/* TEXT POSITIONS */ |
3525 |
05 Oct 15 |
nicklas |
// Left X of text columns |
3525 |
05 Oct 15 |
nicklas |
69 |
private static final float TEXT_X1 = 99; |
3525 |
05 Oct 15 |
nicklas |
70 |
private static final float TEXT_X2 = 191; |
3525 |
05 Oct 15 |
nicklas |
71 |
private static final float TEXT_X3 = 283; |
3525 |
05 Oct 15 |
nicklas |
72 |
private static final float TEXT_X4 = 404; |
3525 |
05 Oct 15 |
nicklas |
73 |
private static final float TEXT_X5 = 495; |
3506 |
23 Sep 15 |
nicklas |
74 |
|
3525 |
05 Oct 15 |
nicklas |
// Bottom Y of text rows |
3525 |
05 Oct 15 |
nicklas |
76 |
private static final float TEXT_Y1 = 801; |
3525 |
05 Oct 15 |
nicklas |
77 |
private static final float TEXT_Y2 = 773; |
3525 |
05 Oct 15 |
nicklas |
78 |
private static final float TEXT_Y3 = 746; |
3525 |
05 Oct 15 |
nicklas |
79 |
private static final float TEXT_Y4 = 718; |
3525 |
05 Oct 15 |
nicklas |
80 |
private static final float TEXT_Y5 = 690; |
3528 |
05 Oct 15 |
nicklas |
81 |
|
3528 |
05 Oct 15 |
nicklas |
// Molecular subtype box |
3528 |
05 Oct 15 |
nicklas |
83 |
private static final float SUBTYPE_Y1 = 616; |
3528 |
05 Oct 15 |
nicklas |
84 |
private static final float SUBTYPE_Y2 = 608; |
3528 |
05 Oct 15 |
nicklas |
85 |
private static final float SUBTYPE_X1 = 156; |
3528 |
05 Oct 15 |
nicklas |
86 |
private static final float SUBTYPE_X2 = 330; |
3528 |
05 Oct 15 |
nicklas |
87 |
private static final float SUBTYPE_XX = 50; |
3528 |
05 Oct 15 |
nicklas |
88 |
|
3528 |
05 Oct 15 |
nicklas |
/* PLOT POSITIONS */ |
3528 |
05 Oct 15 |
nicklas |
// Left X of plots |
3528 |
05 Oct 15 |
nicklas |
91 |
private static final float PLOT_X = 355; |
3528 |
05 Oct 15 |
nicklas |
// Bottom Y of first plot |
3556 |
21 Oct 15 |
nicklas |
93 |
private static final float PLOT_START_Y = 503f; |
3528 |
05 Oct 15 |
nicklas |
// Distance between plots |
3556 |
21 Oct 15 |
nicklas |
95 |
private static final float PLOT_DELTA_Y = 98.5f; |
3528 |
05 Oct 15 |
nicklas |
// Size of plots |
3528 |
05 Oct 15 |
nicklas |
97 |
private static final float PLOT_WIDTH = 160; |
3528 |
05 Oct 15 |
nicklas |
98 |
private static final float PLOT_HEIGHT = 80; |
3528 |
05 Oct 15 |
nicklas |
// Text releated to plot |
3556 |
21 Oct 15 |
nicklas |
100 |
private static final float PLOT_TEXT_X = 205; |
3556 |
21 Oct 15 |
nicklas |
101 |
private static final float PLOT_TEXT_START_Y = 540.5f; |
3528 |
05 Oct 15 |
nicklas |
102 |
|
3506 |
23 Sep 15 |
nicklas |
103 |
private PilotReport script; |
3620 |
24 Nov 15 |
nicklas |
104 |
private final String config; |
3620 |
24 Nov 15 |
nicklas |
105 |
private final String parameterSet; |
3506 |
23 Sep 15 |
nicklas |
106 |
private String pdfTemplatePath; |
3525 |
05 Oct 15 |
nicklas |
107 |
private Map<String, String> translations; |
3525 |
05 Oct 15 |
nicklas |
108 |
private NumberFormat oneDecimal; |
3525 |
05 Oct 15 |
nicklas |
109 |
private NumberFormat twoDecimals; |
3506 |
23 Sep 15 |
nicklas |
110 |
|
3620 |
24 Nov 15 |
nicklas |
111 |
PilotReportWorker(PdfReportTemplate template, String config, String parameterSet) |
3506 |
23 Sep 15 |
nicklas |
112 |
{ |
3506 |
23 Sep 15 |
nicklas |
113 |
super(template); |
3506 |
23 Sep 15 |
nicklas |
114 |
this.config = config; |
3620 |
24 Nov 15 |
nicklas |
115 |
this.parameterSet = parameterSet; |
3506 |
23 Sep 15 |
nicklas |
116 |
} |
3506 |
23 Sep 15 |
nicklas |
117 |
|
3506 |
23 Sep 15 |
nicklas |
118 |
/** |
3506 |
23 Sep 15 |
nicklas |
Run the gene report script for the given raw bioassay and then |
3506 |
23 Sep 15 |
nicklas |
create the pdf. |
3506 |
23 Sep 15 |
nicklas |
121 |
*/ |
3506 |
23 Sep 15 |
nicklas |
122 |
@Override |
6036 |
02 Nov 20 |
nicklas |
123 |
public ScriptResult runAndCreatePdf(DbControl dc, Rawbioassay raw, ExportOutputStream out, ReportOptions options) |
3506 |
23 Sep 15 |
nicklas |
124 |
throws IOException |
3506 |
23 Sep 15 |
nicklas |
125 |
{ |
3506 |
23 Sep 15 |
nicklas |
126 |
if (script == null) |
3506 |
23 Sep 15 |
nicklas |
127 |
{ |
3506 |
23 Sep 15 |
nicklas |
// Initialize script in the first call to this method |
3620 |
24 Nov 15 |
nicklas |
129 |
script = new PilotReport(config, parameterSet); |
3620 |
24 Nov 15 |
nicklas |
130 |
pdfTemplatePath = Reggie.getConfig().getConfig(config+"/template", parameterSet, script.getScriptDir() + "/template.pdf"); |
3506 |
23 Sep 15 |
nicklas |
131 |
Reggie.checkFile(pdfTemplatePath, false); |
3525 |
05 Oct 15 |
nicklas |
132 |
oneDecimal = createNumberFormat(1); |
3525 |
05 Oct 15 |
nicklas |
133 |
twoDecimals = createNumberFormat(2); |
3506 |
23 Sep 15 |
nicklas |
134 |
} |
3506 |
23 Sep 15 |
nicklas |
135 |
PilotReport.Result result = script.run(dc, raw); |
3506 |
23 Sep 15 |
nicklas |
136 |
if (result.getExitStatus() == 0) |
3506 |
23 Sep 15 |
nicklas |
137 |
{ |
4537 |
21 Jun 17 |
nicklas |
138 |
toPdf(dc, result, out, options); |
3506 |
23 Sep 15 |
nicklas |
139 |
} |
3506 |
23 Sep 15 |
nicklas |
140 |
return result; |
3506 |
23 Sep 15 |
nicklas |
141 |
} |
3506 |
23 Sep 15 |
nicklas |
142 |
|
3506 |
23 Sep 15 |
nicklas |
143 |
|
4537 |
21 Jun 17 |
nicklas |
144 |
private void toPdf(DbControl dc, PilotReport.Result result, OutputStream out, ReportOptions options) |
3506 |
23 Sep 15 |
nicklas |
145 |
throws IOException |
3506 |
23 Sep 15 |
nicklas |
146 |
{ |
3506 |
23 Sep 15 |
nicklas |
147 |
Rawbioassay raw = result.raw; |
3506 |
23 Sep 15 |
nicklas |
148 |
|
3525 |
05 Oct 15 |
nicklas |
149 |
Map<Subtype, BioMaterial> parents = raw.findParentBioMaterial(dc, Subtype.PATIENT, Subtype.SPECIMEN, Subtype.CASE, Subtype.RNA); |
3525 |
05 Oct 15 |
nicklas |
150 |
Extract rna = (Extract)parents.get(Subtype.RNA); |
3506 |
23 Sep 15 |
nicklas |
151 |
Sample specimen = (Sample)parents.get(Subtype.SPECIMEN); |
3525 |
05 Oct 15 |
nicklas |
152 |
Sample theCase = (Sample)parents.get(Subtype.CASE); |
3506 |
23 Sep 15 |
nicklas |
153 |
BioSource patient = (BioSource)parents.get(Subtype.PATIENT); |
3525 |
05 Oct 15 |
nicklas |
154 |
Site site = Site.findByCaseName(raw.getName()); |
4537 |
21 Jun 17 |
nicklas |
155 |
RawBioAssay rba = raw.getRawBioAssay(); |
4537 |
21 Jun 17 |
nicklas |
156 |
Map<String, String> translations = new HashMap<>(); |
4537 |
21 Jun 17 |
nicklas |
157 |
translations.put("Hög", "High"); |
4537 |
21 Jun 17 |
nicklas |
158 |
translations.put("Låg", "Low"); |
4537 |
21 Jun 17 |
nicklas |
159 |
translations.put("Positiv", "Positive"); |
4537 |
21 Jun 17 |
nicklas |
160 |
translations.put("Negativ", "Negative"); |
3506 |
23 Sep 15 |
nicklas |
161 |
|
6060 |
17 Nov 20 |
nicklas |
162 |
PdfUtil7 pdfUtil = null; |
3506 |
23 Sep 15 |
nicklas |
163 |
try |
3506 |
23 Sep 15 |
nicklas |
164 |
{ |
6060 |
17 Nov 20 |
nicklas |
165 |
pdfUtil = new PdfUtil7("Pilot report: " + raw.getName(), result.getScript()); |
3506 |
23 Sep 15 |
nicklas |
166 |
pdfUtil.open(out); |
3506 |
23 Sep 15 |
nicklas |
167 |
|
6061 |
18 Nov 20 |
nicklas |
168 |
pdfUtil.importPdf(new FileInputStream(pdfTemplatePath), 1, 0, 0, Float.NaN, Float.NaN, Align.LEFT); |
3506 |
23 Sep 15 |
nicklas |
//pdfUtil.drawGrid(); |
3506 |
23 Sep 15 |
nicklas |
170 |
|
3506 |
23 Sep 15 |
nicklas |
// Patient and sample information |
3525 |
05 Oct 15 |
nicklas |
// Row 2 |
6070 |
20 Nov 20 |
nicklas |
173 |
if (patient != null) pdfUtil.addText(patient.getName(), 12, TEXT_X1, TEXT_Y2); |
6070 |
20 Nov 20 |
nicklas |
174 |
if (theCase != null) pdfUtil.addText(theCase.getName(), 12, TEXT_X2, TEXT_Y2); |
6070 |
20 Nov 20 |
nicklas |
175 |
if (specimen != null) pdfUtil.addText(specimen.getName(), 12, TEXT_X3, TEXT_Y2); |
3525 |
05 Oct 15 |
nicklas |
176 |
|
3525 |
05 Oct 15 |
nicklas |
// Row 3 |
3525 |
05 Oct 15 |
nicklas |
178 |
String consent = (String)Annotationtype.CONSENT.getAnnotationValue(dc, theCase); |
3525 |
05 Oct 15 |
nicklas |
179 |
Date consentDate = (Date)Annotationtype.CONSENT_DATE.getAnnotationValue(dc, theCase); |
6070 |
20 Nov 20 |
nicklas |
180 |
pdfUtil.addText(translate(consent), 12, TEXT_X1, TEXT_Y3); |
6070 |
20 Nov 20 |
nicklas |
181 |
pdfUtil.addText(DATE_FORMAT.convert(consentDate), 12, TEXT_X2, TEXT_Y3); |
3525 |
05 Oct 15 |
nicklas |
182 |
if (rna != null) |
3506 |
23 Sep 15 |
nicklas |
183 |
{ |
3525 |
05 Oct 15 |
nicklas |
184 |
List<RnaQc> rnaqc = RnaQc.findByRna(dc, Rna.get(rna)); |
3525 |
05 Oct 15 |
nicklas |
185 |
RnaQc lastRnaQc = RnaQc.findLast(dc, null, rnaqc); |
3525 |
05 Oct 15 |
nicklas |
186 |
if (lastRnaQc != null) |
3525 |
05 Oct 15 |
nicklas |
187 |
{ |
3525 |
05 Oct 15 |
nicklas |
188 |
Float rqs = (Float)Annotationtype.CA_RQS.getAnnotationValue(dc, lastRnaQc.getItem()); |
3525 |
05 Oct 15 |
nicklas |
189 |
Float rin = (Float)Annotationtype.BA_RIN.getAnnotationValue(dc, lastRnaQc.getItem()); |
3525 |
05 Oct 15 |
nicklas |
190 |
if (rqs != null || rin != null) |
3525 |
05 Oct 15 |
nicklas |
191 |
{ |
6070 |
20 Nov 20 |
nicklas |
192 |
pdfUtil.addText(oneDecimal.format((double)(rqs != null ? rqs : rin)), 12, TEXT_X3, TEXT_Y3); |
3525 |
05 Oct 15 |
nicklas |
193 |
} |
3525 |
05 Oct 15 |
nicklas |
194 |
} |
3506 |
23 Sep 15 |
nicklas |
195 |
} |
3506 |
23 Sep 15 |
nicklas |
196 |
|
3525 |
05 Oct 15 |
nicklas |
// Row 4 |
6070 |
20 Nov 20 |
nicklas |
198 |
pdfUtil.addText(DATE_FORMAT.convert((Date)Annotationtype.SAMPLING_DATETIME.getAnnotationValue(dc, specimen)), 12, TEXT_X1, TEXT_Y4); |
6070 |
20 Nov 20 |
nicklas |
199 |
pdfUtil.addText(DATE_FORMAT.convert((Date)Annotationtype.ARRIVAL_DATE.getAnnotationValue(dc, specimen)), 12, TEXT_X2, TEXT_Y4); |
6070 |
20 Nov 20 |
nicklas |
200 |
pdfUtil.addText(DATE_FORMAT.convert(new Date()), 12, TEXT_X3, TEXT_Y4); |
3525 |
05 Oct 15 |
nicklas |
201 |
|
3525 |
05 Oct 15 |
nicklas |
// Row 5 |
3525 |
05 Oct 15 |
nicklas |
203 |
String laterality = (String)Annotationtype.LATERALITY.getAnnotationValue(dc, specimen); |
6070 |
20 Nov 20 |
nicklas |
204 |
pdfUtil.addText(translate(laterality), 12, TEXT_X4, TEXT_Y5); |
6070 |
20 Nov 20 |
nicklas |
205 |
if (site != Site.UNKNOWN) pdfUtil.addText(site.getName(), 12, TEXT_X5, TEXT_Y5); |
3525 |
05 Oct 15 |
nicklas |
206 |
|
3533 |
08 Oct 15 |
nicklas |
// Molecular subtype information is found in the 'PAM50.txt' output file |
3533 |
08 Oct 15 |
nicklas |
208 |
File workDir = result.getWorkDir(); |
3533 |
08 Oct 15 |
nicklas |
209 |
String[] subtypeNames = { "LumA", "LumB", "Her2", "Basal", "Normal" }; |
3533 |
08 Oct 15 |
nicklas |
210 |
float[] subtypeScores = new float[subtypeNames.length]; |
4537 |
21 Jun 17 |
nicklas |
211 |
Annotationtype[] scoreTypes = { Annotationtype.PILOT_SCORE_LUMA, Annotationtype.PILOT_SCORE_LUMB, |
4537 |
21 Jun 17 |
nicklas |
212 |
Annotationtype.PILOT_SCORE_HER2, Annotationtype.PILOT_SCORE_BASAL, Annotationtype.PILOT_SCORE_NORMAL }; |
3533 |
08 Oct 15 |
nicklas |
213 |
String subtypeClass = parsePam50(new File(workDir, "PAM50.txt"), subtypeNames, subtypeScores); |
6070 |
20 Nov 20 |
nicklas |
214 |
pdfUtil.addText(subtypeClass, 14, SUBTYPE_X1, SUBTYPE_Y1); |
4537 |
21 Jun 17 |
nicklas |
215 |
|
4537 |
21 Jun 17 |
nicklas |
216 |
if (options.updateAnnotations()) |
4537 |
21 Jun 17 |
nicklas |
217 |
{ |
4537 |
21 Jun 17 |
nicklas |
218 |
Annotationtype.PILOT_SUBTYPE.setAnnotationValue(dc, rba, subtypeClass); |
4537 |
21 Jun 17 |
nicklas |
219 |
} |
4537 |
21 Jun 17 |
nicklas |
220 |
|
3543 |
14 Oct 15 |
nicklas |
// Find max score |
3543 |
14 Oct 15 |
nicklas |
222 |
float maxScore = subtypeScores[0]; |
3543 |
14 Oct 15 |
nicklas |
223 |
for (int scoreNo = 1; scoreNo < subtypeScores.length; scoreNo++) |
3543 |
14 Oct 15 |
nicklas |
224 |
{ |
3543 |
14 Oct 15 |
nicklas |
225 |
if (subtypeScores[scoreNo] > maxScore) maxScore = subtypeScores[scoreNo]; |
3543 |
14 Oct 15 |
nicklas |
226 |
} |
3543 |
14 Oct 15 |
nicklas |
// Print scores |
3533 |
08 Oct 15 |
nicklas |
228 |
for (int scoreNo = 0; scoreNo < subtypeScores.length; scoreNo++) |
3528 |
05 Oct 15 |
nicklas |
229 |
{ |
4537 |
21 Jun 17 |
nicklas |
230 |
if (options.updateAnnotations()) |
4537 |
21 Jun 17 |
nicklas |
231 |
{ |
4537 |
21 Jun 17 |
nicklas |
232 |
scoreTypes[scoreNo].setAnnotationValue(dc, rba, subtypeScores[scoreNo]); |
4537 |
21 Jun 17 |
nicklas |
233 |
} |
4537 |
21 Jun 17 |
nicklas |
234 |
|
3543 |
14 Oct 15 |
nicklas |
235 |
if (Float.compare(subtypeScores[scoreNo], maxScore) == 0) |
3528 |
05 Oct 15 |
nicklas |
236 |
{ |
6070 |
20 Nov 20 |
nicklas |
237 |
pdfUtil.addText(twoDecimals.format(subtypeScores[scoreNo]), 12, SUBTYPE_X2+scoreNo*SUBTYPE_XX, SUBTYPE_Y2, new Options().bold()); |
3528 |
05 Oct 15 |
nicklas |
238 |
} |
3528 |
05 Oct 15 |
nicklas |
239 |
else |
3528 |
05 Oct 15 |
nicklas |
240 |
{ |
6070 |
20 Nov 20 |
nicklas |
241 |
pdfUtil.addText(twoDecimals.format(subtypeScores[scoreNo]), 12, SUBTYPE_X2+scoreNo*SUBTYPE_XX, SUBTYPE_Y2); |
3528 |
05 Oct 15 |
nicklas |
242 |
} |
3528 |
05 Oct 15 |
nicklas |
243 |
} |
3528 |
05 Oct 15 |
nicklas |
244 |
|
3528 |
05 Oct 15 |
nicklas |
// Plots |
3535 |
08 Oct 15 |
nicklas |
246 |
float yPlot = PLOT_START_Y; |
3528 |
05 Oct 15 |
nicklas |
247 |
float yText = PLOT_TEXT_START_Y; |
3542 |
14 Oct 15 |
nicklas |
248 |
String[] plots = { "GGI.pdf", "ER_validationClass.pdf", "PR_validationClass.pdf", "ERBB2_validationClass.pdf", "KI67_validationClass.pdf" }; |
3542 |
14 Oct 15 |
nicklas |
249 |
String[] groups = { "GGI_group.txt", "ER_validationClass.txt", "PR_validationClass.txt", "ERBB2_validationClass.txt", "KI67_validationClass.txt" }; |
4537 |
21 Jun 17 |
nicklas |
250 |
Annotationtype[] groupTypes = { Annotationtype.PILOT_GGI, Annotationtype.PILOT_ER, Annotationtype.PILOT_PGR, Annotationtype.PILOT_HER2, Annotationtype.PILOT_KI67 }; |
3533 |
08 Oct 15 |
nicklas |
251 |
for (int plotNo = 0; plotNo < plots.length; plotNo++) |
3528 |
05 Oct 15 |
nicklas |
252 |
{ |
3542 |
14 Oct 15 |
nicklas |
253 |
File groupTxt = new File(workDir, groups[plotNo]); |
3542 |
14 Oct 15 |
nicklas |
254 |
String group = parseGroupTxt(groupTxt); |
4537 |
21 Jun 17 |
nicklas |
255 |
String translatedGroup = translations.containsKey(group) ? translations.get(group) : group; |
4537 |
21 Jun 17 |
nicklas |
256 |
if (options.updateAnnotations()) |
4537 |
21 Jun 17 |
nicklas |
257 |
{ |
4537 |
21 Jun 17 |
nicklas |
258 |
groupTypes[plotNo].setAnnotationValue(dc, rba, translatedGroup); |
4537 |
21 Jun 17 |
nicklas |
259 |
} |
6070 |
20 Nov 20 |
nicklas |
260 |
pdfUtil.addText(group == null ? "N/A" : group, 14, PLOT_TEXT_X, yText); |
3528 |
05 Oct 15 |
nicklas |
261 |
yText -= PLOT_DELTA_Y; |
3528 |
05 Oct 15 |
nicklas |
262 |
|
3542 |
14 Oct 15 |
nicklas |
263 |
File plotPdf = new File(workDir, plots[plotNo]); |
3535 |
08 Oct 15 |
nicklas |
264 |
if (plotPdf.exists()) |
3528 |
05 Oct 15 |
nicklas |
265 |
{ |
6061 |
18 Nov 20 |
nicklas |
266 |
pdfUtil.importPdf(new FileInputStream(plotPdf), 1, PLOT_X, yPlot, Float.NaN, Float.NaN, Align.LEFT); |
3528 |
05 Oct 15 |
nicklas |
267 |
} |
3535 |
08 Oct 15 |
nicklas |
268 |
yPlot -= PLOT_DELTA_Y; |
3528 |
05 Oct 15 |
nicklas |
269 |
} |
3528 |
05 Oct 15 |
nicklas |
270 |
|
3506 |
23 Sep 15 |
nicklas |
// Extra info at bottom |
6070 |
20 Nov 20 |
nicklas |
272 |
pdfUtil.addText(raw.getName(), 8, MARGIN_RIGHT, 10, Options.ALIGN_RIGHT); |
3506 |
23 Sep 15 |
nicklas |
273 |
} |
3506 |
23 Sep 15 |
nicklas |
274 |
finally |
3506 |
23 Sep 15 |
nicklas |
275 |
{ |
3506 |
23 Sep 15 |
nicklas |
276 |
if (pdfUtil != null) pdfUtil.close(); |
3506 |
23 Sep 15 |
nicklas |
277 |
} |
3533 |
08 Oct 15 |
nicklas |
278 |
} |
3533 |
08 Oct 15 |
nicklas |
279 |
|
3533 |
08 Oct 15 |
nicklas |
280 |
/** |
3533 |
08 Oct 15 |
nicklas |
The PAM50.txt file has one header line and one data line. |
3506 |
23 Sep 15 |
nicklas |
282 |
|
3533 |
08 Oct 15 |
nicklas |
@param pam50 The PAM50.txt file |
3533 |
08 Oct 15 |
nicklas |
@param subtypes Column headers in the file we are interested in |
3533 |
08 Oct 15 |
nicklas |
@param scores Output array for the scores found in the file. Must be |
3533 |
08 Oct 15 |
nicklas |
of same length as the subtypes array |
3533 |
08 Oct 15 |
nicklas |
@return The data value for the 'class' column |
3533 |
08 Oct 15 |
nicklas |
288 |
*/ |
3533 |
08 Oct 15 |
nicklas |
289 |
private String parsePam50(File pam50, String[] subtypes, float[] scores) |
3533 |
08 Oct 15 |
nicklas |
290 |
throws IOException |
3533 |
08 Oct 15 |
nicklas |
291 |
{ |
3533 |
08 Oct 15 |
nicklas |
292 |
FlatFileParser ffp = new FlatFileParser(); |
3533 |
08 Oct 15 |
nicklas |
293 |
ffp.setDataHeaderRegexp(Pattern.compile("class\\tnearest.*")); |
3533 |
08 Oct 15 |
nicklas |
294 |
ffp.setDataSplitterRegexp(Pattern.compile("\\t")); |
3533 |
08 Oct 15 |
nicklas |
295 |
InputStream in = null; |
3533 |
08 Oct 15 |
nicklas |
296 |
String subtypeClass = null; |
3533 |
08 Oct 15 |
nicklas |
297 |
try |
3533 |
08 Oct 15 |
nicklas |
298 |
{ |
3533 |
08 Oct 15 |
nicklas |
299 |
in = new FileInputStream(pam50); |
3533 |
08 Oct 15 |
nicklas |
300 |
ffp.setInputStream(in, "UTF-8"); |
3533 |
08 Oct 15 |
nicklas |
301 |
FlatFileParser.LineType line = ffp.parseHeaders(); |
3533 |
08 Oct 15 |
nicklas |
// Check that we have found the header and has data |
3533 |
08 Oct 15 |
nicklas |
303 |
if (line != FlatFileParser.LineType.DATA_HEADER) |
3533 |
08 Oct 15 |
nicklas |
304 |
{ |
3533 |
08 Oct 15 |
nicklas |
305 |
throw new IOException("Can't find data header in file: "+pam50); |
3533 |
08 Oct 15 |
nicklas |
306 |
} |
3533 |
08 Oct 15 |
nicklas |
307 |
FlatFileParser.Data data = ffp.nextData(); |
3533 |
08 Oct 15 |
nicklas |
308 |
if (data == null) |
3533 |
08 Oct 15 |
nicklas |
309 |
{ |
3533 |
08 Oct 15 |
nicklas |
310 |
throw new IOException("Can't find data line in file: "+pam50); |
3533 |
08 Oct 15 |
nicklas |
311 |
} |
3533 |
08 Oct 15 |
nicklas |
312 |
|
3533 |
08 Oct 15 |
nicklas |
// Get the subtype class |
3533 |
08 Oct 15 |
nicklas |
314 |
Mapper mapper = ffp.getMapper("\\class\\"); |
5364 |
16 Apr 19 |
nicklas |
315 |
subtypeClass = mapper.getString(data); |
3533 |
08 Oct 15 |
nicklas |
// Get subtype scores |
3533 |
08 Oct 15 |
nicklas |
317 |
for (int subtypeNo = 0; subtypeNo < subtypes.length; subtypeNo++) |
3533 |
08 Oct 15 |
nicklas |
318 |
{ |
3533 |
08 Oct 15 |
nicklas |
319 |
mapper = ffp.getMapper("\\"+subtypes[subtypeNo]+"\\"); |
3533 |
08 Oct 15 |
nicklas |
320 |
scores[subtypeNo] = mapper.getFloat(data); |
3533 |
08 Oct 15 |
nicklas |
321 |
} |
3533 |
08 Oct 15 |
nicklas |
322 |
} |
3533 |
08 Oct 15 |
nicklas |
323 |
finally |
3533 |
08 Oct 15 |
nicklas |
324 |
{ |
3533 |
08 Oct 15 |
nicklas |
325 |
FileUtil.close(in); |
3533 |
08 Oct 15 |
nicklas |
326 |
} |
3533 |
08 Oct 15 |
nicklas |
327 |
return subtypeClass; |
3506 |
23 Sep 15 |
nicklas |
328 |
} |
3506 |
23 Sep 15 |
nicklas |
329 |
|
3542 |
14 Oct 15 |
nicklas |
330 |
private String parseGroupTxt(File groupTxt) |
3535 |
08 Oct 15 |
nicklas |
331 |
throws IOException |
3535 |
08 Oct 15 |
nicklas |
332 |
{ |
3535 |
08 Oct 15 |
nicklas |
333 |
BufferedReader reader = null; |
3542 |
14 Oct 15 |
nicklas |
334 |
String group = null; |
3542 |
14 Oct 15 |
nicklas |
335 |
if (groupTxt.exists()) |
3535 |
08 Oct 15 |
nicklas |
336 |
{ |
3535 |
08 Oct 15 |
nicklas |
337 |
try |
3535 |
08 Oct 15 |
nicklas |
338 |
{ |
3542 |
14 Oct 15 |
nicklas |
339 |
reader = new BufferedReader(new InputStreamReader(new FileInputStream(groupTxt), "UTF-8")); |
3542 |
14 Oct 15 |
nicklas |
340 |
group = reader.readLine(); |
3535 |
08 Oct 15 |
nicklas |
341 |
} |
3535 |
08 Oct 15 |
nicklas |
342 |
finally |
3535 |
08 Oct 15 |
nicklas |
343 |
{ |
3535 |
08 Oct 15 |
nicklas |
344 |
FileUtil.close(reader); |
3535 |
08 Oct 15 |
nicklas |
345 |
} |
3535 |
08 Oct 15 |
nicklas |
346 |
} |
3542 |
14 Oct 15 |
nicklas |
347 |
return group; |
3535 |
08 Oct 15 |
nicklas |
348 |
} |
3535 |
08 Oct 15 |
nicklas |
349 |
|
3506 |
23 Sep 15 |
nicklas |
350 |
/** |
3506 |
23 Sep 15 |
nicklas |
Add personal information to the pilot report. |
3506 |
23 Sep 15 |
nicklas |
352 |
*/ |
3506 |
23 Sep 15 |
nicklas |
353 |
@Override |
6060 |
17 Nov 20 |
nicklas |
354 |
public void addPersonalInformation(DbControl dc, Rawbioassay raw, PdfUtil7 pdf) |
3506 |
23 Sep 15 |
nicklas |
355 |
throws IOException |
3506 |
23 Sep 15 |
nicklas |
356 |
{ |
3506 |
23 Sep 15 |
nicklas |
357 |
Map<Subtype, BioMaterial> parents = raw.findParentBioMaterial(dc, Subtype.SPECIMEN, Subtype.PATIENT); |
3506 |
23 Sep 15 |
nicklas |
358 |
BioSource patient = (BioSource)parents.get(Subtype.PATIENT); |
3525 |
05 Oct 15 |
nicklas |
359 |
Sample specimen = (Sample)parents.get(Subtype.SPECIMEN); |
3506 |
23 Sep 15 |
nicklas |
360 |
|
6070 |
20 Nov 20 |
nicklas |
361 |
pdf.addText(DATE_FORMAT.convert(new Date()), 8, MARGIN_LEFT, 10); |
3506 |
23 Sep 15 |
nicklas |
362 |
|
3506 |
23 Sep 15 |
nicklas |
363 |
if (patient != null) |
3506 |
23 Sep 15 |
nicklas |
364 |
{ |
6070 |
20 Nov 20 |
nicklas |
365 |
pdf.addText((String)Annotationtype.PERSONAL_NUMBER.getAnnotationValue(dc, patient), 12, TEXT_X4, TEXT_Y1); |
6070 |
20 Nov 20 |
nicklas |
366 |
pdf.addText((String)Annotationtype.FAMILY_NAME.getAnnotationValue(dc, patient), 12, TEXT_X4, TEXT_Y2); |
6070 |
20 Nov 20 |
nicklas |
367 |
pdf.addText((String)Annotationtype.ALL_FIRST_NAMES.getAnnotationValue(dc, patient), 12, TEXT_X4, TEXT_Y3); |
6070 |
20 Nov 20 |
nicklas |
368 |
pdf.addText((String)Annotationtype.PAD.getAnnotationValue(dc, specimen), 12, TEXT_X3, TEXT_Y5); |
3506 |
23 Sep 15 |
nicklas |
369 |
} |
3506 |
23 Sep 15 |
nicklas |
370 |
else |
3506 |
23 Sep 15 |
nicklas |
371 |
{ |
6070 |
20 Nov 20 |
nicklas |
372 |
pdf.addText("No patient information", 12, TEXT_X4, TEXT_Y1); |
3506 |
23 Sep 15 |
nicklas |
373 |
} |
3506 |
23 Sep 15 |
nicklas |
374 |
} |
3506 |
23 Sep 15 |
nicklas |
375 |
|
3525 |
05 Oct 15 |
nicklas |
376 |
private String translate(String word) |
3525 |
05 Oct 15 |
nicklas |
377 |
{ |
3525 |
05 Oct 15 |
nicklas |
378 |
if (word == null) return null; |
3525 |
05 Oct 15 |
nicklas |
379 |
if (translations == null) |
3525 |
05 Oct 15 |
nicklas |
380 |
{ |
3525 |
05 Oct 15 |
nicklas |
381 |
translations = new HashMap<String, String>(); |
3525 |
05 Oct 15 |
nicklas |
382 |
translations.put("left", "Vänster"); |
3525 |
05 Oct 15 |
nicklas |
383 |
translations.put("right", "Höger"); |
3525 |
05 Oct 15 |
nicklas |
384 |
translations.put("yes", "Ja"); |
3525 |
05 Oct 15 |
nicklas |
385 |
translations.put("no", "Nej"); |
3525 |
05 Oct 15 |
nicklas |
386 |
} |
3525 |
05 Oct 15 |
nicklas |
387 |
|
3525 |
05 Oct 15 |
nicklas |
388 |
String translatedWord = translations.get(word.toLowerCase()); |
3525 |
05 Oct 15 |
nicklas |
389 |
return translatedWord == null ? word : translatedWord; |
3525 |
05 Oct 15 |
nicklas |
390 |
} |
3506 |
23 Sep 15 |
nicklas |
391 |
|
3525 |
05 Oct 15 |
nicklas |
392 |
private NumberFormat createNumberFormat(int numDecimals) |
3525 |
05 Oct 15 |
nicklas |
393 |
{ |
3525 |
05 Oct 15 |
nicklas |
394 |
DecimalFormatSymbols sym = new DecimalFormatSymbols(); |
3525 |
05 Oct 15 |
nicklas |
395 |
sym.setDecimalSeparator(','); |
3525 |
05 Oct 15 |
nicklas |
396 |
String format = "0"; |
3525 |
05 Oct 15 |
nicklas |
397 |
if (numDecimals > 0) format += "." + MD5.leftPad("", '0', numDecimals); |
3525 |
05 Oct 15 |
nicklas |
398 |
DecimalFormat df = new DecimalFormat(format, sym); |
3525 |
05 Oct 15 |
nicklas |
399 |
return df; |
3525 |
05 Oct 15 |
nicklas |
400 |
} |
3525 |
05 Oct 15 |
nicklas |
401 |
|
3506 |
23 Sep 15 |
nicklas |
402 |
} |