source: TOOLS/ConsoGENCMIP6/bin/plot_bilan.py @ 2427

Last change on this file since 2427 was 2427, checked in by labetoulle, 8 years ago

Move common functions to common module

  • Property svn:executable set to *
File size: 12.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# this must come first
5from __future__ import print_function, unicode_literals, division
6
7# standard library imports
8from argparse import ArgumentParser
9import os
10import os.path
11import datetime as dt
12import numpy as np
13
14# Application library imports
15from gencmip6 import *
16from gencmip6_path import *
17
18
19########################################
20class BilanDict(dict):
21  #---------------------------------------
22  def __init__(self):
23    self = {}
24
25  #---------------------------------------
26  def init_range(self, date_beg, date_end, inc=1):
27    """
28    """
29    delta = date_end - date_beg
30
31    (deb, fin) = (0, delta.days+1)
32
33    dates = (date_beg + dt.timedelta(days=i)
34             for i in xrange(deb, fin, inc))
35
36    for date in dates:
37      self.add_item(date)
38
39  #---------------------------------------
40  def fill_data(self, filein):
41    """
42    """
43    try:
44      data = np.genfromtxt(
45        filein,
46        skip_header=1,
47        converters={0: string_to_date,
48                    1: string_to_float,
49                    2: string_to_percent,
50                    3: string_to_percent},
51        missing_values="nan",
52      )
53    except:
54      print("Empty file {}".format(filein))
55      exit(1)
56
57    for date, conso, real_use, theo_use in data:
58      if date in self:
59        self.add_item(date, conso, real_use, theo_use)
60        self[date].fill()
61
62  #---------------------------------------
63  def add_item(self, date, conso=np.nan,
64               real_use=np.nan, theo_use=np.nan):
65    """
66    """
67    self[date] = Conso(date, conso, real_use, theo_use)
68
69  #---------------------------------------
70  def theo_equation(self):
71    """
72    """
73    (dates, theo_uses) = \
74      zip(*((item.date, item.theo_use)
75            for item in self.get_items_in_full_range()))
76
77    (idx_min, idx_max) = \
78        (np.nanargmin(theo_uses), np.nanargmax(theo_uses))
79
80    x1 = dates[idx_min].timetuple().tm_yday
81    x2 = dates[idx_max].timetuple().tm_yday
82
83    y1 = theo_uses[idx_min]
84    y2 = theo_uses[idx_max]
85
86    m = np.array([
87      [x1, 1.],
88      [x2, 1.]
89    ], dtype="float")
90    n = np.array([
91      y1,
92      y2
93    ], dtype="float")
94
95    try:
96      (a, b) = np.linalg.solve(m, n)
97    except np.linalg.linalg.LinAlgError:
98      (a, b) = (None, None)
99
100    if a and b:
101      for date in dates:
102        self[date].theo_equ = date.timetuple().tm_yday*a + b
103
104  #---------------------------------------
105  def get_items_in_range(self, date_beg, date_end, inc=1):
106    """
107    """
108    items = (item for item in self.itervalues()
109                   if item.date >= date_beg and
110                      item.date <= date_end)
111    items = sorted(items, key=lambda item: item.date)
112
113    return items[::inc]
114
115  #---------------------------------------
116  def get_items_in_full_range(self, inc=1):
117    """
118    """
119    items = (item for item in self.itervalues())
120    items = sorted(items, key=lambda item: item.date)
121
122    return items[::inc]
123
124  #---------------------------------------
125  def get_items(self, inc=1):
126    """
127    """
128    items = (item for item in self.itervalues()
129                   if item.isfilled())
130    items = sorted(items, key=lambda item: item.date)
131
132    return items[::inc]
133
134
135class Conso(object):
136  #---------------------------------------
137  def __init__(self, date, conso=np.nan,
138               real_use=np.nan, theo_use=np.nan):
139    self.date     = date
140    self.conso    = conso
141    self.real_use = real_use
142    self.theo_use = theo_use
143    self.theo_equ = np.nan
144    self.filled   = False
145
146  #---------------------------------------
147  def __repr__(self):
148    return "{:.2f} ({:.2%})".format(self.conso, self.real_use)
149
150  #---------------------------------------
151  def isfilled(self):
152    return self.filled
153
154  #---------------------------------------
155  def fill(self):
156    self.filled = True
157
158
159########################################
160def plot_init():
161  paper_size  = np.array([29.7, 21.0])
162  fig, ax_conso = plt.subplots(figsize=(paper_size/2.54))
163  ax_theo = ax_conso.twinx()
164
165  return fig, ax_conso, ax_theo
166
167
168########################################
169def plot_data(ax_conso, ax_theo, xcoord, xlabels,
170              consos, conso_per_day, theo_uses, real_uses, theo_equs):
171  """
172  """
173  if args.full:
174    line_style = "-"
175    line_width = 0.1
176  else:
177    line_style = "+-"
178    line_width = 0.2
179
180  ax_conso.bar(xcoord, consos, align="center", color="linen",
181               linewidth=line_width, label="conso (heures)")
182  # ax_conso.plot(xcoord, conso_per_day, line_style, color="blue",
183  #               linewidth=1, markersize=8, alpha=0.5,
184  #               # solid_capstyle="round", solid_joinstyle="round",
185  #               label="conso journaliÚre idéale (heures)")
186  ax_conso.axhline(y=conso_per_day[0], color="blue", alpha=0.5,
187                   label="conso journaliÚre idéale (heures)")
188
189  ax_theo.plot(xcoord, theo_equs, "--",
190               color="firebrick", linewidth=0.5,
191               solid_capstyle="round", solid_joinstyle="round")
192  ax_theo.plot(xcoord, theo_uses, line_style, color="firebrick",
193               linewidth=1, markersize=8,
194               # solid_capstyle="round", solid_joinstyle="round",
195               label="conso théorique (%)")
196  ax_theo.plot(xcoord, real_uses, line_style, color="forestgreen",
197               linewidth=1, markersize=8,
198               # solid_capstyle="round", solid_joinstyle="round",
199               label="conso réelle (%)")
200
201
202########################################
203def plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title):
204  """
205  """
206  # ... Config axes ...
207  # -------------------
208  # 1) Range
209  xmin, xmax = xcoord[0]-1, xcoord[-1]+1
210  ax_conso.set_xlim(xmin, xmax)
211  ax_conso.set_ylim(0., ymax)
212  ax_theo.set_ylim(0., 100)
213
214  # 2) Ticks labels
215  inc_label = 7 if nb_items > 37 else 1
216  ax_conso.ticklabel_format(axis="y", style="sci", scilimits=(0, 0))
217  ax_conso.set_xticks(xcoord, minor=True)
218  ax_conso.set_xticks(xcoord[::inc_label], minor=False)
219  ax_conso.set_xticklabels(
220    xlabels[::inc_label], rotation="45", size="x-small"
221  )
222
223  # 3) Define axes title
224  ax_conso.set_ylabel("heures", fontweight="bold")
225  ax_theo.set_ylabel("%", fontweight="bold")
226
227  # ... Main title and legend ...
228  # -----------------------------
229  ax_conso.set_title(title, fontweight="bold", size="large")
230  ax_theo.legend(loc="upper right", fontsize="x-small", frameon=False)
231  ax_conso.legend(loc="upper left", fontsize="x-small", frameon=False)
232
233
234# ########################################
235# def plot_save(img_name, titre):
236#   """
237#   """
238#   dpi = 200.
239
240#   img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
241
242#   with PdfPages(img_in) as pdf:
243#     pdf.savefig(dpi=dpi)
244
245#     # pdf file's metadata
246#     d = pdf.infodict()
247#     d["Title"]   = titre
248#     d["Author"]  = os.path.basename(__file__)
249#     # d["Subject"] = "Time spent over specific commands during create_ts \
250#     #                 jobs at IDRIS and four configurations at TGCC"
251#     # d["Keywords"] = "bench create_ts TGCC IDRIS ncrcat"
252#     # d["CreationDate"] = dt.datetime(2009, 11, 13)
253#     # d["ModDate"] = dt.datetime.today()
254
255#   if os.path.isdir(DIR["SAVEPLOT"]):
256#     img_out = os.path.join(DIR["SAVEPLOT"],
257#                            "{}_{}.pdf".format(img_name, today))
258#     shutil.copy(img_in, img_out)
259
260
261########################################
262def get_arguments():
263  parser = ArgumentParser()
264  parser.add_argument("-v", "--verbose", action="store_true",
265                      help="verbose mode")
266  parser.add_argument("-f", "--full", action="store_true",
267                      help="plot the whole period")
268  parser.add_argument("-i", "--increment", action="store",
269                      type=int, default=1, dest="inc",
270                      help="sampling increment")
271  parser.add_argument("-r", "--range", action="store", nargs=2,
272                      type=string_to_date,
273                      help="date range: ssaa-mm-jj ssaa-mm-jj")
274  parser.add_argument("-m", "--max", action="store_true",
275                      help="plot with y_max = allocation")
276  parser.add_argument("-s", "--show", action="store_true",
277                      help="interactive mode")
278  parser.add_argument("-d", "--dods", action="store_true",
279                      help="copy output on dods")
280
281  return parser.parse_args()
282
283
284########################################
285if __name__ == '__main__':
286
287  # .. Initialization ..
288  # ====================
289  # ... Command line arguments ...
290  # ------------------------------
291  args = get_arguments()
292  if args.verbose:
293    print(args)
294
295  # ... Turn interactive mode off ...
296  # ---------------------------------
297  if not args.show:
298    import matplotlib
299    matplotlib.use('Agg')
300
301  import matplotlib.pyplot as plt
302  # from matplotlib.backends.backend_pdf import PdfPages
303
304  if not args.show:
305    plt.ioff()
306
307  # ... Files and directories ...
308  # -----------------------------
309  (file_param, file_utheo, file_data) = \
310      get_input_files(DIR["SAVEDATA"],
311                      [OUT["PARAM"], OUT["UTHEO"], OUT["BILAN"]])
312
313  img_name = "bilan"
314  today = os.path.basename(file_param).strip(OUT["PARAM"])
315
316  if args.verbose:
317    print(file_param)
318    print(file_utheo)
319    print(file_data)
320    print(img_name)
321    print(today)
322
323  # .. Get project info ..
324  # ======================
325  gencmip6 = Project()
326  gencmip6.fill_data(file_param)
327  gencmip6.get_date_init(file_utheo)
328
329  # .. Fill in conso data ..
330  # ========================
331  # ... Initialization ...
332  # ----------------------
333  bilan = BilanDict()
334  bilan.init_range(gencmip6.date_init, gencmip6.deadline)
335  # ... Extract data from file ...
336  # ------------------------------
337  bilan.fill_data(file_data)
338  # ... Compute theoratical use from known data  ...
339  # ------------------------------------------------
340  bilan.theo_equation()
341
342  # .. Extract data depending on C.L. arguments ..
343  # ==============================================
344  if args.full:
345    selected_items = bilan.get_items_in_full_range(args.inc)
346  elif args.range:
347    selected_items = bilan.get_items_in_range(
348      args.range[0], args.range[1], args.inc
349    )
350  else:
351    selected_items = bilan.get_items(args.inc)
352
353  # .. Compute data to be plotted ..
354  # ================================
355  nb_items = len(selected_items)
356
357  xcoord    = np.linspace(1, nb_items, num=nb_items)
358  xlabels   = ["{:%d-%m}".format(item.date)
359               for item in selected_items]
360  cumul     = np.array([item.conso for item in selected_items],
361                        dtype=float)
362  consos    = []
363  consos.append(cumul[0])
364  consos[1:nb_items] = cumul[1:nb_items] - cumul[0:nb_items-1]
365  consos    = np.array(consos, dtype=float)
366
367  conso_per_day = np.array([gencmip6.alloc / nb_items
368                              for item in selected_items], dtype=float)
369
370  theo_uses = np.array([100.*item.theo_use for item in selected_items],
371                       dtype=float)
372  real_uses = np.array([100.*item.real_use for item in selected_items],
373                       dtype=float)
374  theo_equs = np.array([100.*item.theo_equ for item in selected_items],
375                       dtype=float)
376
377  # .. Plot stuff ..
378  # ================
379  # ... Initialize figure ...
380  # -------------------------
381  (fig, ax_conso, ax_theo) = plot_init()
382
383  # ... Plot data ...
384  # -----------------
385  plot_data(ax_conso, ax_theo, xcoord, xlabels,
386            consos, conso_per_day, theo_uses, real_uses, theo_equs)
387
388  # ... Tweak figure ...
389  # --------------------
390  if args.max:
391    ymax = gencmip6.alloc
392  else:
393    ymax = np.nanmax(consos) + np.nanmax(consos)*.1
394
395  title = "Consommation {}\n({:%d/%m/%Y} - {:%d/%m/%Y})".format(
396    gencmip6.project.upper(),
397    gencmip6.date_init,
398    gencmip6.deadline
399  )
400
401  plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title)
402
403  # ... Save figure ...
404  # -------------------
405  img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
406  img_out = os.path.join(DIR["SAVEPLOT"],
407                         "{}_{}.pdf".format(img_name, today))
408
409  plot_save(img_in, img_out, "Conso GENCMIP6")
410
411  # ... Publish figure on dods ...
412  # ------------------------------
413  if args.dods:
414    dods_cp(img_in)
415
416  if args.show:
417    plt.show()
418
419  exit(0)
Note: See TracBrowser for help on using the repository browser.