Completed
Push — master ( 1806d1...053f07 )
by Nicolas
01:42
created

glances.exports.GlancesHistory.generate_graph()   F

Complexity

Conditions 13

Size

Total Lines 86

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 13
dl 0
loc 86
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like glances.exports.GlancesHistory.generate_graph() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2015 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""History class."""
21
22
import os
23
24
from glances.compat import iterkeys
25
from glances.logger import logger
26
27
try:
28
    from matplotlib import __version__ as matplotlib_version
29
    import matplotlib.pyplot as plt
30
except ImportError:
31
    matplotlib_check = False
32
    logger.warning('Cannot load Matplotlib library. Please install it using "pip install matplotlib"')
33
else:
34
    matplotlib_check = True
35
    logger.info('Load Matplotlib version %s' % matplotlib_version)
36
37
38
class GlancesHistory(object):
39
40
    """This class define the object to manage stats history."""
41
42
    def __init__(self, output_folder):
43
        self.output_folder = output_folder
44
45
    def get_output_folder(self):
46
        """Return the output folder where the graph are generated."""
47
        return self.output_folder
48
49
    def graph_enabled(self):
50
        """Return True if Glances can generate history graphs."""
51
        return matplotlib_check
52
53
    def reset(self, stats):
54
        """Reset all the history."""
55
        if not self.graph_enabled():
56
            return False
57
        for p in stats.getAllPlugins():
58
            h = stats.get_plugin(p).get_stats_history()
59
            if h is not None:
60
                stats.get_plugin(p).reset_stats_history()
61
        return True
62
63
    def get_graph_color(self, item):
64
        """Get the item's color."""
65
        try:
66
            ret = item['color']
67
        except KeyError:
68
            return '#FFFFFF'
69
        else:
70
            return ret
71
72
    def get_graph_legend(self, item):
73
        """Get the item's legend."""
74
        return item['name']
75
76
    def get_graph_yunit(self, item, pre_label=''):
77
        """Get the item's Y unit."""
78
        try:
79
            unit = " (%s)" % item['y_unit']
80
        except KeyError:
81
            unit = ''
82
        if pre_label == '':
83
            label = ''
84
        else:
85
            label = pre_label.split('_')[0]
86
        return "%s%s" % (label, unit)
87
88
    def generate_graph(self, stats):
89
        """Generate graphs from plugins history.
90
91
        Return the number of output files generated by the function.
92
        """
93
        if not self.graph_enabled():
94
            return 0
95
96
        index_all = 0
97
        for p in stats.getAllPlugins():
98
            h = stats.get_plugin(p).get_stats_history()
99
            # Data
100
            if h is None:
101
                # History (h) not available for plugin (p)
102
                continue
103
            # Init graph
104
            plt.clf()
105
            index_graph = 0
106
            handles = []
107
            labels = []
108
            for i in stats.get_plugin(p).get_items_history_list():
109
                if i['name'] in iterkeys(h):
110
                    # The key exist
111
                    # Add the curves in the current chart
112
                    logger.debug("Generate graph: %s %s" % (p, i['name']))
113
                    index_graph += 1
114
                    # Labels
115
                    handles.append(plt.Rectangle((0, 0), 1, 1, fc=self.get_graph_color(i), ec=self.get_graph_color(i), linewidth=2))
116
                    labels.append(self.get_graph_legend(i))
117
                    # Legend
118
                    plt.ylabel(self.get_graph_yunit(i, pre_label=''))
119
                    # Curves
120
                    plt.grid(True)
121
                    plt.plot_date(h['date'], h[i['name']],
122
                                  fmt='', drawstyle='default', linestyle='-',
123
                                  color=self.get_graph_color(i),
124
                                  xdate=True, ydate=False)
125
                    if index_graph == 1:
126
                        # Title only on top of the first graph
127
                        plt.title(p.capitalize())
128
                else:
129
                    # The key did not exist
130
                    # Find if anothers key ends with the key
131
                    # Ex: key='tx' => 'ethernet_tx'
132
                    # Add one curve per chart
133
                    stats_history_filtered = sorted([key for key in iterkeys(h) if key.endswith('_' + i['name'])])
134
                    logger.debug("Generate graphs: %s %s" %
135
                                 (p, stats_history_filtered))
136
                    if len(stats_history_filtered) > 0:
137
                        # Create 'n' graph
138
                        # Each graph iter through the stats
139
                        plt.clf()
140
                        index_item = 0
141
                        for k in stats_history_filtered:
142
                            index_item += 1
143
                            plt.subplot(
144
                                len(stats_history_filtered), 1, index_item)
145
                            plt.ylabel(self.get_graph_yunit(i, pre_label=k))
146
                            plt.grid(True)
147
                            plt.plot_date(h['date'], h[k],
148
                                          fmt='', drawstyle='default', linestyle='-',
149
                                          color=self.get_graph_color(i),
150
                                          xdate=True, ydate=False)
151
                            if index_item == 1:
152
                                # Title only on top of the first graph
153
                                plt.title(p.capitalize() + ' ' + i['name'])
154
                        # Save the graph to output file
155
                        fig = plt.gcf()
156
                        fig.set_size_inches(20, 5 * index_item)
157
                        plt.xlabel('Date')
158
                        plt.savefig(
159
                            os.path.join(self.output_folder, 'glances_%s_%s.png' % (p, i['name'])), dpi=72)
160
                        index_all += 1
161
162
            if index_graph > 0:
163
                # Save the graph to output file
164
                fig = plt.gcf()
165
                fig.set_size_inches(20, 10)
166
                plt.legend(handles, labels, loc=1, prop={'size': 9})
167
                plt.xlabel('Date')
168
                plt.savefig(os.path.join(self.output_folder, 'glances_%s.png' % p), dpi=72)
169
                index_all += 1
170
171
            plt.close()
172
173
        return index_all
174