001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.survival.cox;
022
023import java.text.DecimalFormat;
024import java.util.ArrayList;
025import java.util.LinkedHashMap;
026
027/**
028 * Information needed to represent a survival curve
029 *
030 * @author Scooter Willis <willishf at gmail dot com>
031 */
032public class StrataInfo {
033
034        private ArrayList<Double> time = new ArrayList<Double>();
035        private ArrayList<Integer> status = new ArrayList<Integer>();
036        private ArrayList<Double> nevent = new ArrayList<Double>();
037        private ArrayList<Double> ncens = new ArrayList<Double>();
038        private ArrayList<Double> nrisk = new ArrayList<Double>();
039        private ArrayList<Double> weight = new ArrayList<Double>();
040        private ArrayList<Double> surv = new ArrayList<Double>();
041        private ArrayList<Double> varhaz = new ArrayList<Double>();
042        private ArrayList<Double> stderr = new ArrayList<Double>();
043        private ArrayList<Double> stdlow = new ArrayList<Double>();
044        private ArrayList<Double> upper = new ArrayList<Double>();
045        private ArrayList<Double> lower = new ArrayList<Double>();
046        private LinkedHashMap<Double, Integer> ndead = new LinkedHashMap<Double, Integer>();
047        DecimalFormat df = new DecimalFormat("#.######");
048        DecimalFormat dfe = new DecimalFormat("0.000000E0");
049
050        /**
051         * Need to find the actual time for the nearest time represented as a
052         * percentage Would be used to then look up the number at risk at that
053         * particular time
054         *
055         * @param timePercentage
056         * @return
057         */
058        public Double getNearestTime(double timePercentage) {
059                //the arrays should be sorted by time so this step is probably not needed
060                Double minTime = null;
061                Double maxTime = null;
062                for (Double t : time) {
063                        if (minTime == null || t < minTime) {
064                                minTime = t;
065                        }
066                        if (maxTime == null || t > maxTime) {
067                                maxTime = t;
068                        }
069                }
070                Double timeRange = maxTime - minTime;
071                Double targetTime = minTime + timePercentage * timeRange;
072                Double previousTime = null;
073                for (Double t : time) {
074                        if (previousTime == null || t <= targetTime) {
075                                previousTime = t;
076                        } else {
077                                return previousTime;
078                        }
079                }
080                return previousTime;
081        }
082
083        /**
084         * Selection of number of risk will depend on the precision and rounding of
085         * time in the survival table. If you are asking for 12 and entry exists for
086         * 11.9999999 then 12 is greater than 11.99999 unless you round.
087         *
088         * @param t
089         * @return
090         */
091        public Double getNearestAtRisk(double t) {
092                Integer index = 0;
093/*       String timeValue = t + "";
094                String format = "#";
095                int numDecimals = 0;
096                int decimalIndex = timeValue.indexOf(".");
097                if (decimalIndex > 0) {
098                        for (int i = timeValue.length() - 1; i > decimalIndex; i--) {
099                                if (timeValue.charAt(i) == '0' && numDecimals == 0) {
100                                        continue;
101                                }
102                                if (i == decimalIndex - 1) {
103                                        format = format + ".#";
104                                } else {
105                                        format = format + "#";
106                                }
107                        }
108                }
109 */
110                DecimalFormat newFormat = new DecimalFormat("#.#"); //used to round on expected precision of time. Not correct but trying to match the other packages
111
112                for (int i = 0; i < time.size(); i++) {
113                        Double compareTime = time.get(i);
114                  //  compareTime = new Double(Math.round(compareTime)); //this is rounding up so that we stop on the first match trying to get this to match another report. Not correct or the other report is wrong
115                        compareTime = Double.valueOf(newFormat.format(compareTime));
116                        if (compareTime < t) {
117                                index = i + 1 ;
118                        } else if(compareTime == t){
119                                index = i;
120                                break;
121                        }else {
122                                break;
123                        }
124                }
125
126                //http://www.inside-r.org/packages/cran/rms/docs/survplot
127                //per validation using survplot from RMS package and ggkm they select the next
128                //time in the future which doesn't seem to be correct as the next time represents
129                //knowledge about the future but maybe nrisk at that point in time is defined
130                //as the nrisk prior to that time. This appears to be the case where at time 0
131                //you would expect that everyone is at risk and you should report that time which
132                //is the case in survplot. Added in index = 0 or if the time you are requesting has
133                //an exact match
134                //survplot(kma,n.risk=TRUE,time.inc=1090)
135                //ggkm(kma,timeby=1090)
136           //     if(index != 0 && time.get(index) != t){
137           //      index++;
138           //     }
139                if (index >= nrisk.size()) {
140                        return null;
141                } else {
142                        return nrisk.get(index);
143                }
144        }
145
146        /**
147         *
148         * @param d
149         * @return
150         */
151        public String f(Double d) {
152                String v = df.format(d);
153                int l = 10 - v.length();
154                for (int i = 0; i < l; i++) {
155                        v = v + " ";
156                }
157                return v;
158        }
159
160        @Override
161        public String toString() {
162                String o = "";
163                o = o + "n=" + nevent.size() + "\r\n";
164                o = o + "     time      nevent     ncens     nrisk     weight     surv   varhaz    stderr    stdlow    lower    upper\r\n";
165                for (int i = 0; i < nevent.size(); i++) {
166                        //    if(nevent.get(i) == 0)
167                        //        continue;
168                        o = o + (i + 1) + "    " + f(time.get(i)) + " " + f(nevent.get(i)) + " " + f(ncens.get(i)) + " " + f(nrisk.get(i)) + " " + f(weight.get(i)) + " " + f(surv.get(i)) + " " + (varhaz.get(i)) + "  " + stderr.get(i) + "  " + stdlow.get(i) + "  " + lower.get(i) + "  " + upper.get(i) + "\r\n";
169
170                }
171                o = o + "\r\n";
172                //   for(Integer i : ndead.values()){
173                //       o = o + i + "\r\n";
174                //   }
175
176                return o;
177        }
178
179        /**
180         * @return the time
181         */
182        public ArrayList<Double> getTime() {
183                return time;
184        }
185
186        /**
187         * @return the surv
188         */
189        public ArrayList<Double> getSurv() {
190                return surv;
191        }
192
193        /**
194         * @return the stderr
195         */
196        public ArrayList<Double> getStderr() {
197                return stderr;
198        }
199
200        /**
201         * @return the upper
202         */
203        public ArrayList<Double> getUpper() {
204                return upper;
205        }
206
207        /**
208         * @return the lower
209         */
210        public ArrayList<Double> getLower() {
211                return lower;
212        }
213
214        /**
215         * @return the status
216         */
217        public ArrayList<Integer> getStatus() {
218                return status;
219        }
220
221        /**
222         * @return the nevent
223         */
224        public ArrayList<Double> getNevent() {
225                return nevent;
226        }
227
228        /**
229         * @return the ncens
230         */
231        public ArrayList<Double> getNcens() {
232                return ncens;
233        }
234
235        /**
236         * @return the nrisk
237         */
238        public ArrayList<Double> getNrisk() {
239                return nrisk;
240        }
241
242        /**
243         * @return the weight
244         */
245        public ArrayList<Double> getWeight() {
246                return weight;
247        }
248
249        /**
250         * @return the ndead
251         */
252        public LinkedHashMap<Double, Integer> getNdead() {
253                return ndead;
254        }
255
256        /**
257         * @return the varhaz
258         */
259        public ArrayList<Double> getVarhaz() {
260                return varhaz;
261        }
262
263        /**
264         * @return the stdlow
265         */
266        public ArrayList<Double> getStdlow() {
267                return stdlow;
268        }
269
270        /**
271         * @param stdlow the stdlow to set
272         */
273        public void setStdlow(ArrayList<Double> stdlow) {
274                this.stdlow = stdlow;
275        }
276}