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

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

plot daily consumption instead of cumulative total

  • Property svn:executable set to *
File size: 10.8 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, conso_per_day, 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  # ax_conso.plot(xcoord, conso_per_day, line_style, color="blue",
179  #               linewidth=1, markersize=8, alpha=0.5,
180  #               # solid_capstyle="round", solid_joinstyle="round",
181  #               label="conso journaliÚre idéale (heures)")
182  ax_conso.axhline(y=conso_per_day[0], 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########################################
231def plot_save(img_name):
232  """
233  """
234  dpi = 200.
235
236  with PdfPages(img_name) as pdf:
237    pdf.savefig(dpi=dpi)
238
239    # pdf file's metadata
240    d = pdf.infodict()
241    d["Title"]   = "Conso GENCMIP6"
242    d["Author"]  = "plot_bilan.py"
243    # d["Subject"] = "Time spent over specific commands during create_ts \
244    #                 jobs at IDRIS and four configurations at TGCC"
245    # d["Keywords"] = "bench create_ts TGCC IDRIS ncrcat"
246    # d["CreationDate"] = dt.datetime(2009, 11, 13)
247    # d["ModDate"] = dt.datetime.today()
248
249
250########################################
251def get_arguments():
252  parser = ArgumentParser()
253  parser.add_argument("-v", "--verbose", action="store_true",
254                      help="Verbose mode")
255  parser.add_argument("-f", "--full", action="store_true",
256                      help="plot the whole period")
257  parser.add_argument("-i", "--increment", action="store",
258                      type=int, default=1, dest="inc",
259                      help="sampling increment")
260  parser.add_argument("-r", "--range", action="store", nargs=2,
261                      type=string_to_date,
262                      help="date range: ssaa-mm-jj ssaa-mm-jj")
263  parser.add_argument("-m", "--max", action="store_true",
264                      help="plot with y_max = allocation")
265
266  return parser.parse_args()
267
268
269########################################
270if __name__ == '__main__':
271
272  # .. Initialization ..
273  # ====================
274  # ... Command line arguments ...
275  # ------------------------------
276  args = get_arguments()
277
278  # ... Files and directories ...
279  # -----------------------------
280  file_param = get_last_file(DIR["DATA"], OUT["PARAM"])
281  file_utheo = get_last_file(DIR["DATA"], OUT["UTHEO"])
282  file_bilan = get_last_file(DIR["DATA"], OUT["BILAN"])
283  img_name = "bilan.pdf"
284
285  if args.verbose:
286    print(file_param)
287    print(file_utheo)
288    print(file_bilan)
289    print(img_name)
290
291  # .. Get project info ..
292  # ======================
293  gencmip6 = Project()
294  gencmip6.fill_data(file_param)
295  gencmip6.get_date_init(file_utheo)
296
297  # .. Fill in conso data ..
298  # ========================
299  # ... Initialization ...
300  # ----------------------
301  bilan = BilanDict()
302  bilan.init_range(gencmip6.date_init, gencmip6.deadline)
303  # ... Extract data from file ...
304  # ------------------------------
305  bilan.fill_data(file_bilan)
306  # ... Compute theoratical use from known data  ...
307  # ------------------------------------------------
308  bilan.theo_equation()
309
310  # .. Extract data depending on C.L. arguments ..
311  # ==============================================
312  if args.full:
313    selected_items = bilan.get_items_in_full_range(args.inc)
314  elif args.range:
315    selected_items = bilan.get_items_in_range(
316      args.range[0], args.range[1], args.inc
317    )
318  else:
319    selected_items = bilan.get_items(args.inc)
320
321  # .. Compute data to be plotted ..
322  # ================================
323  nb_items = len(selected_items)
324
325  xcoord    = np.linspace(1, nb_items, num=nb_items)
326  xlabels   = ["{:%d-%m}".format(item.date)
327               for item in selected_items]
328  cumul     = np.array([item.conso for item in selected_items],
329                        dtype=float)
330  consos    = []
331  consos.append(cumul[0])
332  consos[1:nb_items] = cumul[1:nb_items] - cumul[0:nb_items-1]
333  consos    = np.array(consos, dtype=float)
334
335  conso_per_day = np.array([gencmip6.alloc / nb_items
336                              for item in selected_items], dtype=float)
337
338  theo_uses = np.array([100.*item.theo_use for item in selected_items],
339                       dtype=float)
340  real_uses = np.array([100.*item.real_use for item in selected_items],
341                       dtype=float)
342  theo_equs = np.array([100.*item.theo_equ for item in selected_items],
343                       dtype=float)
344
345  # .. Plot stuff ..
346  # ================
347  # ... Initialize figure ...
348  # -------------------------
349  (fig, ax_conso, ax_theo) = plot_init()
350
351  # ... Plot data ...
352  # -----------------
353  plot_data(ax_conso, ax_theo, xcoord, xlabels,
354            consos, conso_per_day, theo_uses, real_uses, theo_equs)
355
356  # ... Tweak figure ...
357  # --------------------
358  if args.max:
359    ymax = gencmip6.alloc
360  else:
361    ymax = np.nanmax(consos) + np.nanmax(consos)*.1
362
363  title = "Consommation {}\n({:%d/%m/%Y} - {:%d/%m/%Y})".format(
364    gencmip6.project.upper(),
365    gencmip6.date_init,
366    gencmip6.deadline
367  )
368
369  plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title)
370
371  # ... Save figure ...
372  # -------------------
373  plot_save(os.path.join(DIR["PLOT"], img_name))
374
375  plt.show()
Note: See TracBrowser for help on using the repository browser.