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)
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, )
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
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
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
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))
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)
def _legend_artist(self, variables, value, scales): key = resolve_properties(self, {v: value for v in variables}, scales) return mpl.lines.Line2D( [], [], color=key["color"], linewidth=key["linewidth"], linestyle=key["linestyle"], **self.artist_kws, )
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, )
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
def _legend_artist(self, variables, value, scales): key = resolve_properties(self, {v: value for v in variables}, scales) artist_kws = self.artist_kws.copy() capstyle = artist_kws.pop("capstyle") artist_kws["solid_capstyle"] = capstyle artist_kws["dash_capstyle"] = capstyle return mpl.lines.Line2D( [], [], color=key["color"], linewidth=key["linewidth"], linestyle=key["linestyle"], **artist_kws, )
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)
def _plot(self, split_gen, scales, orient): for keys, data, ax in split_gen(dropna=False): keys = resolve_properties(self, keys, scales) if self.sort: # TODO where to dropna? data = data.sort_values(orient) else: data.loc[data.isna().any(axis=1), ["x", "y"]] = np.nan line = mpl.lines.Line2D( data["x"].to_numpy(), data["y"].to_numpy(), color=keys["color"], alpha=keys["alpha"], linewidth=keys["linewidth"], linestyle=keys["linestyle"], **self. artist_kws, # TODO keep? remove? be consistent across marks ) ax.add_line(line)