Exemple #1
0
    def _plot(self, split_gen, scales, orient):

        for keys, data, ax in split_gen(keep_na=not self._sort):

            vals = resolve_properties(self, keys, scales)
            vals["color"] = resolve_color(self, keys, scales=scales)
            vals["fillcolor"] = resolve_color(self, keys, prefix="fill", scales=scales)
            vals["edgecolor"] = resolve_color(self, keys, prefix="edge", scales=scales)

            # https://github.com/matplotlib/matplotlib/pull/16692
            if Version(mpl.__version__) < Version("3.3.0"):
                vals["marker"] = vals["marker"]._marker

            if self._sort:
                data = data.sort_values(orient)

            artist_kws = self.artist_kws.copy()
            self._handle_capstyle(artist_kws, vals)

            line = mpl.lines.Line2D(
                data["x"].to_numpy(),
                data["y"].to_numpy(),
                color=vals["color"],
                linewidth=vals["linewidth"],
                linestyle=vals["linestyle"],
                marker=vals["marker"],
                markersize=vals["pointsize"],
                markerfacecolor=vals["fillcolor"],
                markeredgecolor=vals["edgecolor"],
                markeredgewidth=vals["edgewidth"],
                **artist_kws,
            )
            ax.add_line(line)
Exemple #2
0
    def _legend_artist(self, variables, value, scales):

        keys = {v: value for v in variables}
        vals = resolve_properties(self, keys, scales)
        vals["color"] = resolve_color(self, keys, scales=scales)
        vals["fillcolor"] = resolve_color(self, keys, prefix="fill", scales=scales)
        vals["edgecolor"] = resolve_color(self, keys, prefix="edge", scales=scales)

        # https://github.com/matplotlib/matplotlib/pull/16692
        if Version(mpl.__version__) < Version("3.3.0"):
            vals["marker"] = vals["marker"]._marker

        artist_kws = self.artist_kws.copy()
        self._handle_capstyle(artist_kws, vals)

        return mpl.lines.Line2D(
            [], [],
            color=vals["color"],
            linewidth=vals["linewidth"],
            linestyle=vals["linestyle"],
            marker=vals["marker"],
            markersize=vals["pointsize"],
            markerfacecolor=vals["fillcolor"],
            markeredgecolor=vals["edgecolor"],
            markeredgewidth=vals["edgewidth"],
            **artist_kws,
        )
Exemple #3
0
    def _resolve_properties(self, data, scales):
        # TODO this is maybe a little hacky, is there a better abstraction?
        resolved = super()._resolve_properties(data, scales)

        filled = resolved["fill"]

        main_stroke = resolved["stroke"]
        edge_stroke = resolved["edgewidth"]
        resolved["linewidth"] = np.where(filled, edge_stroke, main_stroke)

        # Overwrite the colors that the super class set
        main_color = resolve_color(self, data, "", scales)
        edge_color = resolve_color(self, data, "edge", scales)

        if not np.isscalar(filled):
            # Expand dims to use in np.where with rgba arrays
            filled = filled[:, None]
        resolved["edgecolor"] = np.where(filled, edge_color, main_color)

        filled = np.squeeze(filled)
        if isinstance(main_color, tuple):
            main_color = tuple([*main_color[:3], main_color[3] * filled])
        else:
            main_color = np.c_[main_color[:, :3], main_color[:, 3] * filled]
        resolved["facecolor"] = main_color

        return resolved
Exemple #4
0
    def _resolve_properties(self, data, scales):

        resolved = resolve_properties(self, data, scales)
        resolved["path"] = self._resolve_paths(resolved)

        if isinstance(data, dict):  # TODO need a better way to check
            filled_marker = resolved["marker"].is_filled()
        else:
            filled_marker = [m.is_filled() for m in resolved["marker"]]

        resolved["linewidth"] = resolved["stroke"]
        resolved["fill"] = resolved["fill"] * filled_marker
        resolved["size"] = resolved["pointsize"]**2

        resolved["edgecolor"] = resolve_color(self, data, "", scales)
        resolved["facecolor"] = resolve_color(self, data, "fill", scales)

        # Because only Dot, and not Scatter, has an edgestyle
        resolved.setdefault("edgestyle", (0, None))

        fc = resolved["facecolor"]
        if isinstance(fc, tuple):
            resolved["facecolor"] = fc[0], fc[1], fc[
                2], fc[3] * resolved["fill"]
        else:
            fc[:,
               3] = fc[:,
                       3] * resolved["fill"]  # TODO Is inplace mod a problem?
            resolved["facecolor"] = fc

        return resolved
