EasyPlotLib 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/__init__.py +26 -0
  2. easyplotlib-0.2.0/EasyPlotLib/export.py +58 -0
  3. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/figsizes_set.py +2 -1
  4. easyplotlib-0.2.0/EasyPlotLib/helpers.py +53 -0
  5. easyplotlib-0.2.0/EasyPlotLib/palettes.py +178 -0
  6. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/styles/nature.mplstyle +13 -0
  7. easyplotlib-0.2.0/EasyPlotLib.egg-info/PKG-INFO +135 -0
  8. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib.egg-info/SOURCES.txt +3 -0
  9. easyplotlib-0.2.0/PKG-INFO +135 -0
  10. easyplotlib-0.2.0/README.md +115 -0
  11. easyplotlib-0.1.0/EasyPlotLib.egg-info/PKG-INFO +0 -14
  12. easyplotlib-0.1.0/PKG-INFO +0 -14
  13. easyplotlib-0.1.0/README.md +0 -2
  14. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/cartopy_helper.py +0 -0
  15. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreadventor-bold.ttf +0 -0
  16. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreadventor-bolditalic.ttf +0 -0
  17. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreadventor-italic.ttf +0 -0
  18. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreadventor-regular.ttf +0 -0
  19. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyrechorus-mediumitalic.ttf +0 -0
  20. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyrecursor-bold.ttf +0 -0
  21. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyrecursor-bolditalic.ttf +0 -0
  22. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyrecursor-italic.ttf +0 -0
  23. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyrecursor-regular.ttf +0 -0
  24. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreheros-bold.ttf +0 -0
  25. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreheros-bolditalic.ttf +0 -0
  26. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreheros-italic.ttf +0 -0
  27. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreheros-regular.ttf +0 -0
  28. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreschola-bold.ttf +0 -0
  29. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreschola-bolditalic.ttf +0 -0
  30. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreschola-italic.ttf +0 -0
  31. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib/fonts/texgyreschola-regular.ttf +0 -0
  32. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib.egg-info/dependency_links.txt +0 -0
  33. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/EasyPlotLib.egg-info/top_level.txt +0 -0
  34. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/setup.cfg +0 -0
  35. {easyplotlib-0.1.0 → easyplotlib-0.2.0}/setup.py +0 -0
@@ -7,7 +7,33 @@ import matplotlib.pyplot as plt
7
7
  import EasyPlotLib
8
8
 
9
9
  from .cartopy_helper import cartopy_plot_tickmarks
10
+ from .export import save_pub
10
11
  from .figsizes_set import figsizes, subplot_labels
12
+ from .helpers import journal_style
13
+ from .palettes import (
14
+ COLORMAPS,
15
+ PALETTES,
16
+ SEMANTIC,
17
+ alpha_ramp,
18
+ get_palette,
19
+ set_palette,
20
+ shades,
21
+ )
22
+
23
+ __all__ = [
24
+ "cartopy_plot_tickmarks",
25
+ "figsizes",
26
+ "subplot_labels",
27
+ "journal_style",
28
+ "save_pub",
29
+ "PALETTES",
30
+ "SEMANTIC",
31
+ "COLORMAPS",
32
+ "get_palette",
33
+ "set_palette",
34
+ "alpha_ramp",
35
+ "shades",
36
+ ]
11
37
 
12
38
  # register the bundled stylesheets in the matplotlib style library
13
39
  EasyPlotLib_path = EasyPlotLib.__path__[0]
@@ -0,0 +1,58 @@
1
+ """Publication-quality figure export.
2
+
3
+ Saves a figure to several formats at once with settings that keep text
4
+ **editable** in Illustrator/Inkscape (``pdf.fonttype = 42``, ``svg.fonttype =
5
+ none`` — configured in the bundled ``nature`` style) and rasters at journal DPI.
6
+ """
7
+
8
+ import os
9
+ from typing import Iterable
10
+
11
+ import matplotlib.figure
12
+
13
+
14
+ def save_pub(
15
+ fig: matplotlib.figure.Figure,
16
+ filename: str,
17
+ formats: Iterable[str] = ("pdf", "png"),
18
+ dpi: int = 600,
19
+ transparent: bool = False,
20
+ bbox_inches: str = "tight",
21
+ pad_inches: float = 0.02,
22
+ **savefig_kwargs,
23
+ ) -> list:
24
+ """Save ``fig`` to one file per format and return the written paths.
25
+
26
+ Parameters
27
+ ----------
28
+ filename:
29
+ Path *without* extension, e.g. ``"figures/fig1"``. Parent directories
30
+ are created if needed.
31
+ formats:
32
+ Any matplotlib-supported extensions. Vector formats (``pdf``, ``svg``,
33
+ ``eps``) are preferred for line art; ``tiff``/``png`` at ``dpi`` for
34
+ raster submission. Most journals want one vector + one high-DPI raster.
35
+ dpi:
36
+ Resolution for raster formats. 600 dpi suits line art; use 300 for
37
+ photographic/heatmap content if file size matters.
38
+ """
39
+ if isinstance(formats, str): # a bare "png" must not iterate into 'p','n','g'
40
+ formats = (formats,)
41
+
42
+ directory = os.path.dirname(filename)
43
+ if directory:
44
+ os.makedirs(directory, exist_ok=True)
45
+
46
+ written = []
47
+ for fmt in formats:
48
+ path = f"{filename}.{fmt.lstrip('.')}"
49
+ fig.savefig(
50
+ path,
51
+ dpi=dpi,
52
+ transparent=transparent,
53
+ bbox_inches=bbox_inches,
54
+ pad_inches=pad_inches,
55
+ **savefig_kwargs,
56
+ )
57
+ written.append(path)
58
+ return written
@@ -40,11 +40,12 @@ def figsizes(
40
40
  autolayout=False,
41
41
  tight_layout="tight",
42
42
  pad_inches=_PAD_INCHES,
43
+ gold_ratio=_GOLDEN_RATIO,
43
44
  ratio=1,
44
45
  ) -> dict:
