VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuihlpgraphmatplotlib.py@ 65132

Last change on this file since 65132 was 62484, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuihlpgraphmatplotlib.py 62484 2016-07-22 18:35:33Z vboxsync $
3
4"""
5Test Manager Web-UI - Graph Helpers - Implemented using matplotlib.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2016 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 62484 $"
30
31# Standard Python Import and extensions installed on the system.
32import re;
33import StringIO;
34
35import matplotlib; # pylint: disable=F0401
36matplotlib.use('Agg'); # Force backend.
37import matplotlib.pyplot; # pylint: disable=F0401
38from numpy import arange as numpy_arange; # pylint: disable=E0611,E0401
39
40# Validation Kit imports.
41from testmanager.webui.wuihlpgraphbase import WuiHlpGraphBase;
42
43
44class WuiHlpGraphMatplotlibBase(WuiHlpGraphBase):
45 """ Base class for the matplotlib graphs. """
46
47 def __init__(self, sId, oData, oDisp):
48 WuiHlpGraphBase.__init__(self, sId, oData, oDisp);
49 self._fXkcdStyle = True;
50
51 def setXkcdStyle(self, fEnabled = True):
52 """ Enables xkcd style graphs for implementations that supports it. """
53 self._fXkcdStyle = fEnabled;
54 return True;
55
56 def _createFigure(self):
57 """
58 Wrapper around matplotlib.pyplot.figure that feeds the figure the
59 basic graph configuration.
60 """
61 if self._fXkcdStyle and matplotlib.__version__ > '1.2.9':
62 matplotlib.pyplot.xkcd(); # pylint: disable=E1101
63 matplotlib.rcParams.update({'font.size': self._cPtFont});
64
65 oFigure = matplotlib.pyplot.figure(figsize = (float(self._cxGraph) / self._cDpiGraph,
66 float(self._cyGraph) / self._cDpiGraph),
67 dpi = self._cDpiGraph);
68 return oFigure;
69
70 def _produceSvg(self, oFigure, fTightLayout = True):
71 """ Creates an SVG string from the given figure. """
72 oOutput = StringIO.StringIO();
73 if fTightLayout:
74 oFigure.tight_layout();
75 oFigure.savefig(oOutput, format = 'svg');
76
77 if self._oDisp and self._oDisp.isBrowserGecko('20100101'):
78 # This browser will stretch images to fit if no size or width is given.
79 sSubstitute = r'\1 \3 reserveAspectRatio="xMidYMin meet"';
80 else:
81 # Chrome and IE likes to have the sizes as well as the viewBox.
82 sSubstitute = r'\1 \3 reserveAspectRatio="xMidYMin meet" \2 \4';
83 return re.sub(r'(<svg) (height="\d+pt") (version="\d+.\d+" viewBox="\d+ \d+ \d+ \d+") (width="\d+pt")',
84 sSubstitute,
85 oOutput.getvalue().decode('utf8'),
86 count = 1);
87
88class WuiHlpBarGraph(WuiHlpGraphMatplotlibBase):
89 """
90 Bar graph.
91 """
92
93 def __init__(self, sId, oData, oDisp = None):
94 WuiHlpGraphMatplotlibBase.__init__(self, sId, oData, oDisp);
95 self.fpMax = None;
96 self.fpMin = 0.0;
97 self.cxBarWidth = None;
98
99 def setRangeMax(self, fpMax):
100 """ Sets the max range."""
101 self.fpMax = float(fpMax);
102 return None;
103
104 def renderGraph(self): # pylint: disable=R0914
105 aoTable = self._oData.aoTable;
106
107 #
108 # Extract/structure the required data.
109 #
110 aoSeries = list();
111 for j in range(len(aoTable[1].aoValues)):
112 aoSeries.append(list());
113 asNames = list();
114 oXRange = numpy_arange(self._oData.getGroupCount());
115 fpMin = self.fpMin;
116 fpMax = self.fpMax;
117 if self.fpMax is None:
118 fpMax = float(aoTable[1].aoValues[0]);
119
120 for i in range(1, len(aoTable)):
121 asNames.append(aoTable[i].sName);
122 for j in range(len(aoTable[i].aoValues)):
123 fpValue = float(aoTable[i].aoValues[j]);
124 aoSeries[j].append(fpValue);
125 if fpValue < fpMin:
126 fpMin = fpValue;
127 if fpValue > fpMax:
128 fpMax = fpValue;
129
130 fpMid = fpMin + (fpMax - fpMin) / 2.0;
131
132 if self.cxBarWidth is None:
133 self.cxBarWidth = 1.0 / (len(aoTable[0].asValues) + 1.1);
134
135 # Render the PNG.
136 oFigure = self._createFigure();
137 oSubPlot = oFigure.add_subplot(1, 1, 1);
138
139 aoBars = list();
140 for i, _ in enumerate(aoSeries):
141 sColor = self.calcSeriesColor(i);
142 aoBars.append(oSubPlot.bar(oXRange + self.cxBarWidth * i,
143 aoSeries[i],
144 self.cxBarWidth,
145 color = sColor,
146 align = 'edge'));
147
148 #oSubPlot.set_title('Title')
149 #oSubPlot.set_xlabel('X-axis')
150 #oSubPlot.set_xticks(oXRange + self.cxBarWidth);
151 oSubPlot.set_xticks(oXRange);
152 oLegend = oSubPlot.legend(aoTable[0].asValues, loc = 'best', fancybox = True);
153 oLegend.get_frame().set_alpha(0.5);
154 oSubPlot.set_xticklabels(asNames, ha = "left");
155 #oSubPlot.set_ylabel('Y-axis')
156 oSubPlot.set_yticks(numpy_arange(fpMin, fpMax + (fpMax - fpMin) / 10 * 0, fpMax / 10));
157 oSubPlot.grid(True);
158 fpPadding = (fpMax - fpMin) * 0.02;
159 for i, _ in enumerate(aoBars):
160 aoRects = aoBars[i]
161 for j, _ in enumerate(aoRects):
162 oRect = aoRects[j];
163 fpValue = float(aoTable[j + 1].aoValues[i]);
164 if fpValue <= fpMid:
165 oSubPlot.text(oRect.get_x() + oRect.get_width() / 2.0,
166 oRect.get_height() + fpPadding,
167 aoTable[j + 1].asValues[i],
168 ha = 'center', va = 'bottom', rotation = 'vertical', alpha = 0.6, fontsize = 'small');
169 else:
170 oSubPlot.text(oRect.get_x() + oRect.get_width() / 2.0,
171 oRect.get_height() - fpPadding,
172 aoTable[j + 1].asValues[i],
173 ha = 'center', va = 'top', rotation = 'vertical', alpha = 0.6, fontsize = 'small');
174
175 return self._produceSvg(oFigure);
176
177
178
179
180class WuiHlpLineGraph(WuiHlpGraphMatplotlibBase):
181 """
182 Line graph.
183 """
184
185 def __init__(self, sId, oData, oDisp = None, fErrorBarY = False):
186 # oData must be a WuiHlpGraphDataTableEx like object.
187 WuiHlpGraphMatplotlibBase.__init__(self, sId, oData, oDisp);
188 self._cMaxErrorBars = 12;
189 self._fErrorBarY = fErrorBarY;
190
191 def setErrorBarY(self, fEnable):
192 """ Enables or Disables error bars, making this work like a line graph. """
193 self._fErrorBarY = fEnable;
194 return True;
195
196 def renderGraph(self): # pylint: disable=R0914
197 aoSeries = self._oData.aoSeries;
198
199 oFigure = self._createFigure();
200 oSubPlot = oFigure.add_subplot(1, 1, 1);
201 if self._oData.sYUnit is not None:
202 oSubPlot.set_ylabel(self._oData.sYUnit);
203 if self._oData.sXUnit is not None:
204 oSubPlot.set_xlabel(self._oData.sXUnit);
205
206 cSeriesNames = 0;
207 cYMin = 1000;
208 cYMax = 0;
209 for iSeries, oSeries in enumerate(aoSeries):
210 sColor = self.calcSeriesColor(iSeries);
211 cYMin = min(cYMin, min(oSeries.aoYValues));
212 cYMax = max(cYMax, max(oSeries.aoYValues));
213 if not self._fErrorBarY:
214 oSubPlot.errorbar(oSeries.aoXValues, oSeries.aoYValues, color = sColor);
215 elif len(oSeries.aoXValues) > self._cMaxErrorBars:
216 if matplotlib.__version__ < '1.3.0':
217 oSubPlot.errorbar(oSeries.aoXValues, oSeries.aoYValues, color = sColor);
218 else:
219 oSubPlot.errorbar(oSeries.aoXValues, oSeries.aoYValues,
220 yerr = [oSeries.aoYErrorBarBelow, oSeries.aoYErrorBarAbove],
221 errorevery = len(oSeries.aoXValues) / self._cMaxErrorBars,
222 color = sColor );
223 else:
224 oSubPlot.errorbar(oSeries.aoXValues, oSeries.aoYValues,
225 yerr = [oSeries.aoYErrorBarBelow, oSeries.aoYErrorBarAbove],
226 color = sColor);
227 cSeriesNames += oSeries.sName is not None;
228
229 if cYMin != 0 or cYMax != 0:
230 oSubPlot.set_ylim(bottom = 0);
231
232 if cSeriesNames > 0:
233 oLegend = oSubPlot.legend([oSeries.sName for oSeries in aoSeries], loc = 'best', fancybox = True);
234 oLegend.get_frame().set_alpha(0.5);
235
236 if self._sTitle is not None:
237 oSubPlot.set_title(self._sTitle);
238
239 if self._cxGraph >= 256:
240 oSubPlot.minorticks_on();
241 oSubPlot.grid(True, 'major', axis = 'both');
242 oSubPlot.grid(True, 'both', axis = 'x');
243
244 if True: # pylint: disable=W0125
245 # oSubPlot.axis('off');
246 #oSubPlot.grid(True, 'major', axis = 'none');
247 #oSubPlot.grid(True, 'both', axis = 'none');
248 matplotlib.pyplot.setp(oSubPlot, xticks = [], yticks = []);
249
250 return self._produceSvg(oFigure);
251
252
253class WuiHlpLineGraphErrorbarY(WuiHlpLineGraph):
254 """
255 Line graph with an errorbar for the Y axis.
256 """
257
258 def __init__(self, sId, oData, oDisp = None):
259 WuiHlpLineGraph.__init__(self, sId, oData, fErrorBarY = True);
260
261
262class WuiHlpMiniSuccessRateGraph(WuiHlpGraphMatplotlibBase):
263 """
264 Mini rate graph.
265 """
266
267 def __init__(self, sId, oData, oDisp = None):
268 """
269 oData must be a WuiHlpGraphDataTableEx like object, but only aoSeries,
270 aoSeries[].aoXValues, and aoSeries[].aoYValues will be used. The
271 values are expected to be a percentage, i.e. values between 0 and 100.
272 """
273 WuiHlpGraphMatplotlibBase.__init__(self, sId, oData, oDisp);
274 self.setFontSize(6);
275
276 def renderGraph(self): # pylint: disable=R0914
277 assert len(self._oData.aoSeries) == 1;
278 oSeries = self._oData.aoSeries[0];
279
280 # hacking
281 #self.setWidth(512);
282 #self.setHeight(128);
283 # end
284
285 oFigure = self._createFigure();
286 from mpl_toolkits.axes_grid.axislines import SubplotZero; # pylint: disable=E0401
287 oAxis = SubplotZero(oFigure, 111);
288 oFigure.add_subplot(oAxis);
289
290 # Disable all the normal axis.
291 oAxis.axis['right'].set_visible(False)
292 oAxis.axis['top'].set_visible(False)
293 oAxis.axis['bottom'].set_visible(False)
294 oAxis.axis['left'].set_visible(False)
295
296 # Use the zero axis instead.
297 oAxis.axis['yzero'].set_axisline_style('-|>');
298 oAxis.axis['yzero'].set_visible(True);
299 oAxis.axis['xzero'].set_axisline_style('-|>');
300 oAxis.axis['xzero'].set_visible(True);
301
302 if oSeries.aoYValues[-1] == 100:
303 sColor = 'green';
304 elif oSeries.aoYValues[-1] > 75:
305 sColor = 'yellow';
306 else:
307 sColor = 'red';
308 oAxis.plot(oSeries.aoXValues, oSeries.aoYValues, '.-', color = sColor, linewidth = 3);
309 oAxis.fill_between(oSeries.aoXValues, oSeries.aoYValues, facecolor = sColor, alpha = 0.5)
310
311 oAxis.set_xlim(left = -0.01);
312 oAxis.set_xticklabels([]);
313 oAxis.set_xmargin(1);
314
315 oAxis.set_ylim(bottom = 0, top = 100);
316 oAxis.set_yticks([0, 50, 100]);
317 oAxis.set_ylabel('%');
318 #oAxis.set_yticklabels([]);
319 oAxis.set_yticklabels(['', '%', '']);
320
321 return self._produceSvg(oFigure, False);
322
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette