Completed
Push — master ( 3dcd25...20576f )
by Nicolas
01:26
created

GlancesGraph.generate_graph()   F

Complexity

Conditions 14

Size

Total Lines 95

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
c 1
b 0
f 0
dl 0
loc 95
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 GlancesGraph.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
"""Graph generation 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 GlancesGraph(object):
39
40
    """Thanks to this class, Glances can export history to graphs."""
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['description']
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
            # History
99
            h = stats.get_plugin(p).get_export_history()
100
            # Current plugin item history list
101
            ih = stats.get_plugin(p).get_items_history_list()
102
            # Check if we must process history
103
            if h is None or ih is None:
104
                # History (h) not available for plugin (p)
105
                continue
106
            # Init graph
107
            plt.clf()
108
            index_graph = 0
109
            handles = []
110
            labels = []
111
            for i in ih:
112
                if i['name'] in iterkeys(h):
113
                    # The key exist
114
                    # Add the curves in the current chart
115
                    logger.debug("Generate graph: %s %s" % (p, i['name']))
116
                    index_graph += 1
117
                    # Labels
118
                    handles.append(plt.Rectangle((0, 0), 1, 1, fc=self.get_graph_color(i), ec=self.get_graph_color(i), linewidth=2))
119
                    labels.append(self.get_graph_legend(i))
120
                    # Legend
121
                    plt.ylabel(self.get_graph_yunit(i, pre_label=''))
122
                    # Curves
123
                    plt.grid(True)
124
                    # Points are stored as tuple (date, value)
125
                    x, y = zip(*h[i['name']])
126
                    plt.plot_date(x, y,
127
                                  fmt='', drawstyle='default', linestyle='-',
128
                                  color=self.get_graph_color(i),
129
                                  xdate=True, ydate=False)
130
                    if index_graph == 1:
131
                        # Title only on top of the first graph
132
                        plt.title(p.capitalize())
133
                else:
134
                    # The key did not exist
135
                    # Find if anothers key ends with the key
136
                    # Ex: key='tx' => 'ethernet_tx'
137
                    # Add one curve per chart
138
                    stats_history_filtered = sorted([key for key in iterkeys(h) if key.endswith('_' + i['name'])])
139
                    logger.debug("Generate graphs: %s %s" %
140
                                 (p, stats_history_filtered))
141
                    if len(stats_history_filtered) > 0:
142
                        # Create 'n' graph
143
                        # Each graph iter through the stats
144
                        plt.clf()
145
                        index_item = 0
146
                        for k in stats_history_filtered:
147
                            index_item += 1
148
                            plt.subplot(
149
                                len(stats_history_filtered), 1, index_item)
150
                            # Legend
151
                            plt.ylabel(self.get_graph_yunit(i, pre_label=k))
152
                            # Curves
153
                            plt.grid(True)
154
                            # Points are stored as tuple (date, value)
155
                            x, y = zip(*h[k])
156
                            plt.plot_date(x, y,
157
                                          fmt='', drawstyle='default', linestyle='-',
158
                                          color=self.get_graph_color(i),
159
                                          xdate=True, ydate=False)
160
                            if index_item == 1:
161
                                # Title only on top of the first graph
162
                                plt.title(p.capitalize() + ' ' + i['name'])
163
                        # Save the graph to output file
164
                        fig = plt.gcf()
165
                        fig.set_size_inches(20, 5 * index_item)
166
                        plt.xlabel('Date')
167
                        plt.savefig(
168
                            os.path.join(self.output_folder, 'glances_%s_%s.png' % (p, i['name'])), dpi=72)
169
                        index_all += 1
170
171
            if index_graph > 0:
172
                # Save the graph to output file
173
                fig = plt.gcf()
174
                fig.set_size_inches(20, 10)
175
                plt.legend(handles, labels, loc=1, prop={'size': 9})
176
                plt.xlabel('Date')
177
                plt.savefig(os.path.join(self.output_folder, 'glances_%s.png' % p), dpi=72)
178
                index_all += 1
179
180
            plt.close()
181
182
        return index_all
183