Exemple #1
0
    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__()
Exemple #2
0
    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__()
Exemple #3
0
    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)
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
    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)
Exemple #7
0
    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__()
Exemple #8
0
    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)
Exemple #9
0
    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())
Exemple #10
0
    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())
Exemple #11
0
    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])
Exemple #12
0
    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())
Exemple #13
0
    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)
Exemple #14
0
    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])
Exemple #15
0
    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())
Exemple #16
0
    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)
Exemple #17
0
    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])
Exemple #18
0
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()
Exemple #19
0
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")
Exemple #20
0
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()
Exemple #21
0
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
Exemple #22
0
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))
Exemple #23
0
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")
Exemple #24
0
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
Exemple #25
0
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))
Exemple #26
0
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))
Exemple #27
0
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
Exemple #28
0
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()