#!/bin/env python #====================================================== # Author: Patrick.Brockmann@cea.fr # # Date: 13/11/2012 # #====================================================== #====================================================== import csv import matplotlib.pyplot as plt import datetime as dt import sys, string, os, re import urllib2 import random #====================================================== usage = """###################################################### Usage: plot_runcard.py [-h] [--period] [--yscalelog] [--linewidth width] [--linecolor colorcode] [--showtitle] [--pattern 'pattern, options ; ...'] list Argument: Argument list is text file with one run.card file accessible by HTTP (http://...) or locally (file:///...) per line. For each line, you can add specific options (linecolor, linewidth, title, showtitle) separated by ',' (whatever order). For example : http://dods.extra.cea.fr/work/p86caub/IPSLCM5A/PROD/rcp85GHG/v3.rcp85GHG1/MONITORING/run.card , linecolor="AFBBAA", title="My text", showtitle=1 Notes: Default color are randomly choosen Default title is built from filename Examples: ./plot_runcard.py --linecolor "BBBBBB" --pattern 'p86caub, linecolor="00FF00", showtitle=1 ; p25mart, linecolor="FF0000", showtitle=1, linewidth=4' list_url_work2 ./plot_runcard.py --linecolor "BBBBBB" --pattern 'p86.*, linecolor="00FF00", showtitle=1 ; p25.*, linecolor="FF0000", showtitle=1' list_url_work2 """ options = """###################################################### Options: -h, -?, --help, -help Print this manual --period Use CumulPeriod rather than PeriodDateBegin --yscalelog Set a log axis for vertical axis (only with --period option) --linecolor FFFFFF color code in hexa --linewidth width width = float value in points --showtitle title will be displayed By default, titles are displayed only when mouse is passed over simulations --pattern 'pattern, options ; ...' ex: 'p86caub, linecolor="00FF00", showtitle=1 ; p86mart, linecolor="FF0000"' Use single quote to delimit the option and ; between patterns. Options are considered following the order : options from command, options from pattern option, options from list file. """ #====================================================== periodoption=0 yscalelogoption=0 linecoloroption=0 linewidthoption=0 showtitleoption=0 patternoption=0 while len(sys.argv[1:]) != 0 : if sys.argv[1] in ('-h','--help') : del(sys.argv[1]) print usage + options sys.exit(1) elif sys.argv[1] == '--period' : periodoption=1 del(sys.argv[1]) elif sys.argv[1] == '--yscalelog' : yscalelogoption=1 del(sys.argv[1]) elif sys.argv[1] == '--linecolor' : linecoloroptionvalue=sys.argv[2] linecoloroption=1 del(sys.argv[1]) del(sys.argv[1]) elif sys.argv[1] == '--linewidth' : linewidthoptionvalue=string.atof(sys.argv[2]) linewidthoption=1 del(sys.argv[1]) del(sys.argv[1]) elif sys.argv[1] == '--showtitle' : showtitleoptionvalue=True showtitleoption=1 del(sys.argv[1]) elif sys.argv[1] == '--pattern' : pattern=sys.argv[2].split(';') patternoption=1 del(sys.argv[1]) del(sys.argv[1]) elif re.match('-',sys.argv[1]) : print 'Error: option inconnu' print usage + options sys.exit(1) break else: break if len(sys.argv[1:]) != 1 : print usage + options sys.exit(1) #====================================================== fig = plt.figure() ax = fig.add_subplot(111) #====================================================== nbfile=len(sys.argv[1:])/2 #====================================================== finput=file(sys.argv[1]) simus_with_annotation=[] nbsimus=0 nbfiles=0 for line in finput : print '#===========================================' nbfiles=nbfiles+1 line=line.split(',') #--------------------------- # options from command fileruncard=line[0].strip() if not linecoloroption : linecolor="%06X" % random.randint(0, 16777215) # a random color for default else : linecolor=linecoloroptionvalue if not linewidthoption : linewidth=2.0 else : linewidth=linewidthoptionvalue if fileruncard[0:4] == 'http' : # remote file: http:// # http://dods.idris.fr/login if fileruncard[0:20] == 'http://dods.idris.fr' : title='.'.join(fileruncard.split('/')[3:-2]) else : # http://dods.extra.cea.fr/xxxx/login title='.'.join(fileruncard.split('/')[4:-2]) else : # local file: file:// title=os.path.basename(re.sub(r'_run.card',"",fileruncard)) if not showtitleoption : showtitle=0 else : showtitle=showtitleoptionvalue #--------------------------- # options from pattern option if patternoption : for pat in pattern : pat=pat.split(',') patternword=pat[0].strip() if re.search(patternword,fileruncard) : patternoptions=pat[1:] for i in range(0,len(patternoptions)) : exec patternoptions[i].strip() # set options if defined #--------------------------- # options from list file for i in range(1,len(line)) : #print i, line[i].strip() exec line[i].strip() # set options if defined #--------------------------- print 'file = ', fileruncard print 'linecolor = ', linecolor print 'linewidth = ', linewidth print 'title = ', title print 'showtitle = ', showtitle x,y1,y2 = [],[],[] lineref=['# CumulPeriod | PeriodDateBegin | PeriodDateEnd | RunDateBegin | RunDateEnd | RealCpuTime | UserCpuTime | SysCpuTime | ExeDate'] try: f=urllib2.urlopen(fileruncard) csv_reader = csv.reader(f) headerline = csv_reader.next() while headerline != lineref : # read until find lineref headerline = csv_reader.next() # read an extra line headerline = csv_reader.next() nblines=0 for line in csv_reader: a=line[0][1:] # to remove first character=# part=a.split('|') PeriodDateBegin=dt.datetime.strptime(part[1].strip(),'%Y%m%d') CumulPeriod=int(part[0].strip()) RunDateBegin=dt.datetime.strptime(part[3].strip(),'%Y-%m-%dT%H:%M:%S') RunDateEnd=dt.datetime.strptime(part[4].strip(),'%Y-%m-%dT%H:%M:%S') x.append(RunDateBegin) x.append(RunDateEnd) y1.append(PeriodDateBegin) y1.append(PeriodDateBegin) y2.append(CumulPeriod) y2.append(CumulPeriod) nblines=nblines+1 print '--> Read %d lines'%nblines if nblines < 10 : print '----> File skipped (not enough lines < 10)' continue if not periodoption : y=y1 else : y=y2 simu,=ax.plot(x,y,'-', linewidth=linewidth, color='#'+linecolor) lastx=x[-2] ; lasty=y[-2] # before last (last is None) simuname=fileruncard[:-9] # remove _run.card annotation=ax.annotate(title, xy=(lastx, lasty), xytext=(-20,20), textcoords='offset points', ha='center', va='bottom', bbox=dict(boxstyle='round,pad=0.4', fc='yellow', alpha=0.3), arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='black')) annotation.set_visible(showtitle) if not showtitle : # title will displayed when mouse over simus_with_annotation.append([simu,annotation]) nbsimus=nbsimus+1 except IOError : print "======> IOError when reading run.card" continue except : print "======> Error when reading run.card" continue finput.close() #====================================================== if nbsimus == 0 : print '#===========================================' print "======> No simulation to plot" sys.exit(1) #====================================================== # http://stackoverflow.com/questions/11537374/matplotlib-basemap-popup-box/11556140#11556140 def on_move(event): visibility_changed = False for simu, annotation in simus_with_annotation: should_be_visible = (simu.contains(event)[0] == True) if should_be_visible != annotation.get_visible(): visibility_changed = True x, y = event.xdata, event.ydata annotation.xy = x, y annotation.set_visible(should_be_visible) if visibility_changed: plt.draw() #====================================================== if not periodoption : #from matplotlib.ticker import MaxNLocator #ax.yaxis.set_major_locator(MaxNLocator(5)) from matplotlib.dates import YearLocator ax.yaxis.set_major_locator(YearLocator(50)) #from matplotlib.dates import AutoDateLocator #locator = AutoDateLocator(maxticks=5) #ax.yaxis.set_major_locator(locator) #ax.yaxis_date() else : # period option (not date) if yscalelogoption : ax.set_yscale('log') fig.autofmt_xdate() plt.grid(True) on_move_id = fig.canvas.mpl_connect('motion_notify_event', on_move) print '#===========================================' print 'Number of run.card indicated : %d' % nbfiles print 'Number of run.card processed : %d' % nbsimus print '#===========================================' plt.show()