Diff of /src/scpanel/palettes.py [000000] .. [d90ecf]

Switch to side-by-side view

--- a
+++ b/src/scpanel/palettes.py
@@ -0,0 +1,231 @@
+"""Color palettes in addition to matplotlib's palettes."""
+
+from typing import Mapping, Sequence
+
+from matplotlib import cm, colors
+
+tab10 = [
+    "#1f77b4",
+    "#ff7f0e",
+    "#2ca02c",
+    "#d62728",
+    "#9467bd",
+    "#8c564b",
+    "#e377c2",
+    "#7f7f7f",
+    "#bcbd22",
+    "#17becf",
+]
+# Colorblindness adjusted vega_10
+# See https://github.com/scverse/scanpy/issues/387
+vega_10 = list(map(colors.to_hex, cm.tab10.colors))
+vega_10_scanpy = vega_10.copy()
+vega_10_scanpy[2] = "#279e68"  # green
+vega_10_scanpy[4] = "#aa40fc"  # purple
+vega_10_scanpy[8] = "#b5bd61"  # kakhi
+
+# default matplotlib 2.0 palette
+# see 'category20' on https://github.com/vega/vega/wiki/Scales#scale-range-literals
+vega_20 = list(map(colors.to_hex, cm.tab20.colors))
+
+# reorderd, some removed, some added
+vega_20_scanpy = [
+    # dark without grey:
+    *vega_20[0:14:2],
+    *vega_20[16::2],
+    # light without grey:
+    *vega_20[1:15:2],
+    *vega_20[17::2],
+    # manual additions:
+    "#ad494a",
+    "#8c6d31",
+]
+vega_20_scanpy[2] = vega_10_scanpy[2]
+vega_20_scanpy[4] = vega_10_scanpy[4]
+vega_20_scanpy[7] = vega_10_scanpy[8]  # kakhi shifted by missing grey
+## ['#1f77b4','#aec7e8','#ff7f0e','#ffbb78','#2ca02c','#98df8a',
+##  '#d62728','#ff9896','#9467bd','#c5b0d5','#8c564b','#c49c94',
+##  '#e377c2','#f7b6d2','#7f7f7f','#c7c7c7','#bcbd22','#dbdb8d','#17becf','#9edae5']
+# TODO: also replace pale colors if necessary
+
+default_20 = vega_20_scanpy
+
+# https://graphicdesign.stackexchange.com/questions/3682/where-can-i-find-a-large-palette-set-of-contrasting-colors-for-coloring-many-d
+# update 1
+# orig reference https://research.wu.ac.at/en/publications/escaping-rgbland-selecting-colors-for-statistical-graphics-26
+zeileis_28 = [
+    "#023fa5",
+    "#7d87b9",
+    "#bec1d4",
+    "#d6bcc0",
+    "#bb7784",
+    "#8e063b",
+    "#4a6fe3",
+    "#8595e1",
+    "#b5bbe3",
+    "#e6afb9",
+    "#e07b91",
+    "#d33f6a",
+    "#11c638",
+    "#8dd593",
+    "#c6dec7",
+    "#ead3c6",
+    "#f0b98d",
+    "#ef9708",
+    "#0fcfc0",
+    "#9cded6",
+    "#d5eae7",
+    "#f3e1eb",
+    "#f6c4e1",
+    "#f79cd4",
+    # these last ones were added:
+    "#7f7f7f",
+    "#c7c7c7",
+    "#1CE6FF",
+    "#336600",
+]
+
+default_28 = zeileis_28
+
+# from https://godsnotwheregodsnot.blogspot.com/2012/09/color-distribution-methodology.html
+godsnot_102 = [
+    # "#000000",  # remove the black, as often, we have black colored annotation
+    "#FFFF00",
+    "#1CE6FF",
+    "#FF34FF",
+    "#FF4A46",
+    "#008941",
+    "#006FA6",
+    "#A30059",
+    "#FFDBE5",
+    "#7A4900",
+    "#0000A6",
+    "#63FFAC",
+    "#B79762",
+    "#004D43",
+    "#8FB0FF",
+    "#997D87",
+    "#5A0007",
+    "#809693",
+    "#6A3A4C",
+    "#1B4400",
+    "#4FC601",
+    "#3B5DFF",
+    "#4A3B53",
+    "#FF2F80",
+    "#61615A",
+    "#BA0900",
+    "#6B7900",
+    "#00C2A0",
+    "#FFAA92",
+    "#FF90C9",
+    "#B903AA",
+    "#D16100",
+    "#DDEFFF",
+    "#000035",
+    "#7B4F4B",
+    "#A1C299",
+    "#300018",
+    "#0AA6D8",
+    "#013349",
+    "#00846F",
+    "#372101",
+    "#FFB500",
+    "#C2FFED",
+    "#A079BF",
+    "#CC0744",
+    "#C0B9B2",
+    "#C2FF99",
+    "#001E09",
+    "#00489C",
+    "#6F0062",
+    "#0CBD66",
+    "#EEC3FF",
+    "#456D75",
+    "#B77B68",
+    "#7A87A1",
+    "#788D66",
+    "#885578",
+    "#FAD09F",
+    "#FF8A9A",
+    "#D157A0",
+    "#BEC459",
+    "#456648",
+    "#0086ED",
+    "#886F4C",
+    "#34362D",
+    "#B4A8BD",
+    "#00A6AA",
+    "#452C2C",
+    "#636375",
+    "#A3C8C9",
+    "#FF913F",
+    "#938A81",
+    "#575329",
+    "#00FECF",
+    "#B05B6F",
+    "#8CD0FF",
+    "#3B9700",
+    "#04F757",
+    "#C8A1A1",
+    "#1E6E00",
+    "#7900D7",
+    "#A77500",
+    "#6367A9",
+    "#A05837",
+    "#6B002C",
+    "#772600",
+    "#D790FF",
+    "#9B9700",
+    "#549E79",
+    "#FFF69F",
+    "#201625",
+    "#72418F",
+    "#BC23FF",
+    "#99ADC0",
+    "#3A2465",
+    "#922329",
+    "#5B4534",
+    "#FDE8DC",
+    "#404E55",
+    "#0089A3",
+    "#CB7E98",
+    "#A4E804",
+    "#324E72",
+]
+
+default_102 = godsnot_102
+
+
+def _plot_color_cycle(clists: Mapping[str, Sequence[str]]):
+    import matplotlib.pyplot as plt
+    import numpy as np
+    from matplotlib.colors import BoundaryNorm, ListedColormap
+
+    fig, axes = plt.subplots(nrows=len(clists))  # type: plt.Figure, plt.Axes
+    fig.subplots_adjust(top=0.95, bottom=0.01, left=0.3, right=0.99)
+    axes[0].set_title("Color Maps/Cycles", fontsize=14)
+
+    for ax, (name, clist) in zip(axes, clists.items()):
+        n = len(clist)
+        ax.imshow(
+            np.arange(n)[None, :].repeat(2, 0),
+            aspect="auto",
+            cmap=ListedColormap(clist),
+            norm=BoundaryNorm(np.arange(n + 1) - 0.5, n),
+        )
+        pos = list(ax.get_position().bounds)
+        x_text = pos[0] - 0.01
+        y_text = pos[1] + pos[3] / 2.0
+        fig.text(x_text, y_text, name, va="center", ha="right", fontsize=10)
+
+    # Turn off all ticks & spines
+    for ax in axes:
+        ax.set_axis_off()
+    fig.show()
+
+
+if __name__ == "__main__":
+    _plot_color_cycle(
+        {name: colors for name, colors in globals().items() if isinstance(colors, list)}
+    )