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