| 36 | 1 # | 
|  | 2 # Copyright INRA-URGI 2009-2010 | 
|  | 3 # | 
|  | 4 # This software is governed by the CeCILL license under French law and | 
|  | 5 # abiding by the rules of distribution of free software. You can use, | 
|  | 6 # modify and/ or redistribute the software under the terms of the CeCILL | 
|  | 7 # license as circulated by CEA, CNRS and INRIA at the following URL | 
|  | 8 # "http://www.cecill.info". | 
|  | 9 # | 
|  | 10 # As a counterpart to the access to the source code and rights to copy, | 
|  | 11 # modify and redistribute granted by the license, users are provided only | 
|  | 12 # with a limited warranty and the software's author, the holder of the | 
|  | 13 # economic rights, and the successive licensors have only limited | 
|  | 14 # liability. | 
|  | 15 # | 
|  | 16 # In this respect, the user's attention is drawn to the risks associated | 
|  | 17 # with loading, using, modifying and/or developing or reproducing the | 
|  | 18 # software by the user in light of its specific status of free software, | 
|  | 19 # that may mean that it is complicated to manipulate, and that also | 
|  | 20 # therefore means that it is reserved for developers and experienced | 
|  | 21 # professionals having in-depth computer knowledge. Users are therefore | 
|  | 22 # encouraged to load and test the software's suitability as regards their | 
|  | 23 # requirements in conditions enabling the security of their systems and/or | 
|  | 24 # data to be ensured and, more generally, to use and operate it in the | 
|  | 25 # same conditions as regards security. | 
|  | 26 # | 
|  | 27 # The fact that you are presently reading this means that you have had | 
|  | 28 # knowledge of the CeCILL license and that you accept its terms. | 
|  | 29 # | 
|  | 30 | 
|  | 31 import os | 
|  | 32 import subprocess | 
|  | 33 import random | 
|  | 34 import math | 
|  | 35 | 
|  | 36 minPositiveValue = 10e-6 | 
|  | 37 | 
|  | 38 """ | 
|  | 39 Plot simple curves in R | 
|  | 40 """ | 
|  | 41 | 
|  | 42 class RPlotter(object): | 
|  | 43     """ | 
|  | 44     Plot some curves | 
|  | 45     @ivar nbColors: number of different colors | 
|  | 46     @type nbColors: int | 
|  | 47     @ivar fileName: name of the file | 
|  | 48     @type fileName: string | 
|  | 49     @ivar lines: lines to be plotted | 
|  | 50     @type lines: array of dict | 
|  | 51     @ivar names: name of the lines | 
|  | 52     @type names: array of strings | 
|  | 53     @ivar colors: color of the lines | 
|  | 54     @type colors: array of strings | 
|  | 55     @ivar types: type of the lines (plain or dashed) | 
|  | 56     @type types: array of strings | 
|  | 57     @ivar format: format of the picture | 
|  | 58     @type format: string | 
|  | 59     @ivar lineWidth: width of the line in a xy-plot | 
|  | 60     @type lineWidth: int | 
|  | 61     @ivar xMin: minimum value taken on the x-axis | 
|  | 62     @type xMin: int | 
|  | 63     @ivar xMax: maximum value taken on the x-axis | 
|  | 64     @type xMax: int | 
|  | 65     @ivar yMin: minimum value taken on the y-axis | 
|  | 66     @type yMin: int | 
|  | 67     @ivar yMax: maximum value taken on the y-axis | 
|  | 68     @type yMax: int | 
|  | 69     @ivar minimumX: minimum value allowed on the x-axis | 
|  | 70     @type minimumX: int | 
|  | 71     @ivar maximumX: maximum value allowed on the x-axis | 
|  | 72     @type maximumX: int | 
|  | 73     @ivar minimumY: minimum value allowed on the y-axis | 
|  | 74     @type minimumY: int | 
|  | 75     @ivar maximumY: maximum value allowed on the y-axis | 
|  | 76     @type maximumY: int | 
|  | 77     @ivar leftMargin:  add some margin in the left part of the plot | 
|  | 78     @type leftMargin:  float | 
|  | 79     @ivar rightMargin: add some margin in the right part of the plot | 
|  | 80     @type rightMargin: float | 
|  | 81     @ivar downMargin:  add some margin at the top of the plot | 
|  | 82     @type downMargin:  float | 
|  | 83     @ivar upMargin:    add some margin at the bottom of the plot | 
|  | 84     @type upMargin:    float | 
|  | 85     @ivar logX: use log scale on the x-axis | 
|  | 86     @type logX: boolean | 
|  | 87     @ivar logY: use log scale on the y-axis | 
|  | 88     @type logY: boolean | 
|  | 89     @ivar logZ: use log scale on the z-axis (the color) | 
|  | 90     @type logZ: boolean | 
|  | 91     @ival fill: if a value is not given, fill it with given value | 
|  | 92     @type fill: int | 
|  | 93     @ival bucket: cluster the data into buckets of given size | 
|  | 94     @type bucket: int | 
|  | 95     @ival seed: a random number | 
|  | 96     @type seed: int | 
|  | 97     @ival regression: plot a linear regression | 
|  | 98     @type regression: boolean | 
|  | 99     @ival legend: set the legend | 
|  | 100     @type legend: boolean | 
|  | 101     @ival legendBySide: set the legend outside of the plot | 
|  | 102     @type legendBySde: boolean | 
|  | 103     @ival xLabel: label for the x-axis | 
|  | 104     @type xLabel: string | 
|  | 105     @ival yLabel: label for the y-axis | 
|  | 106     @type yLabel: string | 
|  | 107     @ival title: title of the plot | 
|  | 108     @type title: string | 
|  | 109     @ival barplot: use a barplot representation instead | 
|  | 110     @type barplot: boolean | 
|  | 111     @ival points: use a point cloud instead | 
|  | 112     @type points: boolean | 
|  | 113     @ival heatPoints: use a colored point cloud instead | 
|  | 114     @type heatPoints: boolean | 
|  | 115     @ival axesLabels: change the names of the axes | 
|  | 116     @type axesLabels: vector of 2 int to string dict | 
|  | 117     @ival rotateAxesLabels: rotate the axes labels | 
|  | 118     @type rotateAxesLabels: dict of 2 boolean | 
|  | 119     @ival verbosity: verbosity of the class | 
|  | 120     @type verbosity: int | 
|  | 121     @ival keep: keep temporary files | 
|  | 122     @type keep: boolean | 
|  | 123     """ | 
|  | 124 | 
|  | 125     def __init__(self, fileName, verbosity = 0, keep = False): | 
|  | 126         """ | 
|  | 127         Constructor | 
|  | 128         @param fileName: name of the file to produce | 
|  | 129         @type    fileName: string | 
|  | 130         @param verbosity: verbosity | 
|  | 131         @type    verbosity: int | 
|  | 132         @param keep: keep temporary files | 
|  | 133         @type keep: boolean | 
|  | 134         """ | 
|  | 135         self.nbColors = 9 | 
|  | 136         self.fileName = fileName | 
|  | 137         self.verbosity = verbosity | 
|  | 138         self.keep = keep | 
|  | 139         self.format = "png" | 
|  | 140         self.fill = None | 
|  | 141         self.bucket = None | 
|  | 142         self.lines = [] | 
|  | 143         self.names = [] | 
|  | 144         self.colors = [] | 
|  | 145         self.types = [] | 
|  | 146         self.lineWidth = 1 | 
|  | 147         self.xMin = None | 
|  | 148         self.xMax = None | 
|  | 149         self.yMin = None | 
|  | 150         self.yMax = None | 
|  | 151         self.seed = random.randint(0, 10000) | 
|  | 152         self.minimumX = None | 
|  | 153         self.maximumX = None | 
|  | 154         self.minimumY = None | 
|  | 155         self.maximumY = None | 
|  | 156         self.leftMargin   = 0 | 
|  | 157         self.rightMargin  = 0 | 
|  | 158         self.topMargin    = 0 | 
|  | 159         self.bottomMargin = 0 | 
|  | 160         self.logX = False | 
|  | 161         self.logY = False | 
|  | 162         self.logZ = False | 
|  | 163         self.regression = False | 
|  | 164         self.width = 1000 | 
|  | 165         self.height = 500 | 
|  | 166         self.legend = False | 
|  | 167         self.legendBySide = False | 
|  | 168         self.xLabel = "" | 
|  | 169         self.yLabel = "" | 
|  | 170         self.title = None | 
|  | 171         self.points = False | 
|  | 172         self.heatPoints = False | 
|  | 173         self.barplot = False | 
|  | 174         self.axesLabels = {1: None, 2: None} | 
|  | 175         self.rotateAxesLabels = {1: False, 2: False} | 
|  | 176         self.linesToAddBox = "" | 
|  | 177 | 
|  | 178     def __del__(self): | 
|  | 179         """ | 
|  | 180         Destructor | 
|  | 181         Remove tmp files | 
|  | 182         """ | 
|  | 183         if not self.keep: | 
|  | 184             scriptFileName = "tmpScript-%d.R" % (self.seed) | 
|  | 185             if os.path.exists(scriptFileName): | 
|  | 186                 os.remove(scriptFileName) | 
|  | 187             outputFileName = "%sout" % (scriptFileName) | 
|  | 188             if os.path.exists(outputFileName): | 
|  | 189                 os.remove(outputFileName) | 
|  | 190             nbLines = len(self.lines) + (1 if self.heatPoints else 0) | 
|  | 191             for i in range(nbLines): | 
|  | 192                 if os.path.exists("tmpData-%d-%d.dat" % (self.seed, i)): | 
|  | 193                     os.remove("tmpData-%d-%d.dat" % (self.seed, i)) | 
|  | 194 | 
|  | 195 | 
|  | 196     def setMinimumX(self, xMin): | 
|  | 197         """ | 
|  | 198         Set the minimum value on the x-axis | 
|  | 199         @param xMin:minimum value on the x-axis | 
|  | 200         @type xMin: int | 
|  | 201         """ | 
|  | 202         self.minimumX = xMin | 
|  | 203 | 
|  | 204 | 
|  | 205     def setMaximumX(self, xMax): | 
|  | 206         """ | 
|  | 207         Set the maximum value on the x-axis | 
|  | 208         @param xMax: maximum value on the x-axis | 
|  | 209         @type xMax: int | 
|  | 210         """ | 
|  | 211         self.maximumX = xMax | 
|  | 212 | 
|  | 213 | 
|  | 214     def setMinimumY(self, yMin): | 
|  | 215         """ | 
|  | 216         Set the minimum value on the y-axis | 
|  | 217         @param yMin: minimum value on the y-axis | 
|  | 218         @type yMin: int | 
|  | 219         """ | 
|  | 220         self.minimumY = yMin | 
|  | 221 | 
|  | 222 | 
|  | 223     def setMaximumY(self, yMax): | 
|  | 224         """ | 
|  | 225         Set the maximum value on the y-axis | 
|  | 226         @param yMax: maximum value on the y-axis | 
|  | 227         @type xmax: int | 
|  | 228         """ | 
|  | 229         self.maximumY = yMax | 
|  | 230 | 
|  | 231 | 
|  | 232     def setFill(self, fill): | 
|  | 233         """ | 
|  | 234         Fill empty data with given value | 
|  | 235         @param fill: the value to fill with | 
|  | 236         @type fill: int | 
|  | 237         """ | 
|  | 238         self.fill = fill | 
|  | 239 | 
|  | 240 | 
|  | 241     def setBuckets(self, bucket): | 
|  | 242         """ | 
|  | 243         Cluster the data into buckets of given size | 
|  | 244         @param bucket: the size of the buckets | 
|  | 245         @type bucket: int | 
|  | 246         """ | 
|  | 247         self.bucket = bucket | 
|  | 248 | 
|  | 249 | 
|  | 250     def setRegression(self, regression): | 
|  | 251         """ | 
|  | 252         Plot a linear regression line | 
|  | 253         @param regression: whether to plot the regression | 
|  | 254         @type  regression: bool | 
|  | 255         """ | 
|  | 256         self.regression = regression | 
|  | 257 | 
|  | 258 | 
|  | 259     def setFormat(self, format): | 
|  | 260         """ | 
|  | 261         Set the format of the picture | 
|  | 262         @param format: the format | 
|  | 263         @type format: string | 
|  | 264         """ | 
|  | 265         if format not in ("png", "pdf", "jpeg", "bmp", "tiff"): | 
|  | 266             raise Exception("Format '%s' is not supported by RPlotter" % (format)) | 
|  | 267         self.format = format | 
|  | 268 | 
|  | 269 | 
|  | 270     def setWidth(self, width): | 
|  | 271         """ | 
|  | 272         Set the dimensions of the image produced | 
|  | 273         @param width: width of the image | 
|  | 274         @type width: int | 
|  | 275         """ | 
|  | 276         self.width = width | 
|  | 277 | 
|  | 278 | 
|  | 279     def setHeight(self, height): | 
|  | 280         """ | 
|  | 281         Set the dimensions of the image produced | 
|  | 282         @param height: heigth of the image | 
|  | 283         @type height: int | 
|  | 284         """ | 
|  | 285         self.height = height | 
|  | 286 | 
|  | 287 | 
|  | 288     def setImageSize(self, width, height): | 
|  | 289         """ | 
|  | 290         Set the dimensions of the image produced | 
|  | 291         @param width: width of the image | 
|  | 292         @type width: int | 
|  | 293         @param height: heigth of the image | 
|  | 294         @type height: int | 
|  | 295         """ | 
|  | 296         self.setWidth(width) | 
|  | 297         self.setHeight(height) | 
|  | 298 | 
|  | 299 | 
|  | 300     def setLegend(self, legend, bySide = False): | 
|  | 301         """ | 
|  | 302         Print a legend or not | 
|  | 303         @param legend: print a legend | 
|  | 304         @type  legend: boolean | 
|  | 305         @param bySide: put the legend outside of the plot | 
|  | 306         @type  bySide: boolean | 
|  | 307         """ | 
|  | 308         self.legend       = legend | 
|  | 309         self.legendBySide = bySide | 
|  | 310 | 
|  | 311 | 
|  | 312     def setXLabel(self, label): | 
|  | 313         """ | 
|  | 314         Print a label for the x-axis | 
|  | 315         @param label: the label | 
|  | 316         @type label: string | 
|  | 317         """ | 
|  | 318         self.xLabel = label | 
|  | 319         if self.xLabel != None: | 
|  | 320             self.xLabel = self.xLabel.replace("_", " ") | 
|  | 321 | 
|  | 322 | 
|  | 323     def setYLabel(self, label): | 
|  | 324         """ | 
|  | 325         Print a label for the y-axis | 
|  | 326         @param label: the label | 
|  | 327         @type label: string | 
|  | 328         """ | 
|  | 329         self.yLabel = label | 
|  | 330         if self.yLabel != None: | 
|  | 331             self.yLabel = self.yLabel.replace("_", " ") | 
|  | 332 | 
|  | 333 | 
|  | 334     def addLeftMargin(self, margin): | 
|  | 335         """ | 
|  | 336         Increase the size of the space on the left part of the graph | 
|  | 337         @param margin: the space added | 
|  | 338         @type  margin: float | 
|  | 339         """ | 
|  | 340         self.leftMargin = margin | 
|  | 341 | 
|  | 342 | 
|  | 343     def addRightMargin(self, margin): | 
|  | 344         """ | 
|  | 345         Increase the size of the space on the right part of the graph | 
|  | 346         @param margin: the space added | 
|  | 347         @type  margin: float | 
|  | 348         """ | 
|  | 349         self.rightMargin = margin | 
|  | 350 | 
|  | 351 | 
|  | 352     def addTopMargin(self, margin): | 
|  | 353         """ | 
|  | 354         Increase the size of the space at the top of the graph | 
|  | 355         TopMargin is a percentage if 0 < TopMargin < 1. | 
|  | 356         TopMargin is a value if TopMargin >= 1. | 
|  | 357         @param margin: the space added | 
|  | 358         @type  margin: float | 
|  | 359         """ | 
|  | 360         self.topMargin = margin | 
|  | 361 | 
|  | 362 | 
|  | 363     def addBottomMargin(self, margin): | 
|  | 364         """ | 
|  | 365         Increase the size of the space at the bottom of the graph | 
|  | 366         @param margin: the space added | 
|  | 367         @type  margin: float | 
|  | 368         """ | 
|  | 369         self.bottomMargin = margin | 
|  | 370 | 
|  | 371 | 
|  | 372     def getNewYMaxWithTopMargin(self): | 
|  | 373         """ | 
|  | 374         Return new xMin coordinate with left margin | 
|  | 375         @param xMin: coordinate | 
|  | 376         @type  xMin: float | 
|  | 377         """ | 
|  | 378         yMax = self.yMax | 
|  | 379         if 0 < self.topMargin and self.topMargin < 1: | 
|  | 380             topMargin = self.topMargin * self.yMax | 
|  | 381             yMax = self.yMax + topMargin | 
|  | 382         elif self.topMargin >= 1: | 
|  | 383             yMax = self.yMax + self.topMargin | 
|  | 384         return yMax | 
|  | 385 | 
|  | 386 | 
|  | 387     def setTitle(self, title): | 
|  | 388         """ | 
|  | 389         Print a title for graph | 
|  | 390         @param title: a title | 
|  | 391         @type title: string | 
|  | 392         """ | 
|  | 393         self.title = title | 
|  | 394         if self.title != None: | 
|  | 395             self.title = self.title.replace("_", " ") | 
|  | 396 | 
|  | 397 | 
|  | 398     def setAxisLabel(self, i, labels): | 
|  | 399         """ | 
|  | 400         Change x- or y-labels | 
|  | 401         @param i: x for x-label, y for y-label | 
|  | 402         @type  i: string | 
|  | 403         @param labels: new labels | 
|  | 404         @type  labels: int to string dict | 
|  | 405         """ | 
|  | 406         i = i.lower() | 
|  | 407         if i not in ("x", "y"): | 
|  | 408             raise Exception("Label name '" + i + "' should by 'x' or 'y' while changing axis labels.") | 
|  | 409         self.axesLabels[{"x": 1, "y": 2}[i]] = labels | 
|  | 410 | 
|  | 411 | 
|  | 412     def rotateAxisLabel(self, i, b = True): | 
|  | 413         """ | 
|  | 414         Rotate x- or y-labels | 
|  | 415         @param i: x for x-label, y for y-label | 
|  | 416         @type  i: string | 
|  | 417         @param b: whether the labels should be rotated | 
|  | 418         @type  b: boolean | 
|  | 419         """ | 
|  | 420         i = i.lower() | 
|  | 421         if i not in ("x", "y"): | 
|  | 422             raise Exception("Label name '" + i + "' should by 'x' or 'y' while rotating axis labels.") | 
|  | 423         self.rotateAxesLabels[{"x": 1, "y": 2}[i]] = b | 
|  | 424 | 
|  | 425     def setLineWidth(self, width): | 
|  | 426         """ | 
|  | 427         Set the line width in a xy-plot | 
|  | 428         @param width: the new line width | 
|  | 429         @type  width: int | 
|  | 430         """ | 
|  | 431         self.lineWidth = width | 
|  | 432 | 
|  | 433     def setLog(self, log): | 
|  | 434         """ | 
|  | 435         Use log-scale for axes | 
|  | 436         @param log: use log scale | 
|  | 437         @type log: boolean | 
|  | 438         """ | 
|  | 439         self.logX = ("x" in log) | 
|  | 440         self.logY = ("y" in log) | 
|  | 441         self.logZ = ("z" in log) | 
|  | 442 | 
|  | 443 | 
|  | 444     def setBarplot(self, barplot): | 
|  | 445         """ | 
|  | 446         Use barplot representation instead | 
|  | 447         @param barplot: barplot representation | 
|  | 448         @type barplot: boolean | 
|  | 449         """ | 
|  | 450         self.barplot = barplot | 
|  | 451 | 
|  | 452 | 
|  | 453     def setPoints(self, points): | 
|  | 454         """ | 
|  | 455         Use points cloud representation instead | 
|  | 456         @param points: points cloud representation | 
|  | 457         @type points: boolean | 
|  | 458         """ | 
|  | 459         self.points = points | 
|  | 460 | 
|  | 461 | 
|  | 462     def setHeatPoints(self, heatPoints): | 
|  | 463         """ | 
|  | 464         Use points cloud representation with color representing another variable instead | 
|  | 465         @param points: colored points cloud representation | 
|  | 466         @type points: boolean | 
|  | 467         """ | 
|  | 468         self.heatPoints = heatPoints | 
|  | 469 | 
|  | 470 | 
|  | 471     def addBox(self, lXCoordList, minY, maxY): | 
|  | 472         for lXCoord in lXCoordList: | 
|  | 473             self.linesToAddBox += "rect(%s,%s,%s,%s,density=50, col='grey',border='transparent')\n" % (lXCoord[0], minY, lXCoord[1], maxY) | 
|  | 474 | 
|  | 475     def addLine(self, line, name = "", color = None): | 
|  | 476         """ | 
|  | 477         Add a line | 
|  | 478         @param line: a line to plot | 
|  | 479         @type line: dict | 
|  | 480         """ | 
|  | 481         # prepare data | 
|  | 482         plot = [] | 
|  | 483         if self.points or self.heatPoints: | 
|  | 484             values = line.values() | 
|  | 485         elif self.fill == None: | 
|  | 486             values = sorted(line.keys()) | 
|  | 487         else: | 
|  | 488             values = range(min(line.keys()), max(line.keys()) + 1) | 
|  | 489 | 
|  | 490         for element in values: | 
|  | 491             if self.points or self.heatPoints: | 
|  | 492                 x = element[0] | 
|  | 493                 y = element[1] | 
|  | 494             else: | 
|  | 495                 x = element | 
|  | 496                 if x not in line: | 
|  | 497                     y = self.fill | 
|  | 498                 else: | 
|  | 499                     y = line[x] | 
|  | 500 | 
|  | 501             if self.minimumX != None and x < self.minimumX: | 
|  | 502                 continue | 
|  | 503             if self.maximumX != None and x > self.maximumX: | 
|  | 504                 continue | 
|  | 505 | 
|  | 506             if x == None: | 
|  | 507                 raise Exception("Problem! x is None. Aborting...") | 
|  | 508             if y == None: | 
|  | 509                 raise Exception("Problem! y is None. Aborting...") | 
|  | 510             if x == 0 and self.logX: | 
|  | 511                 x = minPositiveValue | 
|  | 512             if y == 0 and self.logY: | 
|  | 513                 y = minPositiveValue | 
|  | 514             if self.xMin == None: | 
|  | 515                 if not self.logX or x != 0: | 
|  | 516                     self.xMin = x | 
|  | 517             else: | 
|  | 518                 if not self.logX or x != 0: | 
|  | 519                     self.xMin = min(self.xMin, x) | 
|  | 520             if self.xMax == None: | 
|  | 521                 self.xMax = x | 
|  | 522             else: | 
|  | 523                 self.xMax = max(self.xMax, x) | 
|  | 524             if self.yMin == None: | 
|  | 525                 if not self.logY or y != 0: | 
|  | 526                     self.yMin = y | 
|  | 527             else: | 
|  | 528                 if not self.logY or y != 0: | 
|  | 529                     if y != "NA": | 
|  | 530                         self.yMin = min(self.yMin, y) | 
|  | 531             if self.yMax == None: | 
|  | 532                 self.yMax = y | 
|  | 533             else: | 
|  | 534                 if y != "NA": | 
|  | 535                     self.yMax = max(self.yMax, y) | 
|  | 536 | 
|  | 537             plot.append((x, y)) | 
|  | 538 | 
|  | 539         # cluster the data into buckets | 
|  | 540         if self.bucket != None: | 
|  | 541             buckets = dict([((int(value) / int(self.bucket)) * self.bucket, 0) for value in xrange(min(line.keys()), max(line.keys())+1)]) | 
|  | 542             for distance, nb in line.iteritems(): | 
|  | 543                 buckets[(int(distance) / int(self.bucket)) * self.bucket] += nb | 
|  | 544             self.yMax = max(buckets.values()) | 
|  | 545             plot = [] | 
|  | 546             for x, y in buckets.iteritems(): | 
|  | 547                 plot.append((x, y)) | 
|  | 548 | 
|  | 549         # write file | 
|  | 550         dataFileName = "tmpData-%d-%d.dat" % (self.seed, len(self.lines)) | 
|  | 551         dataHandle = open(dataFileName, "w") | 
|  | 552         if not self.heatPoints: | 
|  | 553             plot.sort() | 
|  | 554         for (x, y) in plot: | 
|  | 555             if y != "NA": | 
|  | 556                 dataHandle.write("%f\t%f\n" % (x, y)) | 
|  | 557             else: | 
|  | 558                 dataHandle.write("%f\t%s\n" % (x, y)) | 
|  | 559         dataHandle.close() | 
|  | 560 | 
|  | 561         self.lines.append(line) | 
|  | 562         self.names.append(name) | 
|  | 563 | 
|  | 564         if color == None: | 
|  | 565             colorNumber = len(self.colors) % (self.nbColors - 1) + 1 | 
|  | 566             type = "solid" | 
|  | 567             if len(self.colors) >= self.nbColors: | 
|  | 568                 type = "dashed" | 
|  | 569             color = "colorPanel[%d]" % (colorNumber) | 
|  | 570         else: | 
|  | 571             color = "\"%s\"" % (color) | 
|  | 572             type = "solid" | 
|  | 573         self.colors.append(color) | 
|  | 574         self.types.append(type) | 
|  | 575 | 
|  | 576 | 
|  | 577     def addHeatLine(self, line, name = "", color = None): | 
|  | 578         """ | 
|  | 579         Add the heat line | 
|  | 580         @param line: the line which gives the color of the points | 
|  | 581         @type    line: dict | 
|  | 582         """ | 
|  | 583         if not self.heatPoints: | 
|  | 584             raise Exception("Error! Trying to add a heat point whereas not mentioned to earlier! Aborting.") | 
|  | 585 | 
|  | 586         dataFileName = "tmpData-%d-%d.dat" % (self.seed, len(self.lines)) | 
|  | 587         dataHandle = open(dataFileName, "w") | 
|  | 588 | 
|  | 589         minimumHeat = min(line.values()) | 
|  | 590         maximumHeat = max(line.values()) | 
|  | 591         minLogValue = 0.00001 | 
|  | 592         log = self.logZ | 
|  | 593 | 
|  | 594         if log: | 
|  | 595             if minimumHeat == 0: | 
|  | 596                 for element in line: | 
|  | 597                     line[element] += minLogValue | 
|  | 598                 minimumHeat += minLogValue | 
|  | 599                 maximumHeat += minLogValue | 
|  | 600             minimumHeat = math.log10(minimumHeat) | 
|  | 601             maximumHeat = math.log10(maximumHeat) | 
|  | 602 | 
|  | 603         coeff = 255.0 / (maximumHeat - minimumHeat) | 
|  | 604 | 
|  | 605         for element in line: | 
|  | 606             value = line[element] | 
|  | 607             if log: | 
|  | 608                 value = math.log10(max(minLogValue, value)) | 
|  | 609             dataHandle.write("\"#%02X%02X00\"\n" % (int((value - minimumHeat) * coeff), 255 - int((value - minimumHeat) * coeff))) | 
|  | 610 | 
|  | 611         dataHandle.close() | 
|  | 612         self.names.append(name) | 
|  | 613         if color == None: | 
|  | 614             colorNumber = len(self.colors) % (self.nbColors - 1) + 1 | 
|  | 615             type = "solid" | 
|  | 616             if len(self.colors) >= self.nbColors: | 
|  | 617                 type = "dashed" | 
|  | 618             color = "colorPanel[%d]" % (colorNumber) | 
|  | 619         else: | 
|  | 620             color = "\"%s\"" % (color) | 
|  | 621             type = "solid" | 
|  | 622         self.colors.append(color) | 
|  | 623         self.types.append(type) | 
|  | 624 | 
|  | 625 | 
|  | 626     def getScript(self): | 
|  | 627         """ | 
|  | 628         Write (unfinished) R script | 
|  | 629         """ | 
|  | 630         script = "" | 
|  | 631 | 
|  | 632         xMin = self.xMin - self.leftMargin | 
|  | 633         if self.minimumX != None: | 
|  | 634             xMin = max(xMin, self.minimumX) | 
|  | 635         xMax = self.xMax + self.rightMargin | 
|  | 636         if self.maximumX != None: | 
|  | 637             xMax = min(xMax, self.maximumX) | 
|  | 638         yMin = self.yMin - self.bottomMargin | 
|  | 639         if self.minimumY != None: | 
|  | 640             yMin = self.minimumY | 
|  | 641         yMax = self.getNewYMaxWithTopMargin() | 
|  | 642         yMax += min(1, yMax / 100.0) | 
|  | 643         if self.maximumY != None: | 
|  | 644             yMax = self.maximumY | 
|  | 645 | 
|  | 646         log = "" | 
|  | 647         if self.logX: | 
|  | 648             log += "x" | 
|  | 649         if self.logY: | 
|  | 650             log += "y" | 
|  | 651         if log != "": | 
|  | 652             log = ", log=\"%s\"" % (log) | 
|  | 653 | 
|  | 654         title = "" | 
|  | 655         if self.title != None: | 
|  | 656             title = ", main = \"%s\"" % (self.title) | 
|  | 657 | 
|  | 658         if self.legend and self.legendBySide: | 
|  | 659             script += "layout(matrix(c(1,2), 1, 2), widths=c(5,1))\n" | 
|  | 660 | 
|  | 661         if self.rotateAxesLabels[2]: | 
|  | 662             script += "par(mar=c(5,12,4,2))\n" | 
|  | 663         else: | 
|  | 664             script += "par(mar=c(5,5,4,2))\n" | 
|  | 665 | 
|  | 666         addAxes = True | 
|  | 667 | 
|  | 668         if self.barplot: | 
|  | 669             script += "data = scan(\"tmpData-%d-0.dat\", list(x = -666, y = -666))\n" % (self.seed) | 
|  | 670             if len(self.lines) == 1: | 
|  | 671                 script += "barplot(data$y, name = data$x, xlab=\"%s\", ylab=\"%s\", ylim = c(%f, %f), cex.axis = 2, cex.names = 2, cex.lab = 2%s%s)\n" % (self.xLabel, self.yLabel, yMin, yMax, title, log) | 
|  | 672                 addAxes = False | 
|  | 673             else: | 
|  | 674                 script += "data1 = scan(\"tmpData-%d-1.dat\", list(x = -666, y = -666))\n" % (self.seed) | 
|  | 675                 script += "barplot(rbind(data$y, data1$y), name = data$x, xlab=\"%s\", ylab=\"%s\", cex.axis = 2, cex.names = 2, cex.lab = 2%s, beside = TRUE, space=c(-1,0), axes = FALSE%s)\n" % (self.xLabel, self.yLabel, title, log) | 
|  | 676         elif self.points: | 
|  | 677             script += "data = scan(\"tmpData-%d-0.dat\", list(x = -666, y = -666))\n" % (self.seed) | 
|  | 678             script += "plot(data$x, data$y, xlab=\"%s\", ylab=\"%s\", cex.axis = 2, cex.lab = 2, axes = FALSE%s%s)\n" % (self.xLabel, self.yLabel, title, log) | 
|  | 679             if self.regression: | 
|  | 680                 x = "log10(data$x)" if self.logX else "data$x" | 
|  | 681                 y = "log10(data$y)" if self.logY else "data$y" | 
|  | 682                 script += "abline(lm(%s ~ %s))\n" % (y, x) | 
|  | 683         elif self.heatPoints: | 
|  | 684             if len(self.lines) != 1: | 
|  | 685                 raise Exception("Error! Bad number of input data! Aborting...") | 
|  | 686             script += "data = scan(\"tmpData-%d-0.dat\", list(x = -666, y = -666))\n" % (self.seed) | 
|  | 687             script += "heatData = scan(\"tmpData-%d-1.dat\", list(x = \"\"))\n" % (self.seed) | 
|  | 688             script += "plot(data$x, data$y, col=heatData$x, xlab=\"%s\", ylab=\"%s\", cex.axis = 2, cex.lab = 2, axes = FALSE%s%s)\n" % (self.xLabel, self.yLabel, title, log) | 
|  | 689             if self.regression: | 
|  | 690                 x = "log10(data$x)" if self.logX else "data$x" | 
|  | 691                 y = "log10(data$y)" if self.logY else "data$y" | 
|  | 692                 script += "abline(lm(%s ~ %s))\n" % (y, x) | 
|  | 693         else: | 
|  | 694             script += "plot(x = NA, y = NA, panel.first = grid(lwd = 1.0), xlab=\"%s\", ylab=\"%s\", xlim = c(%f, %f), ylim = c(%f, %f), cex.axis = 2, cex.lab = 2, axes = FALSE%s%s)\n" % (self.xLabel, self.yLabel, xMin, xMax, yMin, yMax, title, log) | 
|  | 695             for i in range(0, len(self.lines)): | 
|  | 696                 script += "data = scan(\"tmpData-%d-%d.dat\", list(x = -666.666, y = -666.666))\n" % (self.seed, i) | 
|  | 697                 script += "lines(x = data$x, y = data$y, col = %s, lty = \"%s\", lwd = %d)\n" % (self.colors[i], self.types[i], self.lineWidth) | 
|  | 698 | 
|  | 699             script += self.linesToAddBox | 
|  | 700 | 
|  | 701         if addAxes: | 
|  | 702             for i in self.axesLabels: | 
|  | 703                 rotation = ", las = 2" if self.rotateAxesLabels[i] else "" | 
|  | 704                 if self.axesLabels[i] == None: | 
|  | 705                     script += "axis(%d, cex.axis = 2, cex.lab = 2%s)\n" % (i, rotation) | 
|  | 706                 else: | 
|  | 707                     oldKeys = ", ".join(["%d" % (key) for key in sorted(self.axesLabels[i].keys())]) | 
|  | 708                     newKeys = ", ".join(["\"%s\"" % (self.axesLabels[i][key]) for key in sorted(self.axesLabels[i].keys())]) | 
|  | 709                     script += "axis(%d, at=c(%s), lab=c(%s), cex.axis = 2, cex.lab = 2%s)\n" % (i, oldKeys, newKeys, rotation) | 
|  | 710         script += "box()\n" | 
|  | 711 | 
|  | 712         if self.legend: | 
|  | 713             if self.legendBySide: | 
|  | 714                 script += "plot.new()\n" | 
|  | 715                 script += "par(mar=c(0,0,0,0))\n" | 
|  | 716                 script += "plot.window(c(0,1), c(0,1))\n" | 
|  | 717             script += "legends   = c(%s)\n" % ", ".join(["\"%s\"" % name  for name  in self.names]) | 
|  | 718             script += "colors    = c(%s)\n" % ", ".join(["%s" %     color for color in self.colors]) | 
|  | 719             script += "lineTypes = c(%s)\n" % ", ".join(["\"%s\"" % type  for type  in self.types]) | 
|  | 720             if self.legendBySide: | 
|  | 721                 script += "legend(0, 1, legend = legends, xjust = 0, yjust = 1, col = colors, lty = lineTypes, lwd = %d, cex = 1.5, ncol = 1, bg = \"white\")\n" % (self.lineWidth) | 
|  | 722             else: | 
|  | 723                 script += "legend(\"topright\", legend = legends, xjust = 0, yjust = 1, col = colors, lty = lineTypes, lwd = %d, cex = 1.5, ncol = 1, bg = \"white\")\n" % (self.lineWidth) | 
|  | 724 | 
|  | 725         return script | 
|  | 726 | 
|  | 727 | 
|  | 728 | 
|  | 729     def plot(self): | 
|  | 730         """ | 
|  | 731         Plot the lines | 
|  | 732         """ | 
|  | 733         scriptFileName = "tmpScript-%d.R" % (self.seed) | 
|  | 734         scriptHandle = open(scriptFileName, "w") | 
|  | 735         scriptHandle.write("library(RColorBrewer)\n") | 
|  | 736         scriptHandle.write("colorPanel = brewer.pal(n=%d, name=\"Set1\")\n" % (self.nbColors)) | 
|  | 737         scriptHandle.write("%s(%s = \"%s\", width = %d, height = %d, bg = \"white\")\n" % (self.format, "filename" if self.format != "pdf" else "file", self.fileName, self.width, self.height)) | 
|  | 738         scriptHandle.write(self.getScript()) | 
|  | 739         scriptHandle.write("dev.off()\n") | 
|  | 740         scriptHandle.close() | 
|  | 741         rCommand = "R" | 
|  | 742         if "SMARTRPATH" in os.environ: | 
|  | 743             rCommand = os.environ["SMARTRPATH"] | 
|  | 744         command = "\"%s\" CMD BATCH %s" % (rCommand, scriptFileName) | 
|  | 745         status = subprocess.call(command, shell=True) | 
|  | 746 | 
|  | 747         if status != 0: | 
|  | 748             self.keep = True | 
|  | 749             raise Exception("Problem with the execution of script file %s, status is: %s" % (scriptFileName, status)) | 
|  | 750 | 
|  | 751 | 
|  | 752     def getCorrelationData(self): | 
|  | 753         if not self.regression: | 
|  | 754             return "" | 
|  | 755         scriptFileName = "tmpScript-%d.R" % (self.seed) | 
|  | 756         rScript = open(scriptFileName, "w") | 
|  | 757         rScript.write("data = scan(\"tmpData-%d-0.dat\", list(x = -0.000000, y = -0.000000))\n" % (self.seed)) | 
|  | 758         x = "log10(data$x)" if self.logX else "data$x" | 
|  | 759         y = "log10(data$y)" if self.logY else "data$y" | 
|  | 760         rScript.write("summary(lm(%s ~ %s))\n" % (y, x)) | 
|  | 761         rScript.close() | 
|  | 762         rCommand = "R" | 
|  | 763         if "SMARTRPATH" in os.environ: | 
|  | 764             rCommand = os.environ["SMARTRPATH"] | 
|  | 765         command = "\"%s\" CMD BATCH %s" % (rCommand, scriptFileName) | 
|  | 766         status = subprocess.call(command, shell=True) | 
|  | 767         if status != 0: | 
|  | 768             self.keep = True | 
|  | 769             raise Exception("Problem with the execution of script file %s computing the correlation, status is: %s" % (scriptFileName, status)) | 
|  | 770         outputRFile = open("%sout" % (scriptFileName)) | 
|  | 771         output      = "" | 
|  | 772         start       = False | 
|  | 773         end         = False | 
|  | 774         for line in outputRFile: | 
|  | 775             if start and "> " in line: | 
|  | 776                 end = True | 
|  | 777             if start and not end: | 
|  | 778                 output += line | 
|  | 779             if "summary" in line: | 
|  | 780                 start = True | 
|  | 781         return output | 
|  | 782 | 
|  | 783 | 
|  | 784     def getSpearmanRho(self): | 
|  | 785         """ | 
|  | 786         Get the Spearman rho correlation using R | 
|  | 787         """ | 
|  | 788         return None | 
|  | 789         if not self.points and not self.barplot and not self.heatPoints: | 
|  | 790             raise Exception("Cannot compute Spearman rho correlation whereas not in 'points' or 'bar' mode.") | 
|  | 791 | 
|  | 792         scriptFileName = "tmpScript-%d.R" % (self.seed) | 
|  | 793         rScript = open(scriptFileName, "w") | 
|  | 794         rScript.write("library(Hmisc)\n") | 
|  | 795         rScript.write("data = scan(\"tmpData-%d-0.dat\", list(x = -0.000000, y = -0.000000))\n" % (self.seed)) | 
|  | 796         rScript.write("spearman(data$x, data$y)\n") | 
|  | 797         rScript.close() | 
|  | 798 | 
|  | 799         rCommand = "R" | 
|  | 800         if "SMARTRPATH" in os.environ: | 
|  | 801             rCommand = os.environ["SMARTRPATH"] | 
|  | 802         command = "\"%s\" CMD BATCH %s" % (rCommand, scriptFileName) | 
|  | 803         status = subprocess.call(command, shell=True) | 
|  | 804 | 
|  | 805         if status != 0: | 
|  | 806             self.keep = True | 
|  | 807             raise Exception("Problem with the execution of script file %s, status is: %s" % (scriptFileName, status)) | 
|  | 808 | 
|  | 809         outputRFile = open("%sout" % (scriptFileName)) | 
|  | 810         nextLine = False | 
|  | 811         for line in outputRFile: | 
|  | 812             line = line.strip() | 
|  | 813             if nextLine: | 
|  | 814                 if line == "NA": | 
|  | 815                     return None | 
|  | 816                 return float(line) | 
|  | 817                 nextLine = False | 
|  | 818             if line == "rho": | 
|  | 819                 nextLine = True | 
|  | 820 | 
|  | 821         return None |