def plot(self, level, per_line=3): """Temporary function to plot data. Expected to be implemented in plotter """ num_plots = self._first_agg.topology.level_span(level) result_1 = self._first_agg.aggregate(level=level, **self._agg_kwargs) result_2 = self._second_agg.aggregate(level=level, **self._agg_kwargs) layout = PlotLayout(per_line, num_plots) plot_index = 0 for group_id, result_group in enumerate(result_1): s_x = result_group s_y = result_2[group_id] s_x = self._resample(s_x) s_y = self._resample(s_y) s_x, s_y = shift_series(s_x, s_y, self._shift) ymax = 1.25 + max(max(s_x.values), max(s_y.values)) + 1 ymin = min(min(s_x.values), min(s_y.values)) - 1 ylim = [ymin, ymax] ylim = [-1, 3] axis = layout.get_axis(plot_index) axis.plot(s_x.index, s_x.values) axis.plot(s_y.index, s_y.values) axis.set_ylim(ylim) plot_index += 1 layout.finish(plot_index)
def plot(self, level, per_line=3): """Temporary function to plot data. Expected to be implemented in plotter :param level: Topological Level (level in :mod:`trappy.stats.Topology`) :type level: str :param per_line: Number of plots per line :type per_line: int """ from trappy.plotter.PlotLayout import PlotLayout num_plots = self._first_agg.topology.level_span(level) result_1 = self._first_agg.aggregate(level=level, **self._agg_kwargs) result_2 = self._second_agg.aggregate(level=level, **self._agg_kwargs) layout = PlotLayout(per_line, num_plots) plot_index = 0 for group_id, result_group in enumerate(result_1): s_x = result_group s_y = result_2[group_id] s_x = self._resample(s_x) s_y = self._resample(s_y) s_x, s_y = shift_series(s_x, s_y, self._shift) ymax = 1.25 + max(max(s_x.values), max(s_y.values)) + 1 ymin = min(min(s_x.values), min(s_y.values)) - 1 ylim = [ymin, ymax] ylim = [-1, 3] axis = layout.get_axis(plot_index) axis.plot(s_x.index, s_x.values) axis.plot(s_y.index, s_y.values) axis.set_ylim(ylim) plot_index += 1 layout.finish(plot_index)
class StaticPlot(with_metaclass(ABCMeta, AbstractDataPlotter)): """ This class uses :mod:`trappy.plotter.Constraint.Constraint` to represent different permutations of input parameters. These constraints are generated by creating an instance of :mod:`trappy.plotter.Constraint.ConstraintManager`. :param traces: The input data :type traces: a list of :mod:`trappy.trace.FTrace`, :mod:`trappy.trace.SysTrace`, :mod:`trappy.trace.BareTrace` or :mod:`pandas.DataFrame` or a single instance of them. :param column: specifies the name of the column to be plotted. :type column: (str, list(str)) :param templates: TRAPpy events .. note:: This is not required if a :mod:`pandas.DataFrame` is used :type templates: :mod:`trappy.base.Base` :param filters: Filter the column to be plotted as per the specified criteria. For Example: :: filters = { "pid": [ 3338 ], "cpu": [0, 2, 4], } :type filters: dict :param per_line: Used to control the number of graphs in each graph subplot row :type per_line: int :param concat: Draw all the pivots on a single graph :type concat: bool :param permute: Draw one plot for each of the traces specified :type permute: bool :param drawstyle: This argument is forwarded to the matplotlib corresponding :func:`matplotlib.pyplot.plot` call drawing style. .. note:: step plots are not currently supported for filled graphs :param xlim: A tuple representing the upper and lower xlimits :type xlim: tuple :param ylim: A tuple representing the upper and lower ylimits :type ylim: tuple :param title: A title describing all the generated plots :type title: str :param style: Created pre-styled graphs loaded from :mod:`trappy.plotter.AttrConf.MPL_STYLE` :type style: bool :param signals: A string of the type event_name:column to indicate the value that needs to be plotted .. note:: - Only one of `signals` or both `templates` and `columns` should be specified - Signals format won't work for :mod:`pandas.DataFrame` input :type signals: str :param legend_ncol: A positive integer that represents the number of columns in the legend :type legend_ncol: int """ def __init__(self, traces, templates, **kwargs): self._fig = None self._layout = None super(StaticPlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: if key in AttrConf.ARGS_TO_FORWARD: self._attr["args_to_forward"][key] = kwargs[key] else: self._attr[key] = kwargs[key] if "signals" in self._attr: self._describe_signals() self._check_data() if "column" not in self._attr: raise RuntimeError("Value Column not specified") zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(traces, self._attr["column"], self.templates, self._attr["pivot"], self._attr["filters"], zip_constraints=zip_constraints) def savefig(self, *args, **kwargs): """Save the plot as a PNG fill. This calls into :mod:`matplotlib.figure.savefig` """ if self._fig is None: self.view() self._fig.savefig(*args, **kwargs) @abstractmethod def set_defaults(self): """Sets the default attrs""" self._attr["width"] = AttrConf.WIDTH self._attr["length"] = AttrConf.LENGTH self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["style"] = True self._attr["permute"] = False self._attr["pivot"] = AttrConf.PIVOT self._attr["xlim"] = AttrConf.XLIM self._attr["ylim"] = AttrConf.YLIM self._attr["title"] = AttrConf.TITLE self._attr["args_to_forward"] = {} self._attr["map_label"] = {} self._attr["_legend_handles"] = [] self._attr["_legend_labels"] = [] self._attr["legend_ncol"] = AttrConf.LEGEND_NCOL def view(self, test=False): """Displays the graph""" if test: self._attr["style"] = True AttrConf.MPL_STYLE["interactive"] = False permute = self._attr["permute"] and not self._attr["concat"] if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._resolve(permute, self._attr["concat"]) else: self._resolve(permute, self._attr["concat"]) def make_title(self, constraint, pivot, permute, concat): """Generates a title string for an axis""" if concat: return str(constraint) if permute: return constraint.get_data_name() elif pivot != AttrConf.PIVOT_VAL: return "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) else: return "" def add_to_legend(self, series_index, handle, constraint, pivot, concat, permute): """ Add series handles and names to the legend A handle is returned from a plot on an axis e.g. Line2D from axis.plot() """ self._attr["_legend_handles"][series_index] = handle legend_labels = self._attr["_legend_labels"] if concat and pivot == AttrConf.PIVOT_VAL: legend_labels[series_index] = self._attr["column"] elif concat: legend_labels[series_index] = "{0}: {1}".format( self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) elif permute: legend_labels[ series_index] = constraint._template.name + ":" + constraint.column else: legend_labels[series_index] = str(constraint) def _resolve(self, permute, concat): """Determine what data to plot on which axis""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) pivot_vals = list(pivot_vals) num_of_axes = len(self.c_mgr) if concat else len_pivots # Create a 2D Layout self._layout = PlotLayout(self._attr["per_line"], num_of_axes, width=self._attr["width"], length=self._attr["length"], title=self._attr['title']) self._fig = self._layout.get_fig() # Determine what constraint to plot and the corresponding pivot value if permute: legend_len = self.c_mgr._max_len pivots = [y for _, y in pivot_vals] c_dict = {c: str(c) for c in self.c_mgr} c_list = sorted(c_dict.items(), key=lambda x: (x[1].split(":")[-1], x[1].split(":")[0])) constraints = [c[0] for c in c_list] cp_pairs = [(c, p) for c in constraints for p in sorted(set(pivots))] else: legend_len = len_pivots if concat else len(self.c_mgr) pivots = pivot_vals cp_pairs = [(c, p) for c in self.c_mgr for p in pivots if p in c.result] # Initialise legend data and colormap self._attr["_legend_handles"] = [None] * legend_len self._attr["_legend_labels"] = [None] * legend_len if "colors" in self._attr: self._cmap = ColorMap.rgb_cmap(self._attr["colors"]) else: self._cmap = ColorMap(legend_len) # Group constraints/series with the axis they are to be plotted on figure_data = ddict(list) for i, (constraint, pivot) in enumerate(cp_pairs): axis = self._layout.get_axis( constraint.trace_index if concat else i) figure_data[axis].append((constraint, pivot)) # Plot each axis for axis, series_list in figure_data.items(): self.plot_axis(axis, series_list, permute, self._attr["concat"], self._attr["args_to_forward"]) if self._attr["xlim"]: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"]: axis.set_ylim(self._attr["ylim"]) # Show legend legend = self._fig.legend(self._attr["_legend_handles"], self._attr["_legend_labels"], loc='lower center', ncol=self._attr["legend_ncol"], borderaxespad=0.) legend.get_frame().set_facecolor('#F4F4F4') self._layout.finish(num_of_axes) def plot_axis(self, axis, series_list, permute, concat, args_to_forward): """Internal Method called to plot data (series_list) on a given axis""" raise NotImplementedError("Method Not Implemented")
class StaticPlot(AbstractDataPlotter): """ This class uses :mod:`trappy.plotter.Constraint.Constraint` to represent different permutations of input parameters. These constraints are generated by creating an instance of :mod:`trappy.plotter.Constraint.ConstraintManager`. :param traces: The input data :type traces: a list of :mod:`trappy.trace.FTrace` or :mod:`pandas.DataFrame` or a single instance of them :param column: specifies the name of the column to be plotted. :type column: (str, list(str)) :param templates: TRAPpy events .. note:: This is not required if a :mod:`pandas.DataFrame` is used :type templates: :mod:`trappy.base.Base` :param filters: Filter the column to be plotted as per the specified criteria. For Example: :: filters = { "pid": [ 3338 ], "cpu": [0, 2, 4], } :type filters: dict :param per_line: Used to control the number of graphs in each graph subplot row :type per_line: int :param concat: Draw all the pivots on a single graph :type concat: bool :param permute: Draw one plot for each of the traces specified :type permute: bool :param drawstyle: This argument is forwarded to the matplotlib corresponding :func:`matplotlib.pyplot.plot` call drawing style. .. note:: step plots are not currently supported for filled graphs :param xlim: A tuple representing the upper and lower xlimits :type xlim: tuple :param ylim: A tuple representing the upper and lower ylimits :type ylim: tuple :param title: A title describing all the generated plots :type title: str :param style: Created pre-styled graphs loaded from :mod:`trappy.plotter.AttrConf.MPL_STYLE` :type style: bool :param signals: A string of the type event_name:column to indicate the value that needs to be plotted .. note:: - Only one of `signals` or both `templates` and `columns` should be specified - Signals format won't work for :mod:`pandas.DataFrame` input :type signals: str :param legend_ncol: A positive integer that represents the number of columns in the legend :type legend_ncol: int """ __metaclass__ = ABCMeta def __init__(self, traces, templates, **kwargs): self._fig = None self._layout = None super(StaticPlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: if key in AttrConf.ARGS_TO_FORWARD: self._attr["args_to_forward"][key] = kwargs[key] else: self._attr[key] = kwargs[key] if "signals" in self._attr: self._describe_signals() self._check_data() if "column" not in self._attr: raise RuntimeError("Value Column not specified") zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(traces, self._attr["column"], self.templates, self._attr["pivot"], self._attr["filters"], zip_constraints) def savefig(self, *args, **kwargs): """Save the plot as a PNG fill. This calls into :mod:`matplotlib.figure.savefig` """ if self._fig is None: self.view() self._fig.savefig(*args, **kwargs) @abstractmethod def set_defaults(self): """Sets the default attrs""" self._attr["width"] = AttrConf.WIDTH self._attr["length"] = AttrConf.LENGTH self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["style"] = True self._attr["permute"] = False self._attr["pivot"] = AttrConf.PIVOT self._attr["xlim"] = AttrConf.XLIM self._attr["ylim"] = AttrConf.XLIM self._attr["title"] = AttrConf.TITLE self._attr["args_to_forward"] = {} self._attr["map_label"] = {} self._attr["_legend_handles"] = [] self._attr["_legend_labels"] = [] self._attr["legend_ncol"] = AttrConf.LEGEND_NCOL def view(self, test=False): """Displays the graph""" if test: self._attr["style"] = True AttrConf.MPL_STYLE["interactive"] = False permute = self._attr["permute"] and not self._attr["concat"] if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._resolve(permute, self._attr["concat"]) else: self._resolve(permute, self._attr["concat"]) def make_title(self, constraint, pivot, permute, concat): """Generates a title string for an axis""" if concat: return str(constraint) if permute: return constraint.get_data_name() elif pivot != AttrConf.PIVOT_VAL: return "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) else: return "" def add_to_legend(self, series_index, handle, constraint, pivot, concat, permute): """ Add series handles and names to the legend A handle is returned from a plot on an axis e.g. Line2D from axis.plot() """ self._attr["_legend_handles"][series_index] = handle legend_labels = self._attr["_legend_labels"] if concat and pivot == AttrConf.PIVOT_VAL: legend_labels[series_index] = self._attr["column"] elif concat: legend_labels[series_index] = "{0}: {1}".format( self._attr["pivot"], self._attr["map_label"].get(pivot, pivot) ) elif permute: legend_labels[series_index] = constraint._template.name + ":" + constraint.column else: legend_labels[series_index] = str(constraint) def _resolve(self, permute, concat): """Determine what data to plot on which axis""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) pivot_vals = list(pivot_vals) num_of_axes = len(self.c_mgr) if concat else len_pivots # Create a 2D Layout self._layout = PlotLayout( self._attr["per_line"], num_of_axes, width=self._attr["width"], length=self._attr["length"], title=self._attr['title']) self._fig = self._layout.get_fig() # Determine what constraint to plot and the corresponding pivot value if permute: legend_len = self.c_mgr._max_len pivots = [y for _, y in pivot_vals] c_dict = {c : str(c) for c in self.c_mgr} c_list = sorted(c_dict.items(), key=lambda x: (x[1].split(":")[-1], x[1].split(":")[0])) constraints = [c[0] for c in c_list] cp_pairs = [(c, p) for c in constraints for p in sorted(set(pivots))] else: legend_len = len_pivots if concat else len(self.c_mgr) pivots = pivot_vals cp_pairs = [(c, p) for c in self.c_mgr for p in pivots if p in c.result] # Initialise legend data and colormap self._attr["_legend_handles"] = [None] * legend_len self._attr["_legend_labels"] = [None] * legend_len self._cmap = ColorMap(legend_len) # Group constraints/series with the axis they are to be plotted on figure_data = ddict(list) for i, (constraint, pivot) in enumerate(cp_pairs): axis = self._layout.get_axis(constraint.trace_index if concat else i) figure_data[axis].append((constraint, pivot)) # Plot each axis for axis, series_list in figure_data.iteritems(): self.plot_axis( axis, series_list, permute, self._attr["concat"], self._attr["args_to_forward"] ) # Show legend legend = self._fig.legend(self._attr["_legend_handles"], self._attr["_legend_labels"], loc='lower center', ncol=self._attr["legend_ncol"], borderaxespad=0.) legend.get_frame().set_facecolor('#F4F4F4') self._layout.finish(num_of_axes) def plot_axis(self, axis, series_list, permute, concat, args_to_forward): """Internal Method called to plot data (series_list) on a given axis""" raise NotImplementedError("Method Not Implemented")
class LinePlot(AbstractDataPlotter): """ This class uses :mod:`trappy.plotter.Constraint.Constraint` to represent different permutations of input parameters. These constraints are generated by creating an instance of :mod:`trappy.plotter.Constraint.ConstraintManager`. :param run: The input data :type run: :mod:`trappy.run.Run` or :mod:`pandas.DataFrame`, list or single :param column: specifies the name of the column to be plotted. :type column: (str, list(str)) :param templates: TRAPpy events .. note:: This is not required if a :mod:`pandas.DataFrame` is used :type templates: :mod:`trappy.base.Base` :param filters: Filter the column to be plotted as per the specified criteria. For Example: :: filters = { "pid": [ 3338 ], "cpu": [0, 2, 4], } :type filters: dict :param per_line: Used to control the number of graphs in each graph subplot row :type per_line: int :param concat: Draw all the pivots on a single graph :type concat: bool :param fill: Fill the area under the plots :type fill: bool :param permute: Draw one plot for each of the runs specified :type permute: bool :param drawstyle: This argument is forwarded to the matplotlib corresponding :func:`matplotlib.pyplot.plot` call drawing style. .. note:: step plots are not currently supported for filled graphs :param xlim: A tuple representing the upper and lower xlimits :type xlim: tuple :param ylim: A tuple representing the upper and lower ylimits :type ylim: tuple :param style: Created pre-styled graphs loaded from :mod:`trappy.plotter.AttrConf.MPL_STYLE` :type style: bool """ def __init__(self, runs, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._attr = {} self.runs = runs self.templates = templates self.set_defaults() self._fig = None self._layout = None self._check_data() for key in kwargs: if key in AttrConf.ARGS_TO_FORWARD: self._attr["args_to_forward"][key] = kwargs[key] else: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager( runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) self._check_add_scatter() super(LinePlot, self).__init__() def savefig(self, *args, **kwargs): """Save the plot as a PNG fill. This calls into :mod:`matplotlib.figure.savefig` """ if self._fig == None: self.view() self._fig.savefig(*args, **kwargs) def view(self, test=False): """Displays the graph""" if test: self._attr["style"] = True AttrConf.MPL_STYLE["interactive"] = False if self._attr["concat"]: if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._plot_concat() else: self._plot_concat() else: if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._plot(self._attr["permute"]) else: self._plot(self._attr["permute"]) def set_defaults(self): """Sets the default attrs""" self._attr["width"] = AttrConf.WIDTH self._attr["length"] = AttrConf.LENGTH self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["fill"] = AttrConf.FILL self._attr["filters"] = {} self._attr["style"] = True self._attr["permute"] = False self._attr["pivot"] = AttrConf.PIVOT self._attr["xlim"] = AttrConf.XLIM self._attr["ylim"] = AttrConf.XLIM self._attr["args_to_forward"] = {} self._attr["scatter"] = AttrConf.PLOT_SCATTER def _check_add_scatter(self): """Check if a scatter plot is needed and augment the forwarded args accordingly""" if self._attr["scatter"]: self._attr["args_to_forward"]["linestyle"] = "" self._attr["args_to_forward"]["marker"] = "o" if "point_size" in self._attr: self._attr["args_to_forward"]["markersize"] = \ self._attr["point_size"] def _plot(self, permute): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) # Create a 2D Layout self._layout = PlotLayout( self._attr["per_line"], len_pivots, width=self._attr["width"], length=self._attr["length"]) self._fig = self._layout.get_fig() legend_str = [] plot_index = 0 if permute: legend = [None] * self.c_mgr._max_len cmap = ColorMap(self.c_mgr._max_len) else: legend = [None] * len(self.c_mgr) cmap = ColorMap(len(self.c_mgr)) for p_val in pivot_vals: l_index = 0 for constraint in self.c_mgr: if permute: run_idx, pivot = p_val if constraint.run_index != run_idx: continue legend_str.append(constraint._column) l_index = self.c_mgr.get_column_index(constraint) title = constraint.get_data_name() + ":" else: pivot = p_val legend_str.append(str(constraint)) title = "" result = constraint.result if pivot in result: axis = self._layout.get_axis(plot_index) line_2d_list = axis.plot( result[pivot].index, result[pivot].values, color=cmap.cmap(l_index), **self._attr["args_to_forward"]) if self._attr["fill"]: drawstyle = line_2d_list[0].get_drawstyle() # This has been fixed in upstream matplotlib if drawstyle.startswith("steps"): raise UserWarning("matplotlib does not support fill for step plots") xdat, ydat = line_2d_list[0].get_data(orig=False) axis.fill_between(xdat, axis.get_ylim()[0], ydat, facecolor=cmap.cmap(l_index), alpha=AttrConf.ALPHA) legend[l_index] = line_2d_list[0] if self._attr["xlim"] != None: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"] != None: axis.set_ylim(self._attr["ylim"]) else: axis = self._layout.get_axis(plot_index) axis.plot([], [], **self._attr["args_to_forward"]) l_index += 1 if pivot == AttrConf.PIVOT_VAL: title += ",".join(self._attr["column"]) else: title += "{0}: {1}".format(self._attr["pivot"], pivot) axis.set_title(title) plot_index += 1 for l_idx, legend_line in enumerate(legend): if not legend_line: del legend[l_idx] del legend_str[l_idx] self._fig.legend(legend, legend_str) self._layout.finish(len_pivots) def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, len_pivots = self.c_mgr.generate_pivots() cmap = ColorMap(len_pivots) self._layout = PlotLayout(self._attr["per_line"], len(self.c_mgr), width=self._attr["width"], length=self._attr["length"]) self._fig = self._layout.get_fig() legend = [None] * len_pivots legend_str = [""] * len_pivots plot_index = 0 for constraint in self.c_mgr: result = constraint.result title = str(constraint) result = constraint.result pivot_index = 0 for pivot in pivot_vals: if pivot in result: axis = self._layout.get_axis(plot_index) line_2d_list = axis.plot( result[pivot].index, result[pivot].values, color=cmap.cmap(pivot_index), **self._attr["args_to_forward"]) if self._attr["xlim"] != None: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"] != None: axis.set_ylim(self._attr["ylim"]) legend[pivot_index] = line_2d_list[0] if self._attr["fill"]: drawstyle = line_2d_list[0].get_drawstyle() if drawstyle.startswith("steps"): # This has been fixed in upstream matplotlib raise UserWarning("matplotlib does not support fill for step plots") xdat, ydat = line_2d_list[0].get_data(orig=False) axis.fill_between(xdat, axis.get_ylim()[0], ydat, facecolor=cmap.cmap(pivot_index), alpha=AttrConf.ALPHA) if pivot == AttrConf.PIVOT_VAL: legend_str[pivot_index] = self._attr["column"] else: legend_str[pivot_index] = "{0}: {1}".format(self._attr["pivot"], pivot) else: axis = self._layout.get_axis(plot_index) axis.plot( [], [], color=cmap.cmap(pivot_index), **self._attr["args_to_forward"]) pivot_index += 1 plot_index += 1 self._fig.legend(legend, legend_str) plot_index = 0 for constraint in self.c_mgr: self._layout.get_axis(plot_index).set_title(str(constraint)) plot_index += 1 self._layout.finish(len(self.c_mgr))
class LinePlot(AbstractDataPlotter): """ This class uses :mod:`trappy.plotter.Constraint.Constraint` to represent different permutations of input parameters. These constraints are generated by creating an instance of :mod:`trappy.plotter.Constraint.ConstraintManager`. :param run: The input data :type run: :mod:`trappy.run.Run` or :mod:`pandas.DataFrame`, list or single :param column: specifies the name of the column to be plotted. :type column: (str, list(str)) :param templates: TRAPpy events .. note:: This is not required if a :mod:`pandas.DataFrame` is used :type templates: :mod:`trappy.base.Base` :param filters: Filter the column to be plotted as per the specified criteria. For Example: :: filters = { "pid": [ 3338 ], "cpu": [0, 2, 4], } :type filters: dict :param per_line: Used to control the number of graphs in each graph subplot row :type per_line: int :param concat: Draw all the pivots on a single graph :type concat: bool :param fill: Fill the area under the plots :type fill: bool :param permute: Draw one plot for each of the runs specified :type permute: bool :param drawstyle: This argument is forwarded to the matplotlib corresponding :func:`matplotlib.pyplot.plot` call drawing style. .. note:: step plots are not currently supported for filled graphs :param xlim: A tuple representing the upper and lower xlimits :type xlim: tuple :param ylim: A tuple representing the upper and lower ylimits :type ylim: tuple :param style: Created pre-styled graphs loaded from :mod:`trappy.plotter.AttrConf.MPL_STYLE` :type style: bool """ def __init__(self, runs, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._attr = {} self.runs = runs self.templates = templates self.set_defaults() self._fig = None self._layout = None self._check_data() for key in kwargs: if key in AttrConf.ARGS_TO_FORWARD: self._attr["args_to_forward"][key] = kwargs[key] else: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) self._check_add_scatter() super(LinePlot, self).__init__() def savefig(self, *args, **kwargs): """Save the plot as a PNG fill. This calls into :mod:`matplotlib.figure.savefig` """ if self._fig == None: self.view() self._fig.savefig(*args, **kwargs) def view(self, test=False): """Displays the graph""" if test: self._attr["style"] = True AttrConf.MPL_STYLE["interactive"] = False if self._attr["concat"]: if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._plot_concat() else: self._plot_concat() else: if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._plot(self._attr["permute"]) else: self._plot(self._attr["permute"]) def set_defaults(self): """Sets the default attrs""" self._attr["width"] = AttrConf.WIDTH self._attr["length"] = AttrConf.LENGTH self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["fill"] = AttrConf.FILL self._attr["filters"] = {} self._attr["style"] = True self._attr["permute"] = False self._attr["pivot"] = AttrConf.PIVOT self._attr["xlim"] = AttrConf.XLIM self._attr["ylim"] = AttrConf.XLIM self._attr["args_to_forward"] = {} self._attr["scatter"] = AttrConf.PLOT_SCATTER def _check_add_scatter(self): """Check if a scatter plot is needed and augment the forwarded args accordingly""" if self._attr["scatter"]: self._attr["args_to_forward"]["linestyle"] = "" self._attr["args_to_forward"]["marker"] = "o" if "point_size" in self._attr: self._attr["args_to_forward"]["markersize"] = \ self._attr["point_size"] def _plot(self, permute): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) # Create a 2D Layout self._layout = PlotLayout(self._attr["per_line"], len_pivots, width=self._attr["width"], length=self._attr["length"]) self._fig = self._layout.get_fig() legend_str = [] plot_index = 0 if permute: legend = [None] * self.c_mgr._max_len cmap = ColorMap(self.c_mgr._max_len) else: legend = [None] * len(self.c_mgr) cmap = ColorMap(len(self.c_mgr)) for p_val in pivot_vals: l_index = 0 for constraint in self.c_mgr: if permute: run_idx, pivot = p_val if constraint.run_index != run_idx: continue legend_str.append(constraint._column) l_index = self.c_mgr.get_column_index(constraint) title = constraint.get_data_name() + ":" else: pivot = p_val legend_str.append(str(constraint)) title = "" result = constraint.result if pivot in result: axis = self._layout.get_axis(plot_index) line_2d_list = axis.plot(result[pivot].index, result[pivot].values, color=cmap.cmap(l_index), **self._attr["args_to_forward"]) if self._attr["fill"]: drawstyle = line_2d_list[0].get_drawstyle() # This has been fixed in upstream matplotlib if drawstyle.startswith("steps"): raise UserWarning( "matplotlib does not support fill for step plots" ) xdat, ydat = line_2d_list[0].get_data(orig=False) axis.fill_between(xdat, axis.get_ylim()[0], ydat, facecolor=cmap.cmap(l_index), alpha=AttrConf.ALPHA) legend[l_index] = line_2d_list[0] if self._attr["xlim"] != None: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"] != None: axis.set_ylim(self._attr["ylim"]) else: axis = self._layout.get_axis(plot_index) axis.plot([], [], **self._attr["args_to_forward"]) l_index += 1 if pivot == AttrConf.PIVOT_VAL: title += ",".join(self._attr["column"]) else: title += "{0}: {1}".format(self._attr["pivot"], pivot) axis.set_title(title) plot_index += 1 for l_idx, legend_line in enumerate(legend): if not legend_line: del legend[l_idx] del legend_str[l_idx] self._fig.legend(legend, legend_str) self._layout.finish(len_pivots) def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, len_pivots = self.c_mgr.generate_pivots() cmap = ColorMap(len_pivots) self._layout = PlotLayout(self._attr["per_line"], len(self.c_mgr), width=self._attr["width"], length=self._attr["length"]) self._fig = self._layout.get_fig() legend = [None] * len_pivots legend_str = [""] * len_pivots plot_index = 0 for constraint in self.c_mgr: result = constraint.result title = str(constraint) result = constraint.result pivot_index = 0 for pivot in pivot_vals: if pivot in result: axis = self._layout.get_axis(plot_index) line_2d_list = axis.plot(result[pivot].index, result[pivot].values, color=cmap.cmap(pivot_index), **self._attr["args_to_forward"]) if self._attr["xlim"] != None: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"] != None: axis.set_ylim(self._attr["ylim"]) legend[pivot_index] = line_2d_list[0] if self._attr["fill"]: drawstyle = line_2d_list[0].get_drawstyle() if drawstyle.startswith("steps"): # This has been fixed in upstream matplotlib raise UserWarning( "matplotlib does not support fill for step plots" ) xdat, ydat = line_2d_list[0].get_data(orig=False) axis.fill_between(xdat, axis.get_ylim()[0], ydat, facecolor=cmap.cmap(pivot_index), alpha=AttrConf.ALPHA) if pivot == AttrConf.PIVOT_VAL: legend_str[pivot_index] = self._attr["column"] else: legend_str[pivot_index] = "{0}: {1}".format( self._attr["pivot"], pivot) else: axis = self._layout.get_axis(plot_index) axis.plot([], [], color=cmap.cmap(pivot_index), **self._attr["args_to_forward"]) pivot_index += 1 plot_index += 1 self._fig.legend(legend, legend_str) plot_index = 0 for constraint in self.c_mgr: self._layout.get_axis(plot_index).set_title(str(constraint)) plot_index += 1 self._layout.finish(len(self.c_mgr))
class LinePlot(AbstractDataPlotter): """The plots are plotted by default against the dataframe index The column="col_name" specifies the name of the column to be plotted filters = { "pid": [ 3338 ], "cpu": [0, 2, 4], } The above filters will filter the column to be plotted as per the specified criteria. per_line input is used to control the number of graphs in each graph subplot row concat, Draws all the graphs on a single plot permute, draws one plot for each of the runs specified """ def __init__(self, runs, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._attr = {} self.runs = runs self.templates = templates self.set_defaults() self._fig = None self._layout = None self._check_data() for key in kwargs: if key in AttrConf.ARGS_TO_FORWARD: self._attr["args_to_forward"][key] = kwargs[key] else: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) super(LinePlot, self).__init__() def savefig(self, *args, **kwargs): if self._fig == None: self.view() self._fig.savefig(*args, **kwargs) def view(self, test=False): """Displays the graph""" if test: self._attr["style"] = True AttrConf.MPL_STYLE["interactive"] = False if self._attr["concat"]: if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._plot_concat() else: self._plot_concat() else: if self._attr["style"]: with plt.rc_context(AttrConf.MPL_STYLE): self._plot(self._attr["permute"]) else: self._plot(self._attr["permute"]) def set_defaults(self): """Sets the default attrs""" self._attr["width"] = AttrConf.WIDTH self._attr["length"] = AttrConf.LENGTH self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["fill"] = AttrConf.FILL self._attr["filters"] = {} self._attr["style"] = True self._attr["permute"] = False self._attr["pivot"] = AttrConf.PIVOT self._attr["xlim"] = AttrConf.XLIM self._attr["ylim"] = AttrConf.XLIM self._attr["args_to_forward"] = {} def _plot(self, permute): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) # Create a 2D Layout self._layout = PlotLayout(self._attr["per_line"], len_pivots, width=self._attr["width"], length=self._attr["length"]) self._fig = self._layout.get_fig() legend_str = [] plot_index = 0 if permute: legend = [None] * self.c_mgr._max_len cmap = ColorMap(self.c_mgr._max_len) else: legend = [None] * len(self.c_mgr) cmap = ColorMap(len(self.c_mgr)) for p_val in pivot_vals: l_index = 0 for constraint in self.c_mgr: if permute: run_idx, pivot = p_val if constraint.run_index != run_idx: continue legend_str.append(constraint._column) l_index = self.c_mgr.get_column_index(constraint) title = constraint.get_data_name() + ":" else: pivot = p_val legend_str.append(str(constraint)) title = "" result = constraint.result if pivot in result: axis = self._layout.get_axis(plot_index) line_2d_list = axis.plot(result[pivot].index, result[pivot].values, color=cmap.cmap(l_index), **self._attr["args_to_forward"]) if self._attr["fill"]: drawstyle = line_2d_list[0].get_drawstyle() # This has been fixed in upstream matplotlib if drawstyle.startswith("steps"): raise UserWarning( "matplotlib does not support fill for step plots" ) xdat, ydat = line_2d_list[0].get_data(orig=False) axis.fill_between(xdat, axis.get_ylim()[0], ydat, facecolor=cmap.cmap(l_index), alpha=AttrConf.ALPHA) legend[l_index] = line_2d_list[0] if self._attr["xlim"] != None: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"] != None: axis.set_ylim(self._attr["ylim"]) else: axis = self._layout.get_axis(plot_index) axis.plot([], [], **self._attr["args_to_forward"]) l_index += 1 if pivot == AttrConf.PIVOT_VAL: title += ",".join(self._attr["column"]) else: title += "{0}: {1}".format(self._attr["pivot"], pivot) axis.set_title(title) plot_index += 1 for l_idx, legend_line in enumerate(legend): if not legend_line: del legend[l_idx] del legend_str[l_idx] self._fig.legend(legend, legend_str) self._layout.finish(len_pivots) def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, len_pivots = self.c_mgr.generate_pivots() cmap = ColorMap(len_pivots) self._layout = PlotLayout(self._attr["per_line"], len(self.c_mgr), width=self._attr["width"], length=self._attr["length"]) self._fig = self._layout.get_fig() legend = [None] * len_pivots legend_str = [""] * len_pivots plot_index = 0 for constraint in self.c_mgr: result = constraint.result title = str(constraint) result = constraint.result pivot_index = 0 for pivot in pivot_vals: if pivot in result: axis = self._layout.get_axis(plot_index) line_2d_list = axis.plot(result[pivot].index, result[pivot].values, color=cmap.cmap(pivot_index), **self._attr["args_to_forward"]) if self._attr["xlim"] != None: axis.set_xlim(self._attr["xlim"]) if self._attr["ylim"] != None: axis.set_ylim(self._attr["ylim"]) legend[pivot_index] = line_2d_list[0] if self._attr["fill"]: drawstyle = line_2d_list[0].get_drawstyle() if drawstyle.startswith("steps"): # This has been fixed in upstream matplotlib raise UserWarning( "matplotlib does not support fill for step plots" ) xdat, ydat = line_2d_list[0].get_data(orig=False) axis.fill_between(xdat, axis.get_ylim()[0], ydat, facecolor=cmap.cmap(pivot_index), alpha=AttrConf.ALPHA) if pivot == AttrConf.PIVOT_VAL: legend_str[pivot_index] = self._attr["column"] else: legend_str[pivot_index] = "{0}: {1}".format( self._attr["pivot"], pivot) else: axis = self._layout.get_axis(plot_index) axis.plot([], [], color=cmap.cmap(pivot_index), **self._attr["args_to_forward"]) pivot_index += 1 plot_index += 1 self._fig.legend(legend, legend_str) plot_index = 0 for constraint in self.c_mgr: self._layout.get_axis(plot_index).set_title(str(constraint)) plot_index += 1 self._layout.finish(len(self.c_mgr))