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 __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._layout = None self._check_data() for key in kwargs: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith( "steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) super(ILinePlot, self).__init__()
def __init__(self, traces, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._layout = None super(ILinePlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: 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") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith( "steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] window = self._attr["xlim"] if "xlim" in self._attr else None self.c_mgr = ConstraintManager(traces, self._attr["column"], self.templates, self._attr["pivot"], self._attr["filters"], window=window, zip_constraints=zip_constraints)
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 test_constraint_with_window(self): """Test that the constraint manager can constraint to a window of time""" c_mgr = ConstraintManager(self.dfrs[0], "freq", None, AttrConf.PIVOT, {}, window=(1, 3)) constraint = iter(c_mgr).next() series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(len(series), 3) # For the graph to plot a value at 0.75, the resulting series # must contain the value before 0.75. Same for the upper limit. c_mgr = ConstraintManager(self.dfrs[0], "freq", None, AttrConf.PIVOT, {}, window=(0.75, 1.5)) constraint = iter(c_mgr).next() series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(series.index.tolist(), [0, 1, 2]) c_mgr = ConstraintManager(self.dfrs[0], "freq", None, AttrConf.PIVOT, {}, window=(0, 2)) constraint = iter(c_mgr).next() series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(len(series), 3)
def __init__(self, traces, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._layout = None super(ILinePlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: 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") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith("steps"): self._attr["step_plot"] = True 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 __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 __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 test_no_pivot_multiple_traces(self): """Test that the constraint manager works with multiple traces and no pivots""" c_mgr = ConstraintManager(self.dfrs, "load", None, AttrConf.PIVOT, {}) self.assertEquals(len(c_mgr), 2) for constraint, orig_dfr in zip(c_mgr, self.dfrs): series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(series.to_dict().values(), orig_dfr["load"].to_dict().values())
def test_no_pivot_zipped_columns_and_traces(self): """Test the constraint manager with multiple columns and traces zipped""" c_mgr = ConstraintManager(self.dfrs, self.cols, None, AttrConf.PIVOT, {}) self.assertEquals(len(c_mgr), 2) for constraint, orig_dfr, col in zip(c_mgr, self.dfrs, self.cols): series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(series.to_dict().values(), orig_dfr[col].to_dict().values())
def test_pivoted_multitraces_multicolumns(self): """Test the constraint manager with multiple traces and columns""" c_mgr = ConstraintManager(self.dfrs, ["load", "freq"], None, "cpu", {}) self.assertEquals(len(c_mgr), 2) constraint_iter = iter(c_mgr) constraint = constraint_iter.next() self.assertEquals(constraint.result[1].to_dict().values(), [2, 3]) constraint = constraint_iter.next() self.assertEquals(constraint.result[0].to_dict().values(), [2, 1])
def test_no_pivot_multicolumns_multitraces(self): """Test the constraint manager with multiple traces that can have each multiple columns""" c_mgr = ConstraintManager(self.dfrs, self.cols, None, AttrConf.PIVOT, {}, zip_constraints=False) self.assertEquals(len(c_mgr), 4) expected_series = [dfr[col] for dfr in self.dfrs for col in self.cols] for constraint, orig_series in zip(c_mgr, expected_series): series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(series.to_dict(), orig_series.to_dict())
def test_pivoted_data(self): """Test the constraint manager with a pivot and one trace""" c_mgr = ConstraintManager(self.dfrs[0], "load", None, "cpu", {}) self.assertEquals(len(c_mgr), 1) constraint = iter(c_mgr).next() results = dict([(k, v.to_dict().values()) for k, v in constraint.result.items()]) expected_results = {0: [1, 2], 1: [2, 3]} self.assertEquals(results, expected_results)
def test_pivoted_multitrace(self): """Test the constraint manager with a pivot and multiple traces""" c_mgr = ConstraintManager(self.dfrs, "load", None, "cpu", {}) self.assertEquals(len(c_mgr), 2) constraint_iter = iter(c_mgr) constraint = constraint_iter.next() self.assertEquals(constraint.result[0].to_dict().values(), [1, 2]) constraint = constraint_iter.next() self.assertEquals(constraint.result[1].to_dict().values(), [2, 2])
def test_one_constraint(self): """Test that the constraint manager works with one constraint""" dfr = self.dfrs[0] c_mgr = ConstraintManager(dfr, "load", None, AttrConf.PIVOT, {}) self.assertEquals(len(c_mgr), 1) constraint = iter(c_mgr).next() series = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(series.to_dict().values(), dfr["load"].to_dict().values())
def test_pivoted_with_filters(self): """Test the constraint manager with pivoted data and filters""" simple_filter = {"load": [2]} c_mgr = ConstraintManager(self.dfrs[0], "freq", None, "cpu", simple_filter) self.assertEquals(len(c_mgr), 1) constraint = iter(c_mgr).next() result = constraint.result self.assertEquals(result[0].iloc[0], 3) self.assertEquals(result[1].iloc[0], 3)
def test_no_pivot_filters(self): """Test the constraint manager with filters""" simple_filter = {"freq": [2]} c_mgr = ConstraintManager(self.dfrs, "load", None, AttrConf.PIVOT, simple_filter) num_constraints = len(c_mgr) self.assertEquals(num_constraints, 2) constraint_iter = iter(c_mgr) constraint = constraint_iter.next() self.assertEquals(len(constraint.result), 1) constraint = constraint_iter.next() series_second_frame = constraint.result[AttrConf.PIVOT_VAL] self.assertEquals(series_second_frame.to_dict().values(), [3, 2])
class ILinePlot(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 permute: Draw one plot for each of the runs specified :type permute: bool :param fill: Fill the area under the plots :type fill: bool :param drawstyle: Set the drawstyle to a matplotlib compatible drawing style. .. note:: Only "steps-post" is supported as a valid value for the drawstyle. This creates a step plot. :type drawstyle: str """ 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._layout = None self._check_data() for key in kwargs: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith("steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) super(ILinePlot, self).__init__() def savefig(self, *args, **kwargs): raise NotImplementedError("Not Available for ILinePlot") def view(self, test=False): """Displays the graph""" # Defer installation of IPython components # to the .view call to avoid any errors at # when importing the module. This facilitates # the importing of the module from outside # an IPython notebook IPythonConf.iplot_install("ILinePlot") if self._attr["concat"]: self._plot_concat() else: self._plot(self._attr["permute"]) def set_defaults(self): """Sets the default attrs""" self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["pivot"] = AttrConf.PIVOT self._attr["permute"] = False self._attr["drawstyle"] = None self._attr["step_plot"] = False self._attr["fill"] = AttrConf.FILL self._attr["draw_line"] = True self._attr["scatter"] = AttrConf.PLOT_SCATTER self._attr["point_size"] = AttrConf.POINT_SIZE def _plot(self, permute): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) self._layout = ILinePlotGen(self._attr["per_line"], len_pivots, **self._attr) plot_index = 0 for p_val in pivot_vals: data_frame = pd.Series() for constraint in self.c_mgr: if permute: run_idx, pivot = p_val if constraint.run_index != run_idx: continue title = constraint.get_data_name() + ":" legend = constraint._column else: pivot = p_val title = "" legend = str(constraint) result = constraint.result if pivot in result: data_frame[legend] = result[pivot] if pivot == AttrConf.PIVOT_VAL: title += ",".join(self._attr["column"]) else: title += "{0}: {1}".format(self._attr["pivot"], pivot) self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish() def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, _ = self.c_mgr.generate_pivots() plot_index = 0 self._layout = ILinePlotGen(self._attr["per_line"], len(self.c_mgr), **self._attr) for constraint in self.c_mgr: result = constraint.result title = str(constraint) data_frame = pd.Series() for pivot in pivot_vals: if pivot in result: if pivot == AttrConf.PIVOT_VAL: key = ",".join(self._attr["column"]) else: key = "{0}: {1}".format(self._attr["pivot"], pivot) data_frame[key] = result[pivot] self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish()
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 ILinePlot(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._layout = None self._check_data() for key in kwargs: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith( "steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) super(ILinePlot, self).__init__() def savefig(self, *args, **kwargs): raise NotImplementedError("Not Available for ILinePlot") def view(self, test=False): """Displays the graph""" if self._attr["concat"]: self._plot_concat() else: self._plot(self._attr["permute"]) def set_defaults(self): """Sets the default attrs""" self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["pivot"] = AttrConf.PIVOT self._attr["permute"] = False self._attr["drawstyle"] = None self._attr["step_plot"] = False self._attr["fill"] = AttrConf.FILL def _plot(self, permute): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) self._layout = ILinePlotGen(self._attr["per_line"], len_pivots, **self._attr) plot_index = 0 for p_val in pivot_vals: data_frame = pd.Series() for constraint in self.c_mgr: if permute: run_idx, pivot = p_val if constraint.run_index != run_idx: continue title = constraint.get_data_name() + ":" legend = constraint._column else: pivot = p_val title = "" legend = str(constraint) result = constraint.result if pivot in result: data_frame[legend] = result[pivot] if pivot == AttrConf.PIVOT_VAL: title += ",".join(self._attr["column"]) else: title += "{0}: {1}".format(self._attr["pivot"], pivot) self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish() def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, _ = self.c_mgr.generate_pivots() plot_index = 0 self._layout = ILinePlotGen(self._attr["per_line"], len(self.c_mgr), **self._attr) for constraint in self.c_mgr: result = constraint.result title = str(constraint) data_frame = pd.Series() for pivot in pivot_vals: if pivot in result: if pivot == AttrConf.PIVOT_VAL: key = ",".join(self._attr["column"]) else: key = "{0}: {1}".format(self._attr["pivot"], pivot) data_frame[key] = result[pivot] self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish()
class ILinePlot(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 fill: Fill the area under the plots :type fill: bool :param fill_alpha: Opacity of filled area under the plots. Implies fill=True. :type fill_alpha: float :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 drawstyle: Set the drawstyle to a matplotlib compatible drawing style. .. note:: Only "steps-post" is supported as a valid value for the drawstyle. This creates a step plot. :type drawstyle: str :param sync_zoom: Synchronize the zoom of a group of plots. Zooming in one plot of a group (see below) will zoom in every plot of that group. Defaults to False. :type sync_zoom: boolean :param group: Name given to the plots created by this ILinePlot instance. This name is only used for synchronized zoom. If you zoom on any plot in a group all plots will zoom at the same time. :type group: string :param signals: A string of the type event_name:column to indicate the value that needs to be plotted. You can add an additional parameter to specify the color of the lin in rgb: "event_name:column:color". The color is specified as a comma separated list of rgb values, from 0 to 255 or from 0x0 to 0xff. E.g. 0xff,0x0,0x0 is red and 100,40,32 is brown. .. 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 """ def __init__(self, traces, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._layout = None super(ILinePlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: 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") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith( "steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] window = self._attr["xlim"] if "xlim" in self._attr else None self.c_mgr = ConstraintManager(traces, self._attr["column"], self.templates, self._attr["pivot"], self._attr["filters"], window=window, zip_constraints=zip_constraints) def savefig(self, *args, **kwargs): raise NotImplementedError("Not Available for ILinePlot") def view(self, max_datapoints=75000, test=False): """Displays the graph :param max_datapoints: Maximum number of datapoints to plot. Dygraph can make the browser unresponsive if it tries to plot too many datapoints. Chrome 50 chokes at around 75000 on an i7-4770 @ 3.4GHz, Firefox 47 can handle up to 200000 before becoming too slow in the same machine. You can increase this number if you know what you're doing and are happy to wait for the plot to render. :type max_datapoints: int :param test: For testing purposes. Only set to true if run from the testsuite. :type test: boolean """ # Defer installation of IPython components # to the .view call to avoid any errors at # when importing the module. This facilitates # the importing of the module from outside # an IPython notebook if not test: IPythonConf.iplot_install("ILinePlot") self._attr["max_datapoints"] = max_datapoints if self._attr["concat"]: self._plot_concat() else: self._plot(self._attr["permute"], test) def set_defaults(self): """Sets the default attrs""" self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["pivot"] = AttrConf.PIVOT self._attr["permute"] = False self._attr["drawstyle"] = None self._attr["step_plot"] = False self._attr["fill"] = AttrConf.FILL self._attr["scatter"] = AttrConf.PLOT_SCATTER self._attr["point_size"] = AttrConf.POINT_SIZE self._attr["map_label"] = {} self._attr["title"] = AttrConf.TITLE def _plot(self, permute, test): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) self._layout = ILinePlotGen(len_pivots, **self._attr) plot_index = 0 for p_val in pivot_vals: data_dict = OrderedDict() for constraint in self.c_mgr: if permute: trace_idx, pivot = p_val if constraint.trace_index != trace_idx: continue legend = constraint._template.name + ":" + constraint.column else: pivot = p_val legend = str(constraint) result = constraint.result if pivot in result: data_dict[legend] = result[pivot] if permute: title = self.traces[plot_index].name elif pivot != AttrConf.PIVOT_VAL: title = "{0}: {1}".format( self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) else: title = "" if len(data_dict) > 1: data_frame = self._fix_indexes(data_dict) else: data_frame = pd.DataFrame(data_dict) self._layout.add_plot(plot_index, data_frame, title, test=test) plot_index += 1 self._layout.finish() def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, _ = self.c_mgr.generate_pivots() plot_index = 0 self._layout = ILinePlotGen(len(self.c_mgr), **self._attr) for constraint in self.c_mgr: result = constraint.result title = str(constraint) data_dict = OrderedDict() for pivot in pivot_vals: if pivot in result: if pivot == AttrConf.PIVOT_VAL: key = ",".join(self._attr["column"]) else: key = "{0}: {1}".format( self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) data_dict[key] = result[pivot] if len(data_dict) > 1: data_frame = self._fix_indexes(data_dict) else: data_frame = pd.DataFrame(data_dict) self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish() def _fix_indexes(self, data_dict): """ In case of multiple traces with different indexes (i.e. x-axis values), create new ones with same indexes """ # 1) Check if we are processing multiple traces if len(data_dict) <= 1: raise ValueError("Cannot fix indexes for single trace. "\ "Expecting multiple traces!") # 2) Merge the data frames to obtain common indexes df_columns = list(data_dict.keys()) dedup_data = [handle_duplicate_index(s) for s in data_dict.values()] ret = pd.Series(dedup_data, index=df_columns) merged_df = pd.concat(ret.get_values(), axis=1) merged_df.columns = df_columns # 3) Fill NaN values depending on drawstyle if self._attr["drawstyle"] == "steps-post": merged_df = merged_df.ffill() elif self._attr["drawstyle"] == "steps-pre": merged_df = merged_df.bfill() elif self._attr["drawstyle"] == "steps-mid": merged_df = merged_df.ffill() else: # default merged_df = merged_df.interpolate() return merged_df
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))
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 ILinePlot(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 fill: Fill the area under the plots :type fill: bool :param fill_alpha: Opacity of filled area under the plots. Implies fill=True. :type fill_alpha: float :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 drawstyle: Set the drawstyle to a matplotlib compatible drawing style. .. note:: Only "steps-post" is supported as a valid value for the drawstyle. This creates a step plot. :type drawstyle: str :param sync_zoom: Synchronize the zoom of a group of plots. Zooming in one plot of a group (see below) will zoom in every plot of that group. Defaults to False. :type sync_zoom: boolean :param group: Name given to the plots created by this ILinePlot instance. This name is only used for synchronized zoom. If you zoom on any plot in a group all plots will zoom at the same time. :type group: string :param signals: A string of the type event_name:column to indicate the value that needs to be plotted. You can add an additional parameter to specify the color of the lin in rgb: "event_name:column:color". The color is specified as a comma separated list of rgb values, from 0 to 255 or from 0x0 to 0xff. E.g. 0xff,0x0,0x0 is red and 100,40,32 is brown. .. 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 """ def __init__(self, traces, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._layout = None super(ILinePlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: 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") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith("steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] window = self._attr["xlim"] if "xlim" in self._attr else None self.c_mgr = ConstraintManager(traces, self._attr["column"], self.templates, self._attr["pivot"], self._attr["filters"], window=window, zip_constraints=zip_constraints) def savefig(self, *args, **kwargs): raise NotImplementedError("Not Available for ILinePlot") def view(self, max_datapoints=75000, test=False): """Displays the graph :param max_datapoints: Maximum number of datapoints to plot. Dygraph can make the browser unresponsive if it tries to plot too many datapoints. Chrome 50 chokes at around 75000 on an i7-4770 @ 3.4GHz, Firefox 47 can handle up to 200000 before becoming too slow in the same machine. You can increase this number if you know what you're doing and are happy to wait for the plot to render. :type max_datapoints: int :param test: For testing purposes. Only set to true if run from the testsuite. :type test: boolean """ # Defer installation of IPython components # to the .view call to avoid any errors at # when importing the module. This facilitates # the importing of the module from outside # an IPython notebook if not test: IPythonConf.iplot_install("ILinePlot") self._attr["max_datapoints"] = max_datapoints if self._attr["concat"]: self._plot_concat() else: self._plot(self._attr["permute"], test) def set_defaults(self): """Sets the default attrs""" self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["pivot"] = AttrConf.PIVOT self._attr["permute"] = False self._attr["drawstyle"] = None self._attr["step_plot"] = False self._attr["fill"] = AttrConf.FILL self._attr["scatter"] = AttrConf.PLOT_SCATTER self._attr["point_size"] = AttrConf.POINT_SIZE self._attr["map_label"] = {} self._attr["title"] = AttrConf.TITLE def _plot(self, permute, test): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) self._layout = ILinePlotGen(len_pivots, **self._attr) plot_index = 0 for p_val in pivot_vals: data_dict = OrderedDict() for constraint in self.c_mgr: if permute: trace_idx, pivot = p_val if constraint.trace_index != trace_idx: continue legend = constraint._template.name + ":" + constraint.column else: pivot = p_val legend = str(constraint) result = constraint.result if pivot in result: data_dict[legend] = result[pivot] if permute: title = self.traces[plot_index].name elif pivot != AttrConf.PIVOT_VAL: title = "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) else: title = "" if len(data_dict) > 1: data_frame = self._fix_indexes(data_dict) else: data_frame = pd.DataFrame(data_dict) self._layout.add_plot(plot_index, data_frame, title, test=test) plot_index += 1 self._layout.finish() def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, _ = self.c_mgr.generate_pivots() plot_index = 0 self._layout = ILinePlotGen(len(self.c_mgr), **self._attr) for constraint in self.c_mgr: result = constraint.result title = str(constraint) data_dict = OrderedDict() for pivot in pivot_vals: if pivot in result: if pivot == AttrConf.PIVOT_VAL: key = ",".join(self._attr["column"]) else: key = "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) data_dict[key] = result[pivot] if len(data_dict) > 1: data_frame = self._fix_indexes(data_dict) else: data_frame = pd.DataFrame(data_dict) self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish() def _fix_indexes(self, data_dict): """ In case of multiple traces with different indexes (i.e. x-axis values), create new ones with same indexes """ # 1) Check if we are processing multiple traces if len(data_dict) <= 1: raise ValueError("Cannot fix indexes for single trace. "\ "Expecting multiple traces!") # 2) Merge the data frames to obtain common indexes df_columns = list(data_dict.keys()) dedup_data = [handle_duplicate_index(s) for s in data_dict.values()] ret = pd.Series(dedup_data, index=df_columns) merged_df = pd.concat(ret.get_values(), axis=1) merged_df.columns = df_columns # 3) Fill NaN values depending on drawstyle if self._attr["drawstyle"] == "steps-post": merged_df = merged_df.ffill() elif self._attr["drawstyle"] == "steps-pre": merged_df = merged_df.bfill() elif self._attr["drawstyle"] == "steps-mid": merged_df = merged_df.ffill() else: # default merged_df = merged_df.interpolate() return merged_df
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 ILinePlot(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 fill: Fill the area under the plots :type fill: bool :param drawstyle: Set the drawstyle to a matplotlib compatible drawing style. .. note:: Only "steps-post" is supported as a valid value for the drawstyle. This creates a step plot. :type drawstyle: str :param sync_zoom: Synchronize the zoom of a group of plots. Zooming in one plot of a group (see below) will zoom in every plot of that group. Defaults to False. :type sync_zoom: boolean :param group: Name given to the plots created by this ILinePlot instance. This name is only used for synchronized zoom. If you zoom on any plot in a group all plots will zoom at the same time. :type group: string :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 """ def __init__(self, traces, templates=None, **kwargs): # Default keys, each can be overridden in kwargs self._layout = None super(ILinePlot, self).__init__(traces=traces, templates=templates) self.set_defaults() for key in kwargs: 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") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith("steps"): self._attr["step_plot"] = True 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): raise NotImplementedError("Not Available for ILinePlot") def view(self, test=False): """Displays the graph""" # Defer installation of IPython components # to the .view call to avoid any errors at # when importing the module. This facilitates # the importing of the module from outside # an IPython notebook if not test: IPythonConf.iplot_install("ILinePlot") if self._attr["concat"]: self._plot_concat() else: self._plot(self._attr["permute"], test) def set_defaults(self): """Sets the default attrs""" self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["pivot"] = AttrConf.PIVOT self._attr["permute"] = False self._attr["drawstyle"] = None self._attr["step_plot"] = False self._attr["fill"] = AttrConf.FILL self._attr["draw_line"] = True self._attr["scatter"] = AttrConf.PLOT_SCATTER self._attr["point_size"] = AttrConf.POINT_SIZE self._attr["map_label"] = {} self._attr["title"] = AttrConf.TITLE def _plot(self, permute, test): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) self._layout = ILinePlotGen(len_pivots, **self._attr) plot_index = 0 for p_val in pivot_vals: data_frame = pd.Series() for constraint in self.c_mgr: if permute: trace_idx, pivot = p_val if constraint.trace_index != trace_idx: continue legend = constraint._template.name + ":" + constraint.column else: pivot = p_val legend = str(constraint) result = constraint.result if pivot in result: data_frame[legend] = result[pivot] if permute: title = self.traces[plot_index].name elif pivot != AttrConf.PIVOT_VAL: title = "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) else: title = "" # Fix data frame indexes if necessary data_frame = self._fix_indexes(data_frame) self._layout.add_plot(plot_index, data_frame, title, test=test) plot_index += 1 self._layout.finish() def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, _ = self.c_mgr.generate_pivots() plot_index = 0 self._layout = ILinePlotGen(len(self.c_mgr), **self._attr) for constraint in self.c_mgr: result = constraint.result title = str(constraint) data_frame = pd.Series() for pivot in pivot_vals: if pivot in result: if pivot == AttrConf.PIVOT_VAL: key = ",".join(self._attr["column"]) else: key = "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot)) data_frame[key] = result[pivot] # Fix data frame indexes if necessary data_frame = self._fix_indexes(data_frame) self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish() def _fix_indexes(self, data_frame): """ In case of multiple traces with different indexes (i.e. x-axis values), create new ones with same indexes """ # 1) Check if we are processing multiple traces if len(data_frame) > 1: # 2) Merge the data frames to obtain common indexes df_columns = list(data_frame.keys()) dedup_data = [handle_duplicate_index(s) for s in data_frame.values] data_frame = pd.Series(dedup_data, index=df_columns) merged_df = pd.concat(data_frame.get_values(), axis=1) merged_df.columns = df_columns # 3) Fill NaN values depending on drawstyle if self._attr["drawstyle"] == "steps-post": merged_df = merged_df.ffill() elif self._attr["drawstyle"] == "steps-pre": merged_df = merged_df.bfill() elif self._attr["drawstyle"] == "steps-mid": merged_df = merged_df.ffill() else: # default merged_df = merged_df.interpolate() return merged_df else: return data_frame
class ILinePlot(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 permute: Draw one plot for each of the runs specified :type permute: bool :param fill: Fill the area under the plots :type fill: bool :param drawstyle: Set the drawstyle to a matplotlib compatible drawing style. .. note:: Only "steps-post" is supported as a valid value for the drawstyle. This creates a step plot. :type drawstyle: str """ 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._layout = None self._check_data() for key in kwargs: self._attr[key] = kwargs[key] if "column" not in self._attr: raise RuntimeError("Value Column not specified") if self._attr["drawstyle"] and self._attr["drawstyle"].startswith( "steps"): self._attr["step_plot"] = True zip_constraints = not self._attr["permute"] self.c_mgr = ConstraintManager(runs, self._attr["column"], templates, self._attr["pivot"], self._attr["filters"], zip_constraints) super(ILinePlot, self).__init__() def savefig(self, *args, **kwargs): raise NotImplementedError("Not Available for ILinePlot") def view(self, test=False): """Displays the graph""" # Defer installation of IPython components # to the .view call to avoid any errors at # when importing the module. This facilitates # the importing of the module from outside # an IPython notebook IPythonConf.iplot_install("ILinePlot") if self._attr["concat"]: self._plot_concat() else: self._plot(self._attr["permute"]) def set_defaults(self): """Sets the default attrs""" self._attr["per_line"] = AttrConf.PER_LINE self._attr["concat"] = AttrConf.CONCAT self._attr["filters"] = {} self._attr["pivot"] = AttrConf.PIVOT self._attr["permute"] = False self._attr["drawstyle"] = None self._attr["step_plot"] = False self._attr["fill"] = AttrConf.FILL self._attr["draw_line"] = True self._attr["scatter"] = AttrConf.PLOT_SCATTER self._attr["point_size"] = AttrConf.POINT_SIZE def _plot(self, permute): """Internal Method called to draw the plot""" pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute) self._layout = ILinePlotGen(self._attr["per_line"], len_pivots, **self._attr) plot_index = 0 for p_val in pivot_vals: data_frame = pd.Series() for constraint in self.c_mgr: if permute: run_idx, pivot = p_val if constraint.run_index != run_idx: continue title = constraint.get_data_name() + ":" legend = constraint._column else: pivot = p_val title = "" legend = str(constraint) result = constraint.result if pivot in result: data_frame[legend] = result[pivot] if pivot == AttrConf.PIVOT_VAL: title += ",".join(self._attr["column"]) else: title += "{0}: {1}".format(self._attr["pivot"], pivot) self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish() def _plot_concat(self): """Plot all lines on a single figure""" pivot_vals, _ = self.c_mgr.generate_pivots() plot_index = 0 self._layout = ILinePlotGen(self._attr["per_line"], len(self.c_mgr), **self._attr) for constraint in self.c_mgr: result = constraint.result title = str(constraint) data_frame = pd.Series() for pivot in pivot_vals: if pivot in result: if pivot == AttrConf.PIVOT_VAL: key = ",".join(self._attr["column"]) else: key = "{0}: {1}".format(self._attr["pivot"], pivot) data_frame[key] = result[pivot] self._layout.add_plot(plot_index, data_frame, title) plot_index += 1 self._layout.finish()