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

Last change on this file since 2413 was 2413, checked in by labetoulle, 9 years ago

Move all scripts to the same dir to use common configuration files

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