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

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

put all path definitions in a seperate file

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