Exemple #5
0
    def _plot(self, split_gen, scales, orient):

        patches = defaultdict(list)

        for keys, data, ax in split_gen():

            kws = {}
            data = self._standardize_coordinate_parameters(data, orient)
            resolved = resolve_properties(self, keys, scales)
            verts = self._get_verts(data, orient)
            ax.update_datalim(verts)

            # TODO should really move this logic into resolve_color
            fc = resolve_color(self, keys, "", scales)
            if not resolved["fill"]:
                fc = mpl.colors.to_rgba(fc, 0)

            kws["facecolor"] = fc
            kws["edgecolor"] = resolve_color(self, keys, "edge", scales)
            kws["linewidth"] = resolved["edgewidth"]
            kws["linestyle"] = resolved["edgestyle"]

            patches[ax].append(mpl.patches.Polygon(verts, **kws))

        for ax, ax_patches in patches.items():

            for patch in ax_patches:
                self._postprocess_artist(patch, ax, orient)
                ax.add_patch(patch)
Exemple #6
0
    def _plot(self, split_gen, scales, orient):

        kws = {}

        for keys, data, ax in split_gen():

            kws.setdefault(ax, defaultdict(list))

            data = self._standardize_coordinate_parameters(data, orient)
            resolved = resolve_properties(self, keys, scales)
            verts = self._get_verts(data, orient)

            ax.update_datalim(verts)
            kws[ax]["verts"].append(verts)

            # TODO fill= is not working here properly
            # We could hack a fix, but would be better to handle fill in resolve_color

            kws[ax]["facecolors"].append(resolve_color(self, keys, "", scales))
            kws[ax]["edgecolors"].append(
                resolve_color(self, keys, "edge", scales))

            kws[ax]["linewidth"].append(resolved["edgewidth"])
            kws[ax]["linestyle"].append(resolved["edgestyle"])

        for ax, ax_kws in kws.items():
            ax.add_collection(mpl.collections.PolyCollection(**ax_kws))
Exemple #7
0
    def test_color(self):

        c, a = "C1", .5
        m = self.mark(color=c, alpha=a)

        assert resolve_color(m, {}) == mpl.colors.to_rgba(c, a)

        df = pd.DataFrame(index=pd.RangeIndex(10))
        cs = [c] * len(df)
        assert_array_equal(resolve_color(m, df), mpl.colors.to_rgba_array(cs, a))
Exemple #8
0
    def _legend_artist(self, variables, value, scales):

        keys = {v: value for v in variables}
        resolved = resolve_properties(self, keys, scales)

        return mpl.patches.Patch(
            facecolor=resolve_color(self, keys, "", scales),
            edgecolor=resolve_color(self, keys, "edge", scales),
            linewidth=resolved["edgewidth"],
            linestyle=resolved["edgestyle"],
            **self.artist_kws,
        )
Exemple #9
0
    def _resolve_properties(self, data, scales):

        resolved = resolve_properties(self, data, scales)

        resolved["facecolor"] = resolve_color(self, data, "", scales)
        resolved["edgecolor"] = resolve_color(self, data, "edge", scales)

        fc = resolved["facecolor"]
        if isinstance(fc, tuple):
            resolved["facecolor"] = fc[0], fc[1], fc[2], fc[3] * resolved["fill"]
        else:
            fc[:, 3] = fc[:, 3] * resolved["fill"]  # TODO Is inplace mod a problem?
            resolved["facecolor"] = fc

        return resolved
Exemple #10
0
    def _setup_lines(self, split_gen, scales, orient):

        line_data = {}

        other = {"x": "y", "y": "x"}[orient]

        for keys, data, ax in split_gen(keep_na=not self._sort):

            if ax not in line_data:
                line_data[ax] = {
                    "segments": [],
                    "colors": [],
                    "linewidths": [],
                    "linestyles": [],
                }

            vals = resolve_properties(self, keys, scales)
            vals["color"] = resolve_color(self, keys, scales=scales)

            cols = [orient, f"{other}min", f"{other}max"]
            data = data[cols].melt(orient, value_name=other)[["x", "y"]]
            segments = [d.to_numpy() for _, d in data.groupby(orient)]

            line_data[ax]["segments"].extend(segments)

            n = len(segments)
            line_data[ax]["colors"].extend([vals["color"]] * n)
            line_data[ax]["linewidths"].extend([vals["linewidth"]] * n)
            line_data[ax]["linestyles"].extend([vals["linestyle"]] * n)

        return line_data