45
46
  # set defaul inverted_aspect if nrows
46
47
  if nrows and ncols:
47
- inverted_aspect_ratio = _GOLDEN_RATIO * nrows / ncols
48
+ inverted_aspect_ratio = gold_ratio * nrows / ncols
48
49
  width = _JOURNAL_SIZES[journal_key]
49
50
  if isinstance(width, tuple): # handle case where width is a tuple
50
51
  width = width[0]
@@ -0,0 +1,53 @@
1
+ """High-level convenience for setting up a journal-ready figure context."""
2
+
3
+ from typing import Optional
4
+
5
+ import matplotlib.pyplot as plt
6
+
7
+ from .figsizes_set import figsizes
8
+ from .palettes import DEFAULT_PALETTE, set_palette
9
+
10
+
11
+ def journal_style(
12
+ journal_key: str = "nat1",
13
+ *,
14
+ palette: str = DEFAULT_PALETTE,
15
+ base_style: str = "nature",
16
+ nrows: Optional[int] = None,
17
+ ncols: Optional[int] = None,
18
+ apply: bool = True,
19
+ **figsize_kwargs,
20
+ ) -> dict:
21
+ """Apply a complete publication style in one call.
22
+
23
+ Combines the bundled ``base_style`` stylesheet, a journal column-width
24
+ :func:`~EasyPlotLib.figsizes` figure size, and a qualitative
25
+ :func:`~EasyPlotLib.set_palette` colour cycle.
26
+
27
+ Parameters
28
+ ----------
29
+ journal_key:
30
+ A key from ``figsizes`` (e.g. ``"nat1"``/``"nat2"`` single/double
31
+ column for Nature, ``"science"`` keys ``"aaas1"``/``"aaas2"``, etc.).
32
+ palette:
33
+ Qualitative palette name (see :data:`EasyPlotLib.PALETTES`).
34
+ base_style:
35
+ A registered matplotlib style; ``"nature"`` is bundled.
36
+ nrows, ncols:
37
+ Passed to ``figsizes`` to auto-pick a sensible aspect ratio for a grid.
38
+ apply:
39
+ When ``True`` (default) mutate the global rc state. Set ``False`` to
40
+ only compute and return the figsize dict.
41
+
42
+ Returns
43
+ -------
44
+ dict
45
+ The figure-size rcParams dict (the return value of ``figsizes``), handy
46
+ to splice into ``plt.rcParams.update`` or ``plt.style.context``.
47
+ """
48
+ fs = figsizes(journal_key, nrows=nrows, ncols=ncols, **figsize_kwargs)
49
+ if apply:
50
+ plt.style.use(base_style)
51
+ plt.rcParams.update(fs)
52
+ set_palette(palette)
53
+ return fs
@@ -0,0 +1,178 @@
1
+ """Curated, journal-friendly qualitative color palettes.
2
+
3
+ The palettes are low-to-medium saturation sets that read well in print and are
4
+ colour-vision-deficiency aware. The names follow the well-known ``ggsci``
5
+ collections so they are familiar to anyone coming from R.
6
+
7
+ Usage
8
+ -----
9
+ >>> import EasyPlotLib as epl
10
+ >>> epl.set_palette("nature") # set the global color cycle
11
+ >>> colors = epl.get_palette("lancet") # grab the raw hex list
12
+ """
13
+
14
+ from typing import List, Optional
15
+
16
+ import matplotlib.colors as mcolors
17
+ import matplotlib.pyplot as plt
18
+ from cycler import cycler
19
+ from matplotlib.axes import Axes
20
+
21
+ # Qualitative palettes. Hex values mirror the canonical ggsci collections,
22
+ # which are widely used in Nature/Science/Cell-family figures.
23
+ PALETTES = {
24
+ # Nature Publishing Group
25
+ "nature": [
26
+ "#E64B35", "#4DBBD5", "#00A087", "#3C5488", "#F39B7F",
27
+ "#8491B4", "#91D1C2", "#DC0000", "#7E6148", "#B09C85",
28
+ ],
29
+ # Science / AAAS
30
+ "science": [
31
+ "#3B4992", "#EE0000", "#008B45", "#631879", "#008280",
32
+ "#BB0021", "#5F559B", "#A20056", "#808180", "#1B1919",
33
+ ],
34
+ # New England Journal of Medicine
35
+ "nejm": [
36
+ "#BC3C29", "#0072B5", "#E18727", "#20854E", "#7876B1",
37
+ "#6F99AD", "#FFDC91", "#EE4C97",
38
+ ],
39
+ # The Lancet
40
+ "lancet": [
41
+ "#00468B", "#ED0000", "#42B540", "#0099B4", "#925E9F",
42
+ "#FDAF91", "#AD002A", "#ADB6B6", "#1B1919",
43
+ ],
44
+ # JAMA
45
+ "jama": [
46
+ "#374E55", "#DF8F44", "#00A1D5", "#B24745", "#79AF97",
47
+ "#6A6599", "#80796B",
48
+ ],
49
+ # Low-saturation "muted" set, close to Nature Machine Intelligence aesthetics.
50
+ "muted": [
51
+ "#4C72B0", "#DD8452", "#55A868", "#C44E52", "#8172B3",
52
+ "#937860", "#DA8BC3", "#8C8C8C", "#CCB974", "#64B5CD",
53
+ ],
54
+ # Semantic order: blue=proposed/hero, green=gain, red=baseline/drop,
55
+ # teal/violet=extra signal, grey=neutral. See SEMANTIC for role lookup.
56
+ "semantic": [
57
+ "#0F4D92", "#8BCF8B", "#B64342", "#42949E", "#9A4D8E", "#CFCECE",
58
+ ],
59
+ # Nature-Machine-Intelligence pastel family: cool baselines + warm hero.
60
+ "nmi": [
61
+ "#484878", "#7884B4", "#B4C0E4", "#F0C0CC", "#E4CCD8", "#CFCECE",
62
+ ],
63
+ # Many-method comparison (e.g. a bar chart of 8-10 baselines vs. yours):
64
+ # soft low-saturation baselines, related methods share a hue family with
65
+ # graduated lightness, and the proposed method gets the one saturated hero.
66
+ # Put your method LAST so #3775BA lands on it.
67
+ "comparison": [
68
+ "#CFCECE", "#F4EEAC", "#FBDFE2", "#D9B9D4", "#DAA87C",
69
+ "#DDF3DE", "#AADCA9", "#8BCF8B", "#92E3F9", "#3775BA",
70
+ ],
71
+ # Imaging / microscopy: a couple of fluorescent accents meant to sit on a
72
+ # BLACK background, plus a grey context channel. Not for white-background plots.
73
+ "imaging": ["#22D7E6", "#FF2AD4", "#B8B8B8"],
74
+ # The original SciencePlots-style bright cycle (kept for backwards compat).
75
+ "bright": [
76
+ "#0C5DA5", "#00B945", "#FF9500", "#FF2C00", "#845B97",
77
+ "#474747", "#9e9e9e",
78
+ ],
79
+ }
80
+
81
+ # Role-based ("semantic") colours: assign by meaning, never remap a method to a
82
+ # different hue family across panels. Reduce saturation before adding categories.
83
+ SEMANTIC = {
84
+ "blue_main": "#0F4D92", # proposed / hero method
85
+ "blue_secondary": "#3775BA",
86
+ "green_light": "#DDF3DE",
87
+ "green_mid": "#AADCA9",
88
+ "green_strong": "#8BCF8B", # gain / improvement / "delta up"
89
+ "red_light": "#F6CFCB",
90
+ "red_mid": "#E9A6A1",
91
+ "red_strong": "#B64342", # baseline / drop / "delta down"
92
+ "neutral_light": "#CFCECE",
93
+ "neutral_mid": "#767676",
94
+ "neutral_dark": "#4D4D4D",
95
+ "neutral_black": "#272727",
96
+ "accent_gold": "#FFD700",
97
+ "accent_teal": "#42949E",
98
+ "accent_violet": "#9A4D8E",
99
+ "accent_magenta": "#EA84DD",
100
+ "delta_up": "#2E9E44",
101
+ "delta_down": "#E53935",
102
+ }
103
+
104
+ # Recommended perceptually-uniform colormaps for continuous data (heatmaps,
105
+ # images, density). Pass these names to ``cmap=`` in imshow/pcolormesh/etc.
106
+ COLORMAPS = {
107
+ "sequential": "viridis", # single-direction magnitude; also "mako", "cividis"
108
+ "sequential_warm": "magma",
109
+ "diverging": "RdBu_r", # signed values around a midpoint; also "coolwarm"
110
+ "grayscale": "Greys", # print-safe context layers
111
+ }
112
+
113
+ DEFAULT_PALETTE = "nature"
114
+
115
+
116
+ def get_palette(name: str = DEFAULT_PALETTE, n: Optional[int] = None) -> List[str]:
117
+ """Return the list of hex colors for ``name``.
118
+
119
+ If ``n`` is given, the palette is truncated (or cycled) to that length.
120
+ """
121
+ if name not in PALETTES:
122
+ raise ValueError(
123
+ f"Unknown palette {name!r}. Available: {', '.join(sorted(PALETTES))}"
124
+ )
125
+ colors = PALETTES[name]
126
+ if n is None:
127
+ return list(colors)
128
+ return [colors[i % len(colors)] for i in range(n)]
129
+
130
+
131
+ def alpha_ramp(color: str, n: int, lo: float = 0.2, hi: float = 1.0) -> List[tuple]:
132
+ """One hue at ``n`` graduated opacities — the standard *ablation* encoding.
133
+
134
+ Use a single color and let opacity carry the ordering (e.g. progressively
135
+ more complete model variants), rather than introducing more hues. Returns a
136
+ list of RGBA tuples ready to pass to ``color=`` in bar/line calls.
137
+
138
+ >>> alpha_ramp(epl.SEMANTIC["blue_main"], 3) # light -> solid
139
+ """
140
+ r, g, b = mcolors.to_rgb(color)
141
+ if n <= 1:
142
+ return [(r, g, b, hi)]
143
+ return [(r, g, b, lo + (hi - lo) * i / (n - 1)) for i in range(n)]
144
+
145
+
146
+ def shades(color: str, n: int, light: float = 0.82) -> List[str]:
147
+ """``n`` shades of one hue from light to the base color.
148
+
149
+ Mirrors the "related methods share a hue family with graduated lightness"
150
+ rule (e.g. a baseline trio dark/mid/soft). The lightest shade is ``color``
151
+ mixed ``light`` of the way toward white; the last shade is ``color`` itself.
152
+ Returns hex strings.
153
+ """
154
+ base = mcolors.to_rgb(color)
155
+ if n <= 1:
156
+ return [mcolors.to_hex(base)]
157
+ out = []
158
+ for i in range(n):
159
+ t = light * (1 - i / (n - 1)) # light at i=0 -> 0 at i=n-1
160
+ mix = (base[0] * (1 - t) + t, base[1] * (1 - t) + t, base[2] * (1 - t) + t)
161
+ out.append(mcolors.to_hex(mix))
162
+ return out
163
+
164
+
165
+ def set_palette(name: str = DEFAULT_PALETTE, ax: Optional[Axes] = None) -> List[str]:
166
+ """Set the qualitative color cycle to ``name``.
167
+
168
+ With no ``ax`` the global :data:`matplotlib.rcParams` cycle is updated so it
169
+ applies to every subsequent figure. Pass an ``ax`` to scope it to a single
170
+ Axes. Returns the colour list that was applied.
171
+ """
172
+ colors = get_palette(name)
173
+ prop_cycle = cycler("color", colors)
174
+ if ax is None:
175
+ plt.rcParams["axes.prop_cycle"] = prop_cycle
176
+ else:
177
+ ax.set_prop_cycle(prop_cycle)
178
+ return colors
@@ -30,6 +30,10 @@ lines.linewidth : 1.
30
30
  lines.markersize: 3
