1#    Copyright 2015-2017 ARM Limited
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16"""This is the template class that all Plotters inherit"""
17from abc import abstractmethod, ABCMeta
18from pandas import DataFrame
19import re
20from trappy.utils import listify
21from functools import reduce
22# pylint: disable=R0921
23# pylint: disable=R0903
24
25
26class AbstractDataPlotter(object):
27    """This is an abstract data plotting Class defining an interface
28       for the various Plotting Classes"""
29
30    __metaclass__ = ABCMeta
31
32    def __init__(self, traces=None, attr=None, templates=None):
33        self._event_map = {}
34        self._attr = attr if attr else {}
35        self.traces = traces
36        self.templates = templates
37
38    @abstractmethod
39    def view(self):
40        """View the graph"""
41        raise NotImplementedError("Method Not Implemented")
42
43    @abstractmethod
44    def savefig(self, path):
45        """Save the image as a file
46
47        :param path: Location of the Saved File
48        :type path: str
49        """
50        raise NotImplementedError("Method Not Implemented")
51
52    def _check_data(self):
53        """Internal function to check the received data"""
54
55        data = listify(self.traces)
56
57        if len(data):
58            mask = map(lambda x: isinstance(x, DataFrame), data)
59            data_frame = reduce(lambda x, y: x and y, mask)
60            sig_or_template = self.templates or "signals" in self._attr
61
62            if not data_frame and not sig_or_template:
63                raise ValueError(
64                    "Cannot understand data. Accepted DataFormats are pandas.DataFrame or trappy.FTrace/BareTrace/SysTrace (with templates)")
65            elif data_frame and "column" not in self._attr:
66                raise ValueError("Column not specified for DataFrame input")
67        else:
68            raise ValueError("Empty Data received")
69
70    def _parse_value(self, signal_def):
71        """Parse a signal definition into a (template, column) tuple
72
73        :param signal_def: A signal definition. E.g. "trace_class:column"
74        :type signal_def: str
75        """
76
77        match = re.match(r"(?P<event>[^:]+):(?P<column>[^:]+)(?P<color>:.+)?",
78                         signal_def)
79        if not match:
80            raise ValueError(
81                'Invalid signal definition "{}". '
82                'Should have the form "trace_class:column" '
83                'e.g. "cpu_frequency:frequency"'.format(signal_def))
84        event = match.group("event")
85        column = match.group("column")
86        color_match = match.group("color")
87        if color_match:
88            color_list = color_match[1:].split(",", 2)
89            color = [int(n, 16) if n.startswith("0x") else int(n) for n in color_list]
90        else:
91            color = None
92
93        try:
94            return self._event_map[event], column, color
95        except KeyError:
96            for trace in listify(self.traces):
97
98                if event in trace.class_definitions:
99                    self._event_map[event] = trace.class_definitions[event]
100                    return self._event_map[event], column, color
101
102            raise ValueError(
103                "Event: " +
104                event +
105                " not found in Trace Object")
106
107    def _describe_signals(self):
108        """Internal Function for populating templates and columns
109        from signals
110        """
111
112        if "column" in self._attr or self.templates:
113            raise ValueError("column/templates specified with values")
114
115        self._attr["column"] = []
116        self.templates = []
117        colors = []
118
119        for value in listify(self._attr["signals"]):
120            template, column, color = self._parse_value(value)
121            self.templates.append(template)
122            self._attr["column"].append(column)
123            colors.append(color)
124
125        if any(colors):
126            self._attr["colors"] = colors
127