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

Last change on this file since 2433 was 2433, checked in by labetoulle, 7 years ago

cleaning

  • Property svn:executable set to *
File size: 11.6 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.axhline(y=conso_per_day, color="blue", alpha=0.5,
183                   label="conso journaliÚre idéale (heures)")
184
185  ax_theo.plot(xcoord, theo_equs, "--",
186               color="firebrick", linewidth=0.5,
187               solid_capstyle="round", solid_joinstyle="round")
188  ax_theo.plot(xcoord, theo_uses, line_style, color="firebrick",
189               linewidth=1, markersize=8,
190               # solid_capstyle="round", solid_joinstyle="round",
191               label="conso théorique (%)")
192  ax_theo.plot(xcoord, real_uses, line_style, color="forestgreen",
193               linewidth=1, markersize=8,
194               # solid_capstyle="round", solid_joinstyle="round",
195               label="conso réelle (%)")
196
197
198########################################
199def plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title):
200  """
201  """
202  # ... Config axes ...
203  # -------------------
204  # 1) Range
205  xmin, xmax = xcoord[0]-1, xcoord[-1]+1
206  ax_conso.set_xlim(xmin, xmax)
207  ax_conso.set_ylim(0., ymax)
208  ax_theo.set_ylim(0., 100)
209
210  # 2) Ticks labels
211  inc_label = 7 if nb_items > 37 else 1
212  ax_conso.ticklabel_format(axis="y", style="sci", scilimits=(0, 0))
213  ax_conso.set_xticks(xcoord, minor=True)
214  ax_conso.set_xticks(xcoord[::inc_label], minor=False)
215  ax_conso.set_xticklabels(
216    xlabels[::inc_label], rotation="45", size="x-small"
217  )
218
219  # 3) Define axes title
220  ax_conso.set_ylabel("heures", fontweight="bold")
221  ax_theo.set_ylabel("%", fontweight="bold")
222
223  # ... Main title and legend ...
224  # -----------------------------
225  ax_conso.set_title(title, fontweight="bold", size="large")
226  ax_theo.legend(loc="upper right", fontsize="x-small", frameon=False)
227  ax_conso.legend(loc="upper left", fontsize="x-small", frameon=False)
228
229
230# ########################################
231# def plot_save(img_name, titre):
232#   """
233#   """
234#   dpi = 200.
235
236#   img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
237
238#   with PdfPages(img_in) as pdf:
239#     pdf.savefig(dpi=dpi)
240
241#     # pdf file's metadata
242#     d = pdf.infodict()
243#     d["Title"]   = titre
244#     d["Author"]  = os.path.basename(__file__)
245#     # d["Subject"] = "Time spent over specific commands during create_ts \
246#     #                 jobs at IDRIS and four configurations at TGCC"
247#     # d["Keywords"] = "bench create_ts TGCC IDRIS ncrcat"
248#     # d["CreationDate"] = dt.datetime(2009, 11, 13)
249#     # d["ModDate"] = dt.datetime.today()
250
251#   if os.path.isdir(DIR["SAVEPLOT"]):
252#     img_out = os.path.join(DIR["SAVEPLOT"],
253#                            "{}_{}.pdf".format(img_name, today))
254#     shutil.copy(img_in, img_out)
255
256
257########################################
258def get_arguments():
259  parser = ArgumentParser()
260  parser.add_argument("-v", "--verbose", action="store_true",
261                      help="verbose mode")
262  parser.add_argument("-f", "--full", action="store_true",
263                      help="plot the whole period")
264  parser.add_argument("-i", "--increment", action="store",
265                      type=int, default=1, dest="inc",
266                      help="sampling increment")
267  parser.add_argument("-r", "--range", action="store", nargs=2,
268                      type=string_to_date,
269                      help="date range: ssaa-mm-jj ssaa-mm-jj")
270  parser.add_argument("-m", "--max", action="store_true",
271                      help="plot with y_max = allocation")
272  parser.add_argument("-s", "--show", action="store_true",
273                      help="interactive mode")
274  parser.add_argument("-d", "--dods", action="store_true",
275                      help="copy output on dods")
276
277  return parser.parse_args()
278
279
280########################################
281if __name__ == '__main__':
282
283  # .. Initialization ..
284  # ====================
285  # ... Command line arguments ...
286  # ------------------------------
287  args = get_arguments()
288  if args.verbose:
289    print(args)
290
291  # ... Turn interactive mode off ...
292  # ---------------------------------
293  if not args.show:
294    import matplotlib
295    matplotlib.use('Agg')
296
297  import matplotlib.pyplot as plt
298  # from matplotlib.backends.backend_pdf import PdfPages
299
300  if not args.show:
301    plt.ioff()
302
303  # ... Files and directories ...
304  # -----------------------------
305  (file_param, file_utheo, file_data) = \
306      get_input_files(DIR["SAVEDATA"],
307                      [OUT["PARAM"], OUT["UTHEO"], OUT["BILAN"]])
308
309  img_name = "bilan"
310  today = os.path.basename(file_param).strip(OUT["PARAM"])
311
312  if args.verbose:
313    print(file_param)
314    print(file_utheo)
315    print(file_data)
316    print(img_name)
317    print(today)
318
319  # .. Get project info ..
320  # ======================
321  gencmip6 = Project()
322  gencmip6.fill_data(file_param)
323  gencmip6.get_date_init(file_utheo)
324
325  # .. Fill in conso data ..
326  # ========================
327  # ... Initialization ...
328  # ----------------------
329  bilan = BilanDict()
330  bilan.init_range(gencmip6.date_init, gencmip6.deadline)
331  # ... Extract data from file ...
332  # ------------------------------
333  bilan.fill_data(file_data)
334  # ... Compute theoratical use from known data  ...
335  # ------------------------------------------------
336  bilan.theo_equation()
337
338  # .. Extract data depending on C.L. arguments ..
339  # ==============================================
340  if args.full:
341    selected_items = bilan.get_items_in_full_range(args.inc)
342  elif args.range:
343    selected_items = bilan.get_items_in_range(
344      args.range[0], args.range[1], args.inc
345    )
346  else:
347    selected_items = bilan.get_items(args.inc)
348
349  # .. Compute data to be plotted ..
350  # ================================
351  nb_items = len(selected_items)
352
353  xcoord    = np.linspace(1, nb_items, num=nb_items)
354  xlabels   = ["{:%d-%m}".format(item.date)
355               for item in selected_items]
356  cumul     = np.array([item.conso for item in selected_items],
357                        dtype=float)
358  consos    = []
359  consos.append(cumul[0])
360  consos[1:nb_items] = cumul[1:nb_items] - cumul[0:nb_items-1]
361  consos    = np.array(consos, dtype=float)
362
363  conso_per_day = gencmip6.alloc / gencmip6.days
364
365  theo_uses = np.array([100.*item.theo_use for item in selected_items],
366                       dtype=float)
367  real_uses = np.array([100.*item.real_use for item in selected_items],
368                       dtype=float)
369  theo_equs = np.array([100.*item.theo_equ for item in selected_items],
370                       dtype=float)
371
372  # .. Plot stuff ..
373  # ================
374  # ... Initialize figure ...
375  # -------------------------
376  (fig, ax_conso, ax_theo) = plot_init()
377
378  # ... Plot data ...
379  # -----------------
380  plot_data(ax_conso, ax_theo, xcoord, xlabels,
381            consos, conso_per_day, theo_uses, real_uses, theo_equs)
382
383  # ... Tweak figure ...
384  # --------------------
385  if args.max:
386    ymax = gencmip6.alloc
387  else:
388    ymax = np.nanmax(consos) + np.nanmax(consos)*.1
389
390  title = "Consommation {}\n({:%d/%m/%Y} - {:%d/%m/%Y})".format(
391    gencmip6.project.upper(),
392    gencmip6.date_init,
393    gencmip6.deadline
394  )
395
396  plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title)
397
398  # ... Save figure ...
399  # -------------------
400  img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
401  img_out = os.path.join(DIR["SAVEPLOT"],
402                         "{}_{}.pdf".format(img_name, today))
403
404  plot_save(img_in, img_out, title)
405
406  # ... Publish figure on dods ...
407  # ------------------------------
408  if args.dods:
409    dods_cp(img_in)
410
411  if args.show:
412    plt.show()
413
414  exit(0)
415
Note: See TracBrowser for help on using the repository browser.