def line(h1: Union[Histogram1D, "HistogramCollection"], ax: Axes, *, errors: bool = False, **kwargs): """Line plot of 1D histogram.""" show_stats = kwargs.pop("show_stats", False) show_values = kwargs.pop("show_values", False) density = kwargs.pop("density", False) cumulative = kwargs.pop("cumulative", False) value_format = kwargs.pop("value_format", None) text_kwargs = pop_kwargs_with_prefix("text_", kwargs) kwargs["label"] = kwargs.get("label", h1.name) data = get_data(h1, cumulative=cumulative, density=density) _apply_xy_lims(ax, h1, data, kwargs) _add_ticks(ax, h1, kwargs) _add_labels(ax, h1, kwargs) if errors: err_data = get_err_data(h1, cumulative=cumulative, density=density) ax.errorbar(h1.bin_centers, data, yerr=err_data, fmt=kwargs.pop("fmt", "-"), ecolor=kwargs.pop("ecolor", "black"), **kwargs) else: ax.plot(h1.bin_centers, data, **kwargs) if show_stats: _add_stats_box(h1, ax, stats=show_stats) if show_values: _add_values(ax, h1, data, value_format=value_format, **text_kwargs)
def polar_map(hist: Histogram2D, ax: Axes, *, show_zero: bool = True, show_colorbar: bool = True, **kwargs): """Polar map of polar histograms. Similar to map, but supports less parameters.""" data = get_data(hist, cumulative=False, flatten=True, density=kwargs.pop("density", False)) cmap = _get_cmap(kwargs) norm, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) rpos, phipos = (arr.flatten() for arr in hist.get_bin_left_edges()) dr, dphi = (arr.flatten() for arr in hist.get_bin_widths()) rmax, _ = (arr.flatten() for arr in hist.get_bin_right_edges()) bar_args = {} if "zorder" in kwargs: bar_args["zorder"] = kwargs.pop("zorder") alphas = _get_alpha_data(cmap_data, kwargs) if np.isscalar(alphas): alphas = np.ones_like(data) * alphas for i in range(len(rpos)): if data[i] > 0 or show_zero: bin_color = colors[i] # TODO: align = "edge" bars = ax.bar(phipos[i], dr[i], width=dphi[i], bottom=rpos[i], align='edge', color=bin_color, edgecolor=kwargs.get("grid_color", cmap(0.5)), lw=kwargs.get("lw", 0.5), alpha=alphas[i], **bar_args) ax.set_rmax(rmax.max()) if show_colorbar: _add_colorbar(ax, cmap, cmap_data, norm)
def cylinder_map(hist: Union[Histogram2D, CylinderSurfaceHistogram], ax: Axes3D, *, show_zero: bool = True, **kwargs): """Heat map plotted on the surface of a cylinder.""" data = get_data(hist, cumulative=False, flatten=False, density=kwargs.pop("density", False)) cmap = _get_cmap(kwargs) norm, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) if hasattr(hist, "radius"): r = kwargs.pop("radius", hist.radius) else: r = kwargs.pop("radius", 1) xs = r * np.outer(np.cos(hist.numpy_bins[0]), np.ones(hist.shape[1] + 1)) ys = r * np.outer(np.sin(hist.numpy_bins[0]), np.ones(hist.shape[1] + 1)) zs = np.outer(np.ones(hist.shape[0] + 1), hist.numpy_bins[1]) for i in range(hist.shape[0]): for j in range(hist.shape[1]): if not show_zero and not data[i, j]: continue x = xs[i, j], xs[i, j + 1], xs[i + 1, j + 1], xs[i + 1, j] y = ys[i, j], ys[i, j + 1], ys[i + 1, j + 1], ys[i + 1, j] z = zs[i, j], zs[i, j + 1], zs[i + 1, j + 1], zs[i + 1, j] verts = [list(zip(x, y, z))] col = Poly3DCollection(verts) col.set_facecolor(colors[i, j]) ax.add_collection3d(col) ax.set_xlabel("x") ax.set_ylabel("y") ax.set_zlabel("z") if matplotlib.__version__ < "2": ax.plot_surface([], [], [], color="b") ax.set_xlim(-r * 1.1, r * 1.1) ax.set_ylim(-r * 1.1, r * 1.1) ax.set_zlim(zs.min(), zs.max())
def globe_map(hist: Union[Histogram2D, DirectionalHistogram], ax: Axes3D, *, show_zero: bool = True, **kwargs): """Heat map plotted on the surface of a sphere.""" data = get_data(hist, cumulative=False, flatten=False, density=kwargs.pop("density", False)) cmap = _get_cmap(kwargs) norm, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) lw = kwargs.pop("lw", 1) r = 1 xs = r * np.outer(np.sin(hist.numpy_bins[0]), np.cos(hist.numpy_bins[1])) ys = r * np.outer(np.sin(hist.numpy_bins[0]), np.sin(hist.numpy_bins[1])) zs = r * np.outer(np.cos(hist.numpy_bins[0]), np.ones(hist.shape[1] + 1)) for i in range(hist.shape[0]): for j in range(hist.shape[1]): if not show_zero and not data[i, j]: continue x = xs[i, j], xs[i, j + 1], xs[i + 1, j + 1], xs[i + 1, j] y = ys[i, j], ys[i, j + 1], ys[i + 1, j + 1], ys[i + 1, j] z = zs[i, j], zs[i, j + 1], zs[i + 1, j + 1], zs[i + 1, j] verts = [list(zip(x, y, z))] col = Poly3DCollection(verts) col.set_facecolor(colors[i, j]) col.set_edgecolor("black") col.set_linewidth(lw) ax.add_collection3d(col) ax.set_xlabel("x") ax.set_ylabel("y") ax.set_zlabel("z") if matplotlib.__version__ < "2": ax.plot_surface([], [], [], color="b") ax.set_xlim(-1.1, 1.1) ax.set_ylim(-1.1, 1.1) ax.set_zlim(-1.1, 1.1) return ax
def image(h2: Histogram2D, ax: Axes, *, show_colorbar: bool = True, interpolation: str = "nearest", **kwargs): """Plot of 2D histograms based on pixmaps. Similar to map, but it: - has fewer options - is much more effective (enables thousands) - does not support irregular bins Parameters ---------- interpolation: interpolation parameter passed to imshow, default: "nearest" (creates rectangles) """ cmap = _get_cmap(kwargs) # h2 as well? data = get_data(h2, cumulative=False, density=kwargs.pop("density", False)) norm, cmap_data = _get_cmap_data(data, kwargs) # zorder = kwargs.pop("zorder", None) for binning in h2._binnings: if not binning.is_regular(): raise RuntimeError( "Histograms with irregular bins cannot be plotted using image method." ) kwargs["interpolation"] = interpolation if kwargs.get("xscale") == "log" or kwargs.get("yscale") == "log": raise RuntimeError("Cannot use logarithmic axes with image plots.") _apply_xy_lims(ax, h2, data=data, kwargs=kwargs) _add_labels(ax, h2, kwargs) ax.imshow(data.T[::-1, :], cmap=cmap, norm=norm, extent=(h2.bins[0][0, 0], h2.bins[0][-1, 1], h2.bins[1][0, 0], h2.bins[1][-1, 1]), aspect="auto", **kwargs) if show_colorbar: _add_colorbar(ax, cmap, cmap_data, norm)
def bar3d(h2: Histogram2D, ax: Axes3D, **kwargs): """Plot of 2D histograms as 3D boxes.""" density = kwargs.pop("density", False) data = get_data(h2, cumulative=False, flatten=True, density=density) if "cmap" in kwargs: cmap = _get_cmap(kwargs) _, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) else: colors = kwargs.pop("color", kwargs.pop("c", "blue")) xpos, ypos = (arr.flatten() for arr in h2.get_bin_centers()) zpos = np.zeros_like(ypos) dx, dy = (arr.flatten() for arr in h2.get_bin_widths()) _add_labels(ax, h2, kwargs) ax.bar3d(xpos, ypos, zpos, dx, dy, data, color=colors, **kwargs) ax.set_zlabel("density" if density else "frequency")
def bar(h1: Histogram1D, ax: Axes, *, errors: bool = False, **kwargs): """Bar plot of 1D histograms.""" show_stats = kwargs.pop("show_stats", False) show_values = kwargs.pop("show_values", False) value_format = kwargs.pop("value_format", None) density = kwargs.pop("density", False) cumulative = kwargs.pop("cumulative", False) label = kwargs.pop("label", h1.name) lw = kwargs.pop("linewidth", kwargs.pop("lw", 0.5)) text_kwargs = pop_kwargs_with_prefix("text_", kwargs) data = get_data(h1, cumulative=cumulative, density=density) if "cmap" in kwargs: cmap = _get_cmap(kwargs) _, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) else: colors = kwargs.pop("color", kwargs.pop("c", None)) _apply_xy_lims(ax, h1, data, kwargs) _add_ticks(ax, h1, kwargs) if errors: err_data = get_err_data(h1, cumulative=cumulative, density=density) kwargs["yerr"] = err_data if "ecolor" not in kwargs: kwargs["ecolor"] = "black" _add_labels(ax, h1, kwargs) ax.bar(h1.bin_left_edges, data, h1.bin_widths, align="edge", label=label, color=colors, linewidth=lw, **kwargs) if show_values: _add_values(ax, h1, data, value_format=value_format, **text_kwargs) if show_stats: _add_stats_box(h1, ax, stats=show_stats)
def fill(h1: Histogram1D, ax: Axes, **kwargs): """Fill plot of 1D histogram.""" show_stats = kwargs.pop("show_stats", False) # show_values = kwargs.pop("show_values", False) density = kwargs.pop("density", False) cumulative = kwargs.pop("cumulative", False) kwargs["label"] = kwargs.get("label", h1.name) data = get_data(h1, cumulative=cumulative, density=density) _apply_xy_lims(ax, h1, data, kwargs) _add_ticks(ax, h1, kwargs) _add_labels(ax, h1, kwargs) ax.fill_between(h1.bin_centers, 0, data, **kwargs) if show_stats: _add_stats_box(h1, ax, stats=show_stats) # if show_values: # _add_values(ax, h1, data) return ax
def step(h1: Histogram1D, ax: Axes, **kwargs): """Step line-plot of 1D histogram.""" show_stats = kwargs.pop("show_stats", False) show_values = kwargs.pop("show_values", False) density = kwargs.pop("density", False) cumulative = kwargs.pop("cumulative", False) value_format = kwargs.pop("value_format", None) text_kwargs = pop_kwargs_with_prefix("text_", kwargs) kwargs["label"] = kwargs.get("label", h1.name) data = get_data(h1, cumulative=cumulative, density=density) _apply_xy_lims(ax, h1, data, kwargs) _add_ticks(ax, h1, kwargs) _add_labels(ax, h1, kwargs) ax.step(h1.numpy_bins, np.concatenate([data[:1], data]), **kwargs) if show_stats: _add_stats_box(h1, ax, stats=show_stats) if show_values: _add_values(ax, h1, data, value_format=value_format, **text_kwargs)
def scatter(h1: Histogram1D, ax: Axes, *, errors: bool = False, **kwargs): """Scatter plot of 1D histogram.""" show_stats = kwargs.pop("show_stats", False) show_values = kwargs.pop("show_values", False) density = kwargs.pop("density", False) cumulative = kwargs.pop("cumulative", False) value_format = kwargs.pop("value_format", None) text_kwargs = pop_kwargs_with_prefix("text_", kwargs) label = kwargs.pop("label", h1.name) data = get_data(h1, cumulative=cumulative, density=density) if "cmap" in kwargs: cmap = _get_cmap(kwargs) _, cmap_data = _get_cmap_data(data, kwargs) kwargs["color"] = cmap(cmap_data) elif "color" in kwargs or "c" in kwargs: kwargs["color"] = kwargs.pop("color", kwargs.get("c", None)) _apply_xy_lims(ax, h1, data, kwargs) _add_ticks(ax, h1, kwargs) _add_labels(ax, h1, kwargs) if errors: err_data = get_err_data(h1, cumulative=cumulative, density=density) ax.errorbar(h1.bin_centers, data, yerr=err_data, fmt=kwargs.pop("fmt", "o"), ecolor=kwargs.pop("ecolor", "black"), ms=0) ax.scatter(h1.bin_centers, data, label=label, **kwargs) if show_values: _add_values(ax, h1, data, value_format=value_format, **text_kwargs) if show_stats: _add_stats_box(h1, ax, stats=show_stats)
def surface_map(hist, ax: Axes3D, *, show_zero: bool = True, x=(lambda x, y: x), y=(lambda x, y: y), z=(lambda x, y: 0), **kwargs): """Coloured-rectangle plot of 2D histogram, placed on an arbitrary surface. Each bin is mapped to a rectangle in 3D space using the x,y,z functions. Parameters ---------- hist : Histogram2D show_zero : Optional[bool] Whether to show coloured box for bins with 0 frequency (otherwise background). x : function Function with 2 parameters used to map bins to spatial x coordinate y : function Function with 2 parameters used to map bins to spatial y coordinate z : function Function with 2 parameters used to map bins to spatial z coordinate Returns ------- matplotlib.axes._subplots.Axes3DSubplot See Also -------- map, cylinder_map, globe_map """ data = get_data(hist, cumulative=False, flatten=False, density=kwargs.pop("density", False)) cmap = _get_cmap(kwargs) norm, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) xs = np.ndarray((hist.shape[0] + 1, hist.shape[1] + 1), dtype=float) ys = np.ndarray((hist.shape[0] + 1, hist.shape[1] + 1), dtype=float) zs = np.ndarray((hist.shape[0] + 1, hist.shape[1] + 1), dtype=float) edges_x = hist.numpy_bins[0] edges_y = hist.numpy_bins[1] for i in range(hist.shape[0] + 1): for j in range(hist.shape[1] + 1): xs[i, j] = x(edges_x[i], edges_y[j]) ys[i, j] = y(edges_x[i], edges_y[j]) zs[i, j] = z(edges_x[i], edges_y[j]) for i in range(hist.shape[0]): for j in range(hist.shape[1]): if not show_zero and not data[i, j]: continue x = xs[i, j], xs[i, j + 1], xs[i + 1, j + 1], xs[i + 1, j] y = ys[i, j], ys[i, j + 1], ys[i + 1, j + 1], ys[i + 1, j] z = zs[i, j], zs[i, j + 1], zs[i + 1, j + 1], zs[i + 1, j] verts = [list(zip(x, y, z))] col = Poly3DCollection(verts) col.set_facecolor(colors[i, j]) ax.add_collection3d(col) ax.set_xlabel("x") ax.set_ylabel("y") ax.set_zlabel("z") if matplotlib.__version__ < "2": ax.plot_surface([], [], [], color="b") # Dummy plot ax.set_xlim(xs.min(), xs.max()) ax.set_ylim(ys.min(), ys.max()) ax.set_zlim(zs.min(), zs.max()) # ax.plot_surface(x, y, z, rstride=hist.shape[0], color="b") return ax
def map(h2: Histogram2D, ax: Axes, *, show_zero: bool = True, show_values: bool = False, show_colorbar: bool = True, x=None, y=None, **kwargs): """Coloured-rectangle plot of 2D histogram. Parameters ---------- show_zero : Whether to show coloured box for bins with 0 frequency (otherwise background). show_values : Whether to show labels with frequencies/densities in the middle of the bin text_color : Optional Colour of text descriptions text_alpha : Optional[float] Alpha for the text labels only x : Optional[Callable] Transformation of x bin coordinates y : Optional[Callable] Transformation of y bin coordinates zorder : float z-order in the axis (higher number above lower) See Also -------- image, polar_map, surface_map Notes ----- If you transform axes using x or y parameters, the deduction of axis limits does not work well automatically. Please, make sure to attend to it yourself. The densities in transformed maps are calculated from original bins. """ # Detect transformation transformed = False if x is not None or y is not None: if not x: x = lambda x, y: x if not y: y = lambda x, y: y transformed = True value_format = kwargs.pop("value_format", lambda x: str(x)) # TODO: Implement correctly the text_kwargs if isinstance(value_format, str): format_str = "{0:" + value_format + "}" value_format = lambda x: format_str.format(x) rect_args = {} if "zorder" in kwargs: rect_args["zorder"] = kwargs.pop("zorder") data = get_data(h2, cumulative=False, flatten=True, density=kwargs.pop("density", False)) cmap = _get_cmap(kwargs) norm, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) xpos, ypos = (arr.flatten() for arr in h2.get_bin_left_edges()) dx, dy = (arr.flatten() for arr in h2.get_bin_widths()) text_x, text_y = (arr.flatten() for arr in h2.get_bin_centers()) _apply_xy_lims(ax, h2, data=data, kwargs=kwargs) _add_labels(ax, h2, kwargs) ax.autoscale_view() alphas = _get_alpha_data(cmap_data, kwargs) if np.isscalar(alphas): alphas = np.ones_like(data) * alphas for i in range(len(xpos)): bin_color = colors[i] alpha = alphas[i] if data[i] != 0 or show_zero: if not transformed: rect = plt.Rectangle([xpos[i], ypos[i]], dx[i], dy[i], facecolor=bin_color, edgecolor=kwargs.get( "grid_color", cmap(0.5)), lw=kwargs.get("lw", 0.5), alpha=alpha, **rect_args) tx, ty = text_x[i], text_y[i] else: # See http://matplotlib.org/users/path_tutorial.html points = ((xpos[i], ypos[i]), (xpos[i] + dx[i], ypos[i]), (xpos[i] + dx[i], ypos[i] + dy[i]), (xpos[i], ypos[i] + dy[i]), (xpos[i], ypos[i])) verts = [(x(*p), y(*p)) for p in points] codes = [ path.Path.MOVETO, path.Path.LINETO, path.Path.LINETO, path.Path.LINETO, path.Path.CLOSEPOLY, ] rect_path = path.Path(verts, codes) rect = patches.PathPatch(rect_path, facecolor=bin_color, edgecolor=kwargs.get( "grid_color", cmap(0.5)), lw=kwargs.get("lw", 0.5), alpha=alpha, **rect_args) tx = x(text_x[i], text_y[i]) ty = y(text_x[i], text_y[i]) ax.add_patch(rect) if show_values: text = value_format(data[i]) yiq_y = np.dot(bin_color[:3], [0.299, 0.587, 0.114]) text_color = kwargs.get("text_color", None) if not text_color: if yiq_y > 0.5: text_color = (0.0, 0.0, 0.0, kwargs.get("text_alpha", alpha)) else: text_color = (1.0, 1.0, 1.0, kwargs.get("text_alpha", alpha)) ax.text(tx, ty, text, horizontalalignment='center', verticalalignment='center', color=text_color, clip_on=True, **rect_args) if show_colorbar: _add_colorbar(ax, cmap, cmap_data, norm)