Exemple #11
0
    def _setup_lines(self, split_gen, scales, orient):

        line_data = {}

        for keys, data, ax in split_gen(keep_na=not self._sort):

            if ax not in line_data:
                line_data[ax] = {
                    "segments": [],
                    "colors": [],
                    "linewidths": [],
                    "linestyles": [],
                }

            vals = resolve_properties(self, keys, scales)
            vals["color"] = resolve_color(self, keys, scales=scales)

            if self._sort:
                data = data.sort_values(orient)

            # Column stack to avoid block consolidation
            xy = np.column_stack([data["x"], data["y"]])
            line_data[ax]["segments"].append(xy)
            line_data[ax]["colors"].append(vals["color"])
            line_data[ax]["linewidths"].append(vals["linewidth"])
            line_data[ax]["linestyles"].append(vals["linestyle"])

        return line_data
Exemple #12
0
    def test_color_mapped_alpha(self):

        c = "r"
        values = {"a": .2, "b": .5, "c": .8}

        m = self.mark(color=c, alpha=Mappable(1))
        scales = {"alpha": lambda s: np.array([values[s_i] for s_i in s])}

        assert resolve_color(m, {"alpha": "b"}, "", scales) == mpl.colors.to_rgba(c, .5)

        df = pd.DataFrame({"alpha": list(values.keys())})

        # Do this in two steps for mpl 3.2 compat
        expected = mpl.colors.to_rgba_array([c] * len(df))
        expected[:, 3] = list(values.values())

        assert_array_equal(resolve_color(m, df, "", scales), expected)
Exemple #13
0
    def test_fillcolor(self):

        c, a = "green", .8
        fa = .2
        m = self.mark(
            color=c, alpha=a,
            fillcolor=Mappable(depend="color"), fillalpha=Mappable(fa),
        )

        assert resolve_color(m, {}) == mpl.colors.to_rgba(c, a)
        assert resolve_color(m, {}, "fill") == mpl.colors.to_rgba(c, fa)

        df = pd.DataFrame(index=pd.RangeIndex(10))
        cs = [c] * len(df)
        assert_array_equal(resolve_color(m, df), mpl.colors.to_rgba_array(cs, a))
        assert_array_equal(
            resolve_color(m, df, "fill"), mpl.colors.to_rgba_array(cs, fa)
        )
Exemple #14
0
    def test_color_scaled_as_strings(self):

        colors = ["C1", "dodgerblue", "#445566"]
        m = self.mark()
        scales = {"color": lambda s: colors}

        actual = resolve_color(m, {"color": pd.Series(["a", "b", "c"])}, "", scales)
        expected = mpl.colors.to_rgba_array(colors)
        assert_array_equal(actual, expected)
Exemple #15
0
    def _plot(self, split_gen, scales, orient):

        line_data = {}

        for keys, data, ax in split_gen(keep_na=not self._sort):

            if ax not in line_data:
                line_data[ax] = {
                    "segments": [],
                    "colors": [],
                    "linewidths": [],
                    "linestyles": [],
                }

            vals = resolve_properties(self, keys, scales)
            vals["color"] = resolve_color(self, keys, scales=scales)

            if self._sort:
                data = data.sort_values(orient)

            # TODO comment about block consolidation
            xy = np.column_stack([data["x"], data["y"]])
            line_data[ax]["segments"].append(xy)
            line_data[ax]["colors"].append(vals["color"])
            line_data[ax]["linewidths"].append(vals["linewidth"])
            line_data[ax]["linestyles"].append(vals["linestyle"])

        for ax, ax_data in line_data.items():
            lines = mpl.collections.LineCollection(
                **ax_data,
                **self.artist_kws,
            )
            ax.add_collection(lines, autolim=False)
            # https://github.com/matplotlib/matplotlib/issues/23129
            # TODO get paths from lines object?
            xy = np.concatenate(ax_data["segments"])
            ax.dataLim.update_from_data_xy(xy,
                                           ax.ignore_existing_data_limits,
                                           updatex=True,
                                           updatey=True)