[1986] | 1 | #!/bin/env python |
---|
| 2 | |
---|
| 3 | #====================================================== |
---|
| 4 | # Author: Patrick.Brockmann@cea.fr |
---|
| 5 | # |
---|
| 6 | # Date: 13/11/2012 |
---|
| 7 | # |
---|
| 8 | #====================================================== |
---|
| 9 | |
---|
| 10 | #====================================================== |
---|
| 11 | import csv |
---|
| 12 | import matplotlib.pyplot as plt |
---|
| 13 | import datetime as dt |
---|
| 14 | import sys, string, os, re |
---|
| 15 | import urllib2 |
---|
| 16 | import random |
---|
| 17 | |
---|
| 18 | #====================================================== |
---|
| 19 | usage = """###################################################### |
---|
| 20 | Usage: plot_runcard.py [-h] |
---|
| 21 | [--period] |
---|
| 22 | [--yscalelog] |
---|
| 23 | [--linewidth width] |
---|
| 24 | [--linecolor colorcode] |
---|
| 25 | [--showtitle] |
---|
| 26 | [--pattern 'pattern, options ; ...'] |
---|
| 27 | list |
---|
| 28 | |
---|
| 29 | |
---|
| 30 | Argument: |
---|
| 31 | Argument list is text file with one run.card file accessible by HTTP (http://...) or locally (file:///...) per line. |
---|
| 32 | For each line, you can add specific options (linecolor, linewidth, title, showtitle) separated by ',' (whatever order). |
---|
| 33 | For example : |
---|
| 34 | http://dods.extra.cea.fr/work/p86caub/IPSLCM5A/PROD/rcp85GHG/v3.rcp85GHG1/MONITORING/run.card , linecolor="AFBBAA", title="My text", showtitle=1 |
---|
| 35 | |
---|
| 36 | Notes: |
---|
| 37 | Default color are randomly choosen |
---|
| 38 | Default title is built from filename |
---|
| 39 | |
---|
| 40 | Examples: |
---|
| 41 | ./plot_runcard.py --linecolor "BBBBBB" --pattern 'p86caub, linecolor="00FF00", showtitle=1 ; p25mart, linecolor="FF0000", showtitle=1, linewidth=4' list_url_work2 |
---|
| 42 | ./plot_runcard.py --linecolor "BBBBBB" --pattern 'p86.*, linecolor="00FF00", showtitle=1 ; p25.*, linecolor="FF0000", showtitle=1' list_url_work2 |
---|
| 43 | |
---|
| 44 | """ |
---|
| 45 | |
---|
| 46 | options = """###################################################### |
---|
| 47 | Options: |
---|
| 48 | -h, -?, --help, -help |
---|
| 49 | Print this manual |
---|
| 50 | --period |
---|
| 51 | Use CumulPeriod rather than PeriodDateBegin |
---|
| 52 | --yscalelog |
---|
| 53 | Set a log axis for vertical axis (only with --period option) |
---|
| 54 | --linecolor FFFFFF |
---|
| 55 | color code in hexa |
---|
| 56 | --linewidth width |
---|
| 57 | width = float value in points |
---|
| 58 | --showtitle |
---|
| 59 | title will be displayed |
---|
| 60 | By default, titles are displayed only when mouse is passed over simulations |
---|
| 61 | --pattern 'pattern, options ; ...' |
---|
| 62 | ex: 'p86caub, linecolor="00FF00", showtitle=1 ; p86mart, linecolor="FF0000"' |
---|
| 63 | Use single quote to delimit the option and ; between patterns. |
---|
| 64 | Options are considered following the order : options from command, options from pattern option, options from list file. |
---|
| 65 | """ |
---|
| 66 | |
---|
| 67 | #====================================================== |
---|
| 68 | periodoption=0 |
---|
| 69 | yscalelogoption=0 |
---|
| 70 | linecoloroption=0 |
---|
| 71 | linewidthoption=0 |
---|
| 72 | showtitleoption=0 |
---|
| 73 | patternoption=0 |
---|
| 74 | while len(sys.argv[1:]) != 0 : |
---|
| 75 | if sys.argv[1] in ('-h','--help') : |
---|
| 76 | del(sys.argv[1]) |
---|
| 77 | print usage + options |
---|
| 78 | sys.exit(1) |
---|
| 79 | elif sys.argv[1] == '--period' : |
---|
| 80 | periodoption=1 |
---|
| 81 | del(sys.argv[1]) |
---|
| 82 | elif sys.argv[1] == '--yscalelog' : |
---|
| 83 | yscalelogoption=1 |
---|
| 84 | del(sys.argv[1]) |
---|
| 85 | elif sys.argv[1] == '--linecolor' : |
---|
| 86 | linecoloroptionvalue=sys.argv[2] |
---|
| 87 | linecoloroption=1 |
---|
| 88 | del(sys.argv[1]) |
---|
| 89 | del(sys.argv[1]) |
---|
| 90 | elif sys.argv[1] == '--linewidth' : |
---|
| 91 | linewidthoptionvalue=string.atof(sys.argv[2]) |
---|
| 92 | linewidthoption=1 |
---|
| 93 | del(sys.argv[1]) |
---|
| 94 | del(sys.argv[1]) |
---|
| 95 | elif sys.argv[1] == '--showtitle' : |
---|
| 96 | showtitleoptionvalue=True |
---|
| 97 | showtitleoption=1 |
---|
| 98 | del(sys.argv[1]) |
---|
| 99 | elif sys.argv[1] == '--pattern' : |
---|
| 100 | pattern=sys.argv[2].split(';') |
---|
| 101 | patternoption=1 |
---|
| 102 | del(sys.argv[1]) |
---|
| 103 | del(sys.argv[1]) |
---|
| 104 | elif re.match('-',sys.argv[1]) : |
---|
| 105 | print 'Error: option inconnu' |
---|
| 106 | print usage + options |
---|
| 107 | sys.exit(1) |
---|
| 108 | break |
---|
| 109 | else: |
---|
| 110 | break |
---|
| 111 | |
---|
| 112 | if len(sys.argv[1:]) != 1 : |
---|
| 113 | print usage + options |
---|
| 114 | sys.exit(1) |
---|
| 115 | |
---|
| 116 | #====================================================== |
---|
| 117 | fig = plt.figure() |
---|
| 118 | ax = fig.add_subplot(111) |
---|
| 119 | |
---|
| 120 | #====================================================== |
---|
| 121 | nbfile=len(sys.argv[1:])/2 |
---|
| 122 | |
---|
| 123 | #====================================================== |
---|
| 124 | finput=file(sys.argv[1]) |
---|
| 125 | |
---|
| 126 | simus_with_annotation=[] |
---|
| 127 | nbsimus=0 |
---|
| 128 | nbfiles=0 |
---|
| 129 | |
---|
| 130 | for line in finput : |
---|
| 131 | print '#===========================================' |
---|
| 132 | nbfiles=nbfiles+1 |
---|
| 133 | |
---|
| 134 | line=line.split(',') |
---|
| 135 | |
---|
| 136 | #--------------------------- |
---|
| 137 | # options from command |
---|
| 138 | fileruncard=line[0].strip() |
---|
| 139 | |
---|
| 140 | if not linecoloroption : |
---|
| 141 | linecolor="%06X" % random.randint(0, 16777215) # a random color for default |
---|
| 142 | else : |
---|
| 143 | linecolor=linecoloroptionvalue |
---|
| 144 | |
---|
| 145 | if not linewidthoption : |
---|
| 146 | linewidth=2.0 |
---|
| 147 | else : |
---|
| 148 | linewidth=linewidthoptionvalue |
---|
| 149 | |
---|
| 150 | if fileruncard[0:4] == 'http' : |
---|
| 151 | # remote file: http:// |
---|
| 152 | # http://dods.idris.fr/login |
---|
| 153 | if fileruncard[0:20] == 'http://dods.idris.fr' : |
---|
| 154 | title='.'.join(fileruncard.split('/')[3:-2]) |
---|
| 155 | else : |
---|
| 156 | # http://dods.extra.cea.fr/xxxx/login |
---|
| 157 | title='.'.join(fileruncard.split('/')[4:-2]) |
---|
| 158 | else : |
---|
| 159 | # local file: file:// |
---|
| 160 | title=os.path.basename(re.sub(r'_run.card',"",fileruncard)) |
---|
| 161 | |
---|
| 162 | if not showtitleoption : |
---|
| 163 | showtitle=0 |
---|
| 164 | else : |
---|
| 165 | showtitle=showtitleoptionvalue |
---|
| 166 | |
---|
| 167 | #--------------------------- |
---|
| 168 | # options from pattern option |
---|
| 169 | if patternoption : |
---|
| 170 | for pat in pattern : |
---|
| 171 | pat=pat.split(',') |
---|
| 172 | patternword=pat[0].strip() |
---|
| 173 | if re.search(patternword,fileruncard) : |
---|
| 174 | patternoptions=pat[1:] |
---|
| 175 | for i in range(0,len(patternoptions)) : |
---|
| 176 | exec patternoptions[i].strip() # set options if defined |
---|
| 177 | |
---|
| 178 | #--------------------------- |
---|
| 179 | # options from list file |
---|
| 180 | for i in range(1,len(line)) : |
---|
| 181 | #print i, line[i].strip() |
---|
| 182 | exec line[i].strip() # set options if defined |
---|
| 183 | |
---|
| 184 | #--------------------------- |
---|
| 185 | print 'file = ', fileruncard |
---|
| 186 | print 'linecolor = ', linecolor |
---|
| 187 | print 'linewidth = ', linewidth |
---|
| 188 | print 'title = ', title |
---|
| 189 | print 'showtitle = ', showtitle |
---|
| 190 | |
---|
| 191 | x,y1,y2 = [],[],[] |
---|
| 192 | lineref=['# CumulPeriod | PeriodDateBegin | PeriodDateEnd | RunDateBegin | RunDateEnd | RealCpuTime | UserCpuTime | SysCpuTime | ExeDate'] |
---|
| 193 | |
---|
| 194 | try: |
---|
| 195 | f=urllib2.urlopen(fileruncard) |
---|
| 196 | csv_reader = csv.reader(f) |
---|
| 197 | headerline = csv_reader.next() |
---|
| 198 | while headerline != lineref : # read until find lineref |
---|
| 199 | headerline = csv_reader.next() |
---|
| 200 | # read an extra line |
---|
| 201 | headerline = csv_reader.next() |
---|
| 202 | |
---|
| 203 | nblines=0 |
---|
| 204 | for line in csv_reader: |
---|
| 205 | a=line[0][1:] # to remove first character=# |
---|
| 206 | part=a.split('|') |
---|
| 207 | |
---|
| 208 | PeriodDateBegin=dt.datetime.strptime(part[1].strip(),'%Y%m%d') |
---|
| 209 | CumulPeriod=int(part[0].strip()) |
---|
| 210 | RunDateBegin=dt.datetime.strptime(part[3].strip(),'%Y-%m-%dT%H:%M:%S') |
---|
| 211 | RunDateEnd=dt.datetime.strptime(part[4].strip(),'%Y-%m-%dT%H:%M:%S') |
---|
| 212 | x.append(RunDateBegin) |
---|
| 213 | x.append(RunDateEnd) |
---|
| 214 | y1.append(PeriodDateBegin) |
---|
| 215 | y1.append(PeriodDateBegin) |
---|
| 216 | y2.append(CumulPeriod) |
---|
| 217 | y2.append(CumulPeriod) |
---|
| 218 | nblines=nblines+1 |
---|
| 219 | |
---|
| 220 | print '--> Read %d lines'%nblines |
---|
| 221 | if nblines < 10 : |
---|
| 222 | print '----> File skipped (not enough lines < 10)' |
---|
| 223 | continue |
---|
| 224 | |
---|
| 225 | if not periodoption : |
---|
| 226 | y=y1 |
---|
| 227 | else : |
---|
| 228 | y=y2 |
---|
| 229 | |
---|
| 230 | simu,=ax.plot(x,y,'-', linewidth=linewidth, color='#'+linecolor) |
---|
| 231 | lastx=x[-2] ; lasty=y[-2] # before last (last is None) |
---|
| 232 | simuname=fileruncard[:-9] # remove _run.card |
---|
| 233 | annotation=ax.annotate(title, xy=(lastx, lasty), xytext=(-20,20), |
---|
| 234 | textcoords='offset points', ha='center', va='bottom', |
---|
| 235 | bbox=dict(boxstyle='round,pad=0.4', fc='yellow', alpha=0.3), |
---|
| 236 | arrowprops=dict(arrowstyle='->', connectionstyle='arc3', |
---|
| 237 | color='black')) |
---|
| 238 | |
---|
| 239 | annotation.set_visible(showtitle) |
---|
| 240 | |
---|
| 241 | if not showtitle : # title will displayed when mouse over |
---|
| 242 | simus_with_annotation.append([simu,annotation]) |
---|
| 243 | |
---|
| 244 | nbsimus=nbsimus+1 |
---|
| 245 | |
---|
| 246 | except IOError : |
---|
| 247 | print "======> IOError when reading run.card" |
---|
| 248 | continue |
---|
| 249 | |
---|
| 250 | except : |
---|
| 251 | print "======> Error when reading run.card" |
---|
| 252 | continue |
---|
| 253 | |
---|
| 254 | finput.close() |
---|
| 255 | |
---|
| 256 | #====================================================== |
---|
| 257 | if nbsimus == 0 : |
---|
| 258 | print '#===========================================' |
---|
| 259 | print "======> No simulation to plot" |
---|
| 260 | sys.exit(1) |
---|
| 261 | |
---|
| 262 | #====================================================== |
---|
| 263 | # http://stackoverflow.com/questions/11537374/matplotlib-basemap-popup-box/11556140#11556140 |
---|
| 264 | |
---|
| 265 | def on_move(event): |
---|
| 266 | visibility_changed = False |
---|
| 267 | for simu, annotation in simus_with_annotation: |
---|
| 268 | should_be_visible = (simu.contains(event)[0] == True) |
---|
| 269 | |
---|
| 270 | if should_be_visible != annotation.get_visible(): |
---|
| 271 | visibility_changed = True |
---|
| 272 | x, y = event.xdata, event.ydata |
---|
| 273 | annotation.xy = x, y |
---|
| 274 | annotation.set_visible(should_be_visible) |
---|
| 275 | |
---|
| 276 | if visibility_changed: |
---|
| 277 | plt.draw() |
---|
| 278 | |
---|
| 279 | #====================================================== |
---|
| 280 | if not periodoption : |
---|
| 281 | #from matplotlib.ticker import MaxNLocator |
---|
| 282 | #ax.yaxis.set_major_locator(MaxNLocator(5)) |
---|
| 283 | from matplotlib.dates import YearLocator |
---|
| 284 | ax.yaxis.set_major_locator(YearLocator(50)) |
---|
| 285 | #from matplotlib.dates import AutoDateLocator |
---|
| 286 | #locator = AutoDateLocator(maxticks=5) |
---|
| 287 | #ax.yaxis.set_major_locator(locator) |
---|
| 288 | #ax.yaxis_date() |
---|
| 289 | |
---|
| 290 | else : # period option (not date) |
---|
| 291 | if yscalelogoption : |
---|
| 292 | ax.set_yscale('log') |
---|
| 293 | |
---|
| 294 | fig.autofmt_xdate() |
---|
| 295 | plt.grid(True) |
---|
| 296 | |
---|
| 297 | on_move_id = fig.canvas.mpl_connect('motion_notify_event', on_move) |
---|
| 298 | |
---|
| 299 | print '#===========================================' |
---|
| 300 | print 'Number of run.card indicated : %d' % nbfiles |
---|
| 301 | print 'Number of run.card processed : %d' % nbsimus |
---|
| 302 | print '#===========================================' |
---|
| 303 | |
---|
| 304 | plt.show() |
---|
| 305 | |
---|
| 306 | |
---|