31
31
 
32
32
 
33
+ # Open frame: drop the top/right spines (Nature default)
34
+ axes.spines.top : False
35
+ axes.spines.right : False
36
+
33
37
  # Remove legend frame
34
38
  legend.frameon : False
35
39
 
@@ -37,6 +41,15 @@ legend.frameon : False
37
41
  savefig.bbox : tight
38
42
  savefig.pad_inches : 0.05
39
43
 
44
+ # Resolution: crisp on-screen preview, journal-grade rasters
45
+ figure.dpi : 200
46
+ savefig.dpi : 600
47
+
48
+ # Keep text editable in vector exports (Illustrator/Inkscape friendly)
49
+ pdf.fonttype : 42
50
+ ps.fonttype : 42
51
+ svg.fonttype : none
52
+
40
53
  # Font sizes
41
54
  axes.labelsize: 7
42
55
  xtick.labelsize: 7
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: EasyPlotLib
3
+ Version: 0.2.0
4
+ Summary: A simple plotting library
5
+ Home-page: https://github.com/yourusername/EasyPlotLib
6
+ Author: HanYuyang
7
+ Author-email: 17766095120@163.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.6
11
+ Description-Content-Type: text/markdown
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: home-page
18
+ Dynamic: requires-python
19
+ Dynamic: summary
20
+
21
+ # EasyPlotLib
22
+
23
+ Matplotlib styles and helpers for publication-quality SCI-journal figures
24
+ (Nature / Science / Cell / NEJM / Lancet / PNAS / AGU / AMS).
25
+
26
+ <p align="center">
27
+ <img src="examples/gallery/01_bar_comparison.png" height="150">
28
+ <img src="examples/gallery/03_line_trend.png" height="150">
29
+ <img src="examples/gallery/07_distributions.png" height="150">
30
+ </p>
31
+ <p align="center"><sub>Built with the bundled <code>nature</code> style — see the full <a href="#chart-type-gallery">gallery</a>.</sub></p>
32
+
33
+ ## Install
34
+
35
+ ```
36
+ pip install EasyPlotLib
37
+ ```
38
+
39
+ ## Quick start
40
+
41
+ ```python
42
+ import EasyPlotLib as epl
43
+ import matplotlib.pyplot as plt
44
+ import numpy as np
45
+
46
+ # Style + journal column width + color palette in one call.
47
+ epl.journal_style("nat1", palette="nature", nrows=1, ncols=2)
48
+
49
+ fig, axs = plt.subplots(1, 2)
50
+ x = np.linspace(0, 2 * np.pi, 200)
51
+ for n, ax in enumerate(axs):
52
+ for k in range(3):
53
+ ax.plot(x, np.sin(x + k), label=f"series {k}")
54
+ ax.set_xlabel("x")
55
+ ax.set_ylabel("amplitude")
56
+ ax.annotate(**epl.subplot_labels(n, "a")) # bold panel labels a, b …
57
+
58
+ # Editable vector (PDF) + 600-dpi raster.
59
+ epl.save_pub(fig, "figures/fig1", formats=("pdf", "png"))
60
+ ```
61
+
62
+ ## API
63
+
64
+ | Function | Description |
65
+ |----------|-------------|
66
+ | `journal_style(key, palette=, base_style=, nrows=, ncols=, apply=)` | Apply style + size + palette in one call. Returns the figsize dict. |
67
+ | `figsizes(key, ...)` | rcParams dict with a journal column figure size. Keys: `nat1/2`, `aaas1/2`, `pnas1..3`, `agu1..4`, `ams1..4`. |
68
+ | `subplot_labels(n, style)` | Args for `ax.annotate(**...)`. Styles: `a`, `A`, `(a)`, `a)`, `a.` |
69
+ | `set_palette(name, ax=None)` / `get_palette(name, n=)` | Set the color cycle / return raw hex list. |
70
+ | `PALETTES` | Qualitative palettes: `nature`, `science`, `nejm`, `lancet`, `jama`, `muted`, `semantic`, `nmi`, `comparison`, `imaging`, `bright`. |
71
+ | `SEMANTIC` | Role-based colors (`blue_main`=hero, `green_strong`=gain, `red_strong`=drop, `delta_up/down`, neutrals, accents). |
72
+ | `shades(color, n)` | `n` shades of one hue, light→base — related methods (e.g. a baseline trio, stacked-area family). |
73
+ | `alpha_ramp(color, n)` | One hue at graduated opacity — the standard ablation encoding. |
74
+ | `COLORMAPS` | Recommended continuous colormaps for heatmaps/images: `sequential`, `sequential_warm`, `diverging`, `grayscale`. |
75
+ | `save_pub(fig, path, formats=, dpi=)` | Save to multiple formats with editable vector text. |
76
+ | `cartopy_plot_tickmarks(ax, gl)` | Clean lon/lat tick labels for cartopy maps. |
77
+
78
+ ## Color scheme guidance
79
+ Every recurring nature-style color pattern is abstracted into one small, shared
80
+ API so a whole figure stays consistent (the `examples/gallery.py` panels all
81
+ draw from it):
82
+
83
+ - **One restrained palette per figure.** Use a unified family across panels
84
+ rather than maximizing hue variety; reduce saturation before adding categories.
85
+ - **Assign color by meaning, not by index.** `SEMANTIC` reserves `blue_main`
86
+ for the proposed/hero method and green/red for gains/drops. Never remap the
87
+ same method to a different hue in another panel.
88
+ - **Many-method comparison** → `get_palette("comparison")`: soft pastel
89
+ baselines with related methods sharing a hue family, and one saturated hero
90
+ (put your method last).
91
+ - **Related methods / one family** → `shades(color, n)`: graduated lightness of
92
+ a single hue (baseline trios, stacked-area bands).
93
+ - **Ablations** → `alpha_ramp(color, n)`: one hue, opacity carries the ordering.
94
+ - **Continuous data** (heatmaps, density, images) → a perceptual colormap from
95
+ `COLORMAPS` — sequential for magnitude, diverging for signed values.
96
+ - **Microscopy** → `imaging` accents (cyan/magenta) on a black background.
97
+
98
+ ## Chart-type gallery
99
+ `examples/gallery.py` renders one publication-styled panel per common archetype.
100
+ Every panel sources its colors from the abstracted API above, so a method keeps
101
+ its hue across the whole figure (blue = hero, grey = baseline):
102
+
103
+ ```
104
+ python examples/gallery.py # writes PNGs to examples/gallery/
105
+ ```
106
+
107
+ <table>
108
+ <tr>
109
+ <td align="center"><img src="examples/gallery/01_bar_comparison.png" width="260"><br><sub>Method comparison · <code>get_palette("comparison")</code></sub></td>
110
+ <td align="center"><img src="examples/gallery/02_bar_ablation.png" width="260"><br><sub>Ablation · <code>alpha_ramp()</code></sub></td>
111
+ <td align="center"><img src="examples/gallery/03_line_trend.png" width="260"><br><sub>Trend + CI · <code>SEMANTIC</code></sub></td>
112
+ </tr>
113
+ <tr>
114
+ <td align="center"><img src="examples/gallery/04_heatmap.png" width="260"><br><sub>Heatmap · <code>COLORMAPS["sequential"]</code></sub></td>
115
+ <td align="center"><img src="examples/gallery/05_scatter_bubble.png" width="260"><br><sub>Scatter / bubble · <code>SEMANTIC</code></sub></td>
116
+ <td align="center"><img src="examples/gallery/06_radar.png" width="260"><br><sub>Radar / polar · <code>SEMANTIC</code></sub></td>
117
+ </tr>
118
+ <tr>
119
+ <td align="center"><img src="examples/gallery/07_distributions.png" width="260"><br><sub>Violin + box · <code>shades()</code></sub></td>
120
+ <td align="center"><img src="examples/gallery/08_forest.png" width="260"><br><sub>Forest / interval · <code>SEMANTIC</code></sub></td>
121
+ <td align="center"><img src="examples/gallery/09_stacked_area.png" width="260"><br><sub>Stacked area · <code>shades()</code></sub></td>
122
+ </tr>
123
+ </table>
124
+
125
+ ## Style notes
126
+
127
+ The bundled `nature` style uses 7 pt sans (TeX Gyre Heros / Helvetica), an open
128
+ frame (no top/right spines), and export settings that keep text **editable** in
129
+ Illustrator/Inkscape (`pdf.fonttype=42`, `svg.fonttype=none`) at 600 dpi.
130
+
131
+ ## Claude Code skill
132
+
133
+ A personal `sci-figure` skill (`~/.claude/skills/sci-figure/`) walks Claude
134
+ through the publication workflow and is auto-invoked on plotting tasks in any
135
+ project where EasyPlotLib is installed.
@@ -2,7 +2,10 @@ README.md
2
2
  setup.py
3
3
  EasyPlotLib/__init__.py
4
4
  EasyPlotLib/cartopy_helper.py
5
+ EasyPlotLib/export.py
5
6
  EasyPlotLib/figsizes_set.py
7
+ EasyPlotLib/helpers.py
8
+ EasyPlotLib/palettes.py
6
9
  EasyPlotLib.egg-info/PKG-INFO
7
10
  EasyPlotLib.egg-info/SOURCES.txt
8
11
  EasyPlotLib.egg-info/dependency_links.txt
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: EasyPlotLib
3
+ Version: 0.2.0
4
+ Summary: A simple plotting library
5
+ Home-page: https://github.com/yourusername/EasyPlotLib
6
+ Author: HanYuyang
7
+ Author-email: 17766095120@163.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.6
11
+ Description-Content-Type: text/markdown
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: home-page
18
+ Dynamic: requires-python
19
+ Dynamic: summary
20
+
21
+ # EasyPlotLib
22
+
23
+ Matplotlib styles and helpers for publication-quality SCI-journal figures
24
+ (Nature / Science / Cell / NEJM / Lancet / PNAS / AGU / AMS).
25
+
26
+ <p align="center">
27
+ <img src="examples/gallery/01_bar_comparison.png" height="150">
28
+ <img src="examples/gallery/03_line_trend.png" height="150">
29
+ <img src="examples/gallery/07_distributions.png" height="150">
30
+ </p>
31
+ <p align="center"><sub>Built with the bundled <code>nature</code> style — see the full <a href="#chart-type-gallery">gallery</a>.</sub></p>
32
+
33
+ ## Install
34
+
35
+ ```
36
+ pip install EasyPlotLib
37
+ ```
38
+
39
+ ## Quick start
40
+
41
+ ```python
42
+ import EasyPlotLib as epl
43
+ import matplotlib.pyplot as plt
44
+ import numpy as np
45
+
46
+ # Style + journal column width + color palette in one call.
47
+ epl.journal_style("nat1", palette="nature", nrows=1, ncols=2)
48
+
49
+ fig, axs = plt.subplots(1, 2)
50
+ x = np.linspace(0, 2 * np.pi, 200)
51
+ for n, ax in enumerate(axs):
52
+ for k in range(3):
53
+ ax.plot(x, np.sin(x + k), label=f"series {k}")
54
+ ax.set_xlabel("x")
55
+ ax.set_ylabel("amplitude")
56
+ ax.annotate(**epl.subplot_labels(n, "a")) # bold panel labels a, b …
57
+
58
+ # Editable vector (PDF) + 600-dpi raster.
59
+ epl.save_pub(fig, "figures/fig1", formats=("pdf", "png"))
60
+ ```
61
+
62
+ ## API
63
+
64
+ | Function | Description |
65
+ |----------|-------------|
66
+ | `journal_style(key, palette=, base_style=, nrows=, ncols=, apply=)` | Apply style + size + palette in one call. Returns the figsize dict. |
67
+ | `figsizes(key, ...)` | rcParams dict with a journal column figure size. Keys: `nat1/2`, `aaas1/2`, `pnas1..3`, `agu1..4`, `ams1..4`. |
68
+ | `subplot_labels(n, style)` | Args for `ax.annotate(**...)`. Styles: `a`, `A`, `(a)`, `a)`, `a.` |
69
+ | `set_palette(name, ax=None)` / `get_palette(name, n=)` | Set the color cycle / return raw hex list. |
70
+ | `PALETTES` | Qualitative palettes: `nature`, `science`, `nejm`, `lancet`, `jama`, `muted`, `semantic`, `nmi`, `comparison`, `imaging`, `bright`. |
71
+ | `SEMANTIC` | Role-based colors (`blue_main`=hero, `green_strong`=gain, `red_strong`=drop, `delta_up/down`, neutrals, accents). |
72
+ | `shades(color, n)` | `n` shades of one hue, light→base — related methods (e.g. a baseline trio, stacked-area family). |
73
+ | `alpha_ramp(color, n)` | One hue at graduated opacity — the standard ablation encoding. |
74
+ | `COLORMAPS` | Recommended continuous colormaps for heatmaps/images: `sequential`, `sequential_warm`, `diverging`, `grayscale`. |
75
+ | `save_pub(fig, path, formats=, dpi=)` | Save to multiple formats with editable vector text. |
76
+ | `cartopy_plot_tickmarks(ax, gl)` | Clean lon/lat tick labels for cartopy maps. |
77
+
78
+ ## Color scheme guidance
79
+ Every recurring nature-style color pattern is abstracted into one small, shared
80
+ API so a whole figure stays consistent (the `examples/gallery.py` panels all
81
+ draw from it):
82
+
83
+ - **One restrained palette per figure.** Use a unified family across panels
84
+ rather than maximizing hue variety; reduce saturation before adding categories.
85
+ - **Assign color by meaning, not by index.** `SEMANTIC` reserves `blue_main`
86
+ for the proposed/hero method and green/red for gains/drops. Never remap the
87
+ same method to a different hue in another panel.
88
+ - **Many-method comparison** → `get_palette("comparison")`: soft pastel
89
+ baselines with related methods sharing a hue family, and one saturated hero
90
+ (put your method last).
91
+ - **Related methods / one family** → `shades(color, n)`: graduated lightness of
92
+ a single hue (baseline trios, stacked-area bands).
93
+ - **Ablations** → `alpha_ramp(color, n)`: one hue, opacity carries the ordering.
94
+ - **Continuous data** (heatmaps, density, images) → a perceptual colormap from
95
+ `COLORMAPS` — sequential for magnitude, diverging for signed values.
96
+ - **Microscopy** → `imaging` accents (cyan/magenta) on a black background.
97
+
98
+ ## Chart-type gallery
99
+ `examples/gallery.py` renders one publication-styled panel per common archetype.
100
+ Every panel sources its colors from the abstracted API above, so a method keeps
101
+ its hue across the whole figure (blue = hero, grey = baseline):
102
+
103
+ ```
104
+ python examples/gallery.py # writes PNGs to examples/gallery/
105
+ ```
106
+
107
+ <table>
108
+ <tr>
109
+ <td align="center"><img src="examples/gallery/01_bar_comparison.png" width="260"><br><sub>Method comparison · <code>get_palette("comparison")</code></sub></td>
110
+ <td align="center"><img src="examples/gallery/02_bar_ablation.png" width="260"><br><sub>Ablation · <code>alpha_ramp()</code></sub></td>
111
+ <td align="center"><img src="examples/gallery/03_line_trend.png" width="260"><br><sub>Trend + CI · <code>SEMANTIC</code></sub></td>
112
+ </tr>
113
+ <tr>
114
+ <td align="center"><img src="examples/gallery/04_heatmap.png" width="260"><br><sub>Heatmap · <code>COLORMAPS["sequential"]</code></sub></td>
115
+ <td align="center"><img src="examples/gallery/05_scatter_bubble.png" width="260"><br><sub>Scatter / bubble · <code>SEMANTIC</code></sub></td>
116
+ <td align="center"><img src="examples/gallery/06_radar.png" width="260"><br><sub>Radar / polar · <code>SEMANTIC</code></sub></td>
117
+ </tr>
118
+ <tr>
119
+ <td align="center"><img src="examples/gallery/07_distributions.png" width="260"><br><sub>Violin + box · <code>shades()</code></sub></td>
120
+ <td align="center"><img src="examples/gallery/08_forest.png" width="260"><br><sub>Forest / interval · <code>SEMANTIC</code></sub></td>
121
+ <td align="center"><img src="examples/gallery/09_stacked_area.png" width="260"><br><sub>Stacked area · <code>shades()</code></sub></td>
122
+ </tr>
123
+ </table>
124
+
125
+ ## Style notes
126
+
127
+ The bundled `nature` style uses 7 pt sans (TeX Gyre Heros / Helvetica), an open
128
+ frame (no top/right spines), and export settings that keep text **editable** in
129
+ Illustrator/Inkscape (`pdf.fonttype=42`, `svg.fonttype=none`) at 600 dpi.
130
+
131
+ ## Claude Code skill
132
+
133
+ A personal `sci-figure` skill (`~/.claude/skills/sci-figure/`) walks Claude
134
+ through the publication workflow and is auto-invoked on plotting tasks in any
135
+ project where EasyPlotLib is installed.
@@ -0,0 +1,115 @@
1
+ # EasyPlotLib
2
+
3
+ Matplotlib styles and helpers for publication-quality SCI-journal figures
4
+ (Nature / Science / Cell / NEJM / Lancet / PNAS / AGU / AMS).
5
+
6
+ <p align="center">
7
+ <img src="examples/gallery/01_bar_comparison.png" height="150">
8
+ <img src="examples/gallery/03_line_trend.png" height="150">
9
+ <img src="examples/gallery/07_distributions.png" height="150">
10
+ </p>
11
+ <p align="center"><sub>Built with the bundled <code>nature</code> style — see the full <a href="#chart-type-gallery">gallery</a>.</sub></p>
12
+
13
+ ## Install
14
+
15
+ ```
16
+ pip install EasyPlotLib
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```python
22
+ import EasyPlotLib as epl
23
+ import matplotlib.pyplot as plt
24
+ import numpy as np
25
+
26
+ # Style + journal column width + color palette in one call.
27
+ epl.journal_style("nat1", palette="nature", nrows=1, ncols=2)
28
+
29
+ fig, axs = plt.subplots(1, 2)
30
+ x = np.linspace(0, 2 * np.pi, 200)
31
+ for n, ax in enumerate(axs):
32
+ for k in range(3):
33
+ ax.plot(x, np.sin(x + k), label=f"series {k}")
34
+ ax.set_xlabel("x")
35
+ ax.set_ylabel("amplitude")
36
+ ax.annotate(**epl.subplot_labels(n, "a")) # bold panel labels a, b …
37
+
38
+ # Editable vector (PDF) + 600-dpi raster.
39
+ epl.save_pub(fig, "figures/fig1", formats=("pdf", "png"))
40
+ ```
41
+
42
+ ## API
43
+
44
+ | Function | Description |
45
+ |----------|-------------|
46
+ | `journal_style(key, palette=, base_style=, nrows=, ncols=, apply=)` | Apply style + size + palette in one call. Returns the figsize dict. |
47
+ | `figsizes(key, ...)` | rcParams dict with a journal column figure size. Keys: `nat1/2`, `aaas1/2`, `pnas1..3`, `agu1..4`, `ams1..4`. |
48
+ | `subplot_labels(n, style)` | Args for `ax.annotate(**...)`. Styles: `a`, `A`, `(a)`, `a)`, `a.` |
49
+ | `set_palette(name, ax=None)` / `get_palette(name, n=)` | Set the color cycle / return raw hex list. |
50
+ | `PALETTES` | Qualitative palettes: `nature`, `science`, `nejm`, `lancet`, `jama`, `muted`, `semantic`, `nmi`, `comparison`, `imaging`, `bright`. |
51
+ | `SEMANTIC` | Role-based colors (`blue_main`=hero, `green_strong`=gain, `red_strong`=drop, `delta_up/down`, neutrals, accents). |
52
+ | `shades(color, n)` | `n` shades of one hue, light→base — related methods (e.g. a baseline trio, stacked-area family). |
53
+ | `alpha_ramp(color, n)` | One hue at graduated opacity — the standard ablation encoding. |
54
+ | `COLORMAPS` | Recommended continuous colormaps for heatmaps/images: `sequential`, `sequential_warm`, `diverging`, `grayscale`. |
55
+ | `save_pub(fig, path, formats=, dpi=)` | Save to multiple formats with editable vector text. |
56
+ | `cartopy_plot_tickmarks(ax, gl)` | Clean lon/lat tick labels for cartopy maps. |
57
+
58
+ ## Color scheme guidance
59
+ Every recurring nature-style color pattern is abstracted into one small, shared
60
+ API so a whole figure stays consistent (the `examples/gallery.py` panels all
61
+ draw from it):
62
+
63
+ - **One restrained palette per figure.** Use a unified family across panels
64
+ rather than maximizing hue variety; reduce saturation before adding categories.
65
+ - **Assign color by meaning, not by index.** `SEMANTIC` reserves `blue_main`
66
+ for the proposed/hero method and green/red for gains/drops. Never remap the
67
+ same method to a different hue in another panel.
68
+ - **Many-method comparison** → `get_palette("comparison")`: soft pastel
69
+ baselines with related methods sharing a hue family, and one saturated hero
70
+ (put your method last).
71
+ - **Related methods / one family** → `shades(color, n)`: graduated lightness of
72
+ a single hue (baseline trios, stacked-area bands).
73
+ - **Ablations** → `alpha_ramp(color, n)`: one hue, opacity carries the ordering.
74
+ - **Continuous data** (heatmaps, density, images) → a perceptual colormap from
75
+ `COLORMAPS` — sequential for magnitude, diverging for signed values.
76
+ - **Microscopy** → `imaging` accents (cyan/magenta) on a black background.
77
+
78
+ ## Chart-type gallery
79
+ `examples/gallery.py` renders one publication-styled panel per common archetype.
80
+ Every panel sources its colors from the abstracted API above, so a method keeps
81
+ its hue across the whole figure (blue = hero, grey = baseline):
82
+
83
+ ```
84
+ python examples/gallery.py # writes PNGs to examples/gallery/
85
+ ```
86
+
87
+ <table>
88
+ <tr>
89
+ <td align="center"><img src="examples/gallery/01_bar_comparison.png" width="260"><br><sub>Method comparison · <code>get_palette("comparison")</code></sub></td>
90
+ <td align="center"><img src="examples/gallery/02_bar_ablation.png" width="260"><br><sub>Ablation · <code>alpha_ramp()</code></sub></td>
91
+ <td align="center"><img src="examples/gallery/03_line_trend.png" width="260"><br><sub>Trend + CI · <code>SEMANTIC</code></sub></td>
92
+ </tr>
93
+ <tr>
94
+ <td align="center"><img src="examples/gallery/04_heatmap.png" width="260"><br><sub>Heatmap · <code>COLORMAPS["sequential"]</code></sub></td>
95
+ <td align="center"><img src="examples/gallery/05_scatter_bubble.png" width="260"><br><sub>Scatter / bubble · <code>SEMANTIC</code></sub></td>
96
+ <td align="center"><img src="examples/gallery/06_radar.png" width="260"><br><sub>Radar / polar · <code>SEMANTIC</code></sub></td>
97
+ </tr>
98
+ <tr>
99
+ <td align="center"><img src="examples/gallery/07_distributions.png" width="260"><br><sub>Violin + box · <code>shades()</code></sub></td>
100
+ <td align="center"><img src="examples/gallery/08_forest.png" width="260"><br><sub>Forest / interval · <code>SEMANTIC</code></sub></td>
101
+ <td align="center"><img src="examples/gallery/09_stacked_area.png" width="260"><br><sub>Stacked area · <code>shades()</code></sub></td>
102
+ </tr>
103
+ </table>
104
+
105
+ ## Style notes
106
+
107
+ The bundled `nature` style uses 7 pt sans (TeX Gyre Heros / Helvetica), an open
108
+ frame (no top/right spines), and export settings that keep text **editable** in
109
+ Illustrator/Inkscape (`pdf.fonttype=42`, `svg.fonttype=none`) at 600 dpi.
110
+
111
+ ## Claude Code skill
112
+
113
+ A personal `sci-figure` skill (`~/.claude/skills/sci-figure/`) walks Claude
114
+ through the publication workflow and is auto-invoked on plotting tasks in any
115
+ project where EasyPlotLib is installed.
@@ -1,14 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: EasyPlotLib
3
- Version: 0.1.0
4
- Summary: A simple plotting library
5
- Home-page: https://github.com/yourusername/EasyPlotLib
6
- Author: HanYuyang
7
- Author-email: 17766095120@163.com
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.6
11
- Description-Content-Type: text/markdown
12
-
13
- # Install
14
- pip install EasyPlotLib
@@ -1,14 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: EasyPlotLib
3
- Version: 0.1.0
4
- Summary: A simple plotting library
5
- Home-page: https://github.com/yourusername/EasyPlotLib
6
- Author: HanYuyang
7
- Author-email: 17766095120@163.com
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.6
11
- Description-Content-Type: text/markdown
12
-
13
- # Install
14
- pip install EasyPlotLib
@@ -1,2 +0,0 @@
1
- # Install
2
- pip install EasyPlotLib
File without changes
File without changes