pub-ready-plots 0.1.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.
@@ -0,0 +1,76 @@
1
+ Metadata-Version: 2.1
2
+ Name: pub-ready-plots
3
+ Version: 0.1.0
4
+ Summary: Easy publication-ready matplotlib plots for ML papers and posters.
5
+ Author-Email: Agustinus Kristiadi <agustinus@kristia.de>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: matplotlib>=3.9.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # Agustinus' _Very_ Opiniated Publication-Ready Plotting Library
12
+
13
+ I love TikZ. I love [tikzplotlib](https://github.com/nschloe/tikzplotlib). I've been an
14
+ advocate for the latter ([proof](https://agustinus.kristia.de/techblog/2022/05/01/plotting/)). However, tikzplotlib is [as good as dead](https://github.com/nschloe/tikzplotlib/commits/main/). I need to move on.
15
+
16
+ > [!IMPORTANT]
17
+ > Here's what I use now for all my publication needs. This library is designed to be
18
+ > _*very*_ opiniated. Beauty is in the eye of the beholder. Also, it is _very_ simple,
19
+ > just a single file and that's it.
20
+
21
+ > [!NOTE]
22
+ > Of course I still use TikZ whenever possible (e.g. Fig. 1 in a paper, diagrams, etc.)
23
+
24
+ ## Installation
25
+
26
+ Still with me? Still want to use this library? Here's how:
27
+
28
+ ```bash
29
+ pip install pub-ready-plots
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```python
35
+ rc_params, fig_width_in, fig_height_in = pub_ready_plots.get_mpl_rcParams(
36
+ width=1, # between 0 and 1
37
+ height=0.1, # between 0 and 1
38
+ layout="icml" # or "iclr", "neurips", "poster-portrait", "poster-landscape"
39
+ )
40
+ plt.rcParams.update(rc_params)
41
+
42
+ fig, axs = plt.subplots(
43
+ nrows,
44
+ ncols,
45
+ constrained_layout=True, # Important!
46
+ )
47
+ fig.set_size_inches(fig_width_in, fig_height_in)
48
+
49
+ # Your plot here!
50
+
51
+ plt.savefig("filename.pdf")
52
+ ```
53
+
54
+ Then in your LaTeX file, include the plot as follows:
55
+
56
+ ```tex
57
+ \includegraphics[width=\linewidth]{filename.pdf}
58
+ ```
59
+
60
+ The argument `width=\linewidth` is important!
61
+
62
+ > [!TIP]
63
+ > That's it!
64
+
65
+ ## Using your own styles
66
+
67
+ Two options:
68
+
69
+ 1. For this repo and modify things as you wish.
70
+ 2. Use this library and update the resulting `rc_params` dict with your styles.
71
+
72
+ ## Other libraries
73
+
74
+ Check out [tueplots](https://github.com/pnkraemer/tueplots) if you want a more complex
75
+ library. My library is designed to achieve what I want in publication-ready papers and
76
+ posters, with as little code as possible (minimalism FTW!).
@@ -0,0 +1,66 @@
1
+ # Agustinus' _Very_ Opiniated Publication-Ready Plotting Library
2
+
3
+ I love TikZ. I love [tikzplotlib](https://github.com/nschloe/tikzplotlib). I've been an
4
+ advocate for the latter ([proof](https://agustinus.kristia.de/techblog/2022/05/01/plotting/)). However, tikzplotlib is [as good as dead](https://github.com/nschloe/tikzplotlib/commits/main/). I need to move on.
5
+
6
+ > [!IMPORTANT]
7
+ > Here's what I use now for all my publication needs. This library is designed to be
8
+ > _*very*_ opiniated. Beauty is in the eye of the beholder. Also, it is _very_ simple,
9
+ > just a single file and that's it.
10
+
11
+ > [!NOTE]
12
+ > Of course I still use TikZ whenever possible (e.g. Fig. 1 in a paper, diagrams, etc.)
13
+
14
+ ## Installation
15
+
16
+ Still with me? Still want to use this library? Here's how:
17
+
18
+ ```bash
19
+ pip install pub-ready-plots
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```python
25
+ rc_params, fig_width_in, fig_height_in = pub_ready_plots.get_mpl_rcParams(
26
+ width=1, # between 0 and 1
27
+ height=0.1, # between 0 and 1
28
+ layout="icml" # or "iclr", "neurips", "poster-portrait", "poster-landscape"
29
+ )
30
+ plt.rcParams.update(rc_params)
31
+
32
+ fig, axs = plt.subplots(
33
+ nrows,
34
+ ncols,
35
+ constrained_layout=True, # Important!
36
+ )
37
+ fig.set_size_inches(fig_width_in, fig_height_in)
38
+
39
+ # Your plot here!
40
+
41
+ plt.savefig("filename.pdf")
42
+ ```
43
+
44
+ Then in your LaTeX file, include the plot as follows:
45
+
46
+ ```tex
47
+ \includegraphics[width=\linewidth]{filename.pdf}
48
+ ```
49
+
50
+ The argument `width=\linewidth` is important!
51
+
52
+ > [!TIP]
53
+ > That's it!
54
+
55
+ ## Using your own styles
56
+
57
+ Two options:
58
+
59
+ 1. For this repo and modify things as you wish.
60
+ 2. Use this library and update the resulting `rc_params` dict with your styles.
61
+
62
+ ## Other libraries
63
+
64
+ Check out [tueplots](https://github.com/pnkraemer/tueplots) if you want a more complex
65
+ library. My library is designed to achieve what I want in publication-ready papers and
66
+ posters, with as little code as possible (minimalism FTW!).
@@ -0,0 +1,29 @@
1
+ [project]
2
+ name = "pub-ready-plots"
3
+ version = "0.1.0"
4
+ description = "Easy publication-ready matplotlib plots for ML papers and posters."
5
+ authors = [
6
+ { name = "Agustinus Kristiadi", email = "agustinus@kristia.de" },
7
+ ]
8
+ dependencies = [
9
+ "matplotlib>=3.9.0",
10
+ ]
11
+ requires-python = ">=3.10"
12
+ readme = "README.md"
13
+
14
+ [project.license]
15
+ text = "MIT"
16
+
17
+ [build-system]
18
+ requires = [
19
+ "pdm-backend",
20
+ ]
21
+ build-backend = "pdm.backend"
22
+
23
+ [tool.pdm]
24
+ distribution = true
25
+
26
+ [tool.pytest.ini_options]
27
+ pythonpath = [
28
+ "src",
29
+ ]
@@ -0,0 +1,3 @@
1
+ from pub_ready_plots.pub_ready_plots import get_mpl_rcParams
2
+
3
+ __all__ = ["get_mpl_rcParams"]
@@ -0,0 +1,167 @@
1
+ from typing import Any
2
+
3
+ import matplotlib as mpl
4
+ import matplotlib.font_manager as font_manager
5
+
6
+ cmfont = font_manager.FontProperties(fname=mpl.get_data_path() + "/fonts/ttf/cmr10.ttf")
7
+ FONT_NAME_CM = cmfont.get_name()
8
+ FONT_NAME_TNR = "Times New Roman"
9
+ FONT_NAME_AVENIR = "Avenir Next Condensed"
10
+
11
+ PAPER_FORMATS = {
12
+ "icml": {
13
+ "text_width": 6.00117,
14
+ "col_width": 3.25063,
15
+ "text_height": 8.50166,
16
+ "font_name": FONT_NAME_TNR,
17
+ "footnote_size": 8,
18
+ "script_size": 7,
19
+ "linewidth": 1.25,
20
+ "tick_size": 1,
21
+ "tick_width": 1,
22
+ },
23
+ "neurips": {
24
+ "text_width": 5.50107,
25
+ "col_width": 5.50107,
26
+ "text_height": 9.00177,
27
+ "font_name": FONT_NAME_TNR,
28
+ "footnote_size": 8,
29
+ "script_size": 7,
30
+ "linewidth": 1.25,
31
+ "tick_size": 1,
32
+ "tick_width": 1,
33
+ },
34
+ "iclr": {
35
+ "text_width": 5.50107,
36
+ "col_width": 5.50107,
37
+ "text_height": 9.00177,
38
+ "font_name": FONT_NAME_TNR,
39
+ "footnote_size": 8,
40
+ "script_size": 7,
41
+ "linewidth": 1.25,
42
+ "tick_size": 1,
43
+ "tick_width": 1,
44
+ },
45
+ "jmlr": {
46
+ "text_width": 6.00117,
47
+ "col_width": 6.00117,
48
+ "text_height": 8.50166,
49
+ "font_name": FONT_NAME_CM,
50
+ "footnote_size": 8,
51
+ "script_size": 7,
52
+ "linewidth": 1.25,
53
+ "tick_size": 1,
54
+ "tick_width": 1,
55
+ },
56
+ "poster-landscape": {
57
+ "text_width": 6.00117,
58
+ "col_width": 6.00117,
59
+ "text_height": 8.50166,
60
+ "font_name": FONT_NAME_AVENIR,
61
+ "footnote_size": 30,
62
+ "script_size": 23,
63
+ "linewidth": 3,
64
+ "tick_size": 4,
65
+ "tick_width": 2,
66
+ },
67
+ "poster-portrait": {
68
+ "text_width": 6.00117,
69
+ "col_width": 6.00117,
70
+ "text_height": 8.50166,
71
+ "font_name": FONT_NAME_AVENIR,
72
+ "footnote_size": 10,
73
+ "script_size": 8,
74
+ "linewidth": 1,
75
+ "tick_size": 1,
76
+ "tick_width": 1,
77
+ },
78
+ }
79
+
80
+
81
+ def get_mpl_rcParams(
82
+ width_frac: float,
83
+ height_frac: float,
84
+ layout: str = "neurips",
85
+ single_col: bool = False,
86
+ ) -> tuple[dict[str, Any], float, float]:
87
+ """Get matplotlib rcParams dict and fig width & height in inches, depending on the
88
+ chosen layout and fractional width and height. Fractional here in the sense that
89
+ The resulting fig width/height in inches is calculated as `width_frac\\linewidth` and
90
+ `height_frac\\textheight` in LaTeX. Usage:
91
+
92
+ ```python
93
+ rc_params, fig_width_in, fig_height_in = pub_ready_plots.get_mpl_rcParams(
94
+ width=fig_width_frac, height=fig_height_frac, layout="icml"
95
+ )
96
+ plt.rcParams.update(rc_params)
97
+
98
+ fig, axs = plt.subplots(
99
+ nrows,
100
+ ncols,
101
+ constrained_layout=True, # Important!
102
+ )
103
+ fig.set_size_inches(fig_width_in, fig_height_in)
104
+
105
+ # Your plot here!
106
+
107
+ plt.savefig("filename.pdf")
108
+ ```
109
+
110
+ Then in your LaTeX file, include the plot as follows:
111
+
112
+ ```tex
113
+ \\includegraphics[width=\\linewidth]{filename.pdf}
114
+ ```
115
+
116
+ The arg. `width=\\linewidth` is important!
117
+
118
+ Args:
119
+ width_frac: Fraction of `\\linewidth` as the figure width. Usually set to 1.
120
+ height_frac: Fraction of `\\textheight` as the figure height. Try 0.175.
121
+ layout: The LaTeX template used. Possible values are "icml", "iclr", "neurips",
122
+ "jmlr", "poster-portrait" (A1, 2-column), and "poster-landscape" (A0, 3-col).
123
+ single_col: Whether the plot is single column in a layout that has two columns
124
+ (e.g. ICML). Not supported for any other layout.
125
+
126
+ Returns:
127
+ rc_params: Matplotlib key-value rc-params. Use it via
128
+ `plt.rcParams.update(rc_params)`. Note that you can always override/add
129
+ key-values to this dict before applying it.
130
+ fig_width_in: figure width in inches.
131
+ fig_height_in: figure height in inches.
132
+ """
133
+ if (width_frac <= 0 or width_frac > 1) or (height_frac <= 0 or height_frac > 1):
134
+ raise ValueError("Both `width_frac` and `height_frac` must be between 0 and 1.")
135
+
136
+ if layout not in PAPER_FORMATS.keys():
137
+ raise ValueError(f"Layout must be in {list(PAPER_FORMATS.keys())}.")
138
+
139
+ if layout not in ["icml"] and single_col:
140
+ raise ValueError("Double-column is only supported for ICML.")
141
+
142
+ format = PAPER_FORMATS[layout]
143
+ is_poster = "poster" in layout
144
+
145
+ rc_params = {
146
+ "text.usetex": False,
147
+ "font.size": format["footnote_size"],
148
+ "font.family": "serif",
149
+ "font.serif": format["font_name"],
150
+ "mathtext.fontset": "stixsans" if is_poster else "cm",
151
+ "lines.linewidth": format["linewidth"],
152
+ "axes.linewidth": 1,
153
+ "axes.titlesize": format["footnote_size"],
154
+ "axes.labelsize": format["script_size"],
155
+ "axes.unicode_minus": False,
156
+ "axes.formatter.use_mathtext": True,
157
+ "legend.fontsize": format["script_size"],
158
+ "xtick.major.size": format["tick_size"],
159
+ "ytick.major.size": format["tick_size"],
160
+ "xtick.major.width": format["tick_width"],
161
+ "ytick.major.width": format["tick_width"],
162
+ }
163
+
164
+ w = width_frac * (format["col_width"] if single_col else format["text_width"])
165
+ h = height_frac * format["text_height"]
166
+
167
+ return rc_params, w, h
File without changes
@@ -0,0 +1,39 @@
1
+ import matplotlib as plt
2
+ import pytest
3
+
4
+ from pub_ready_plots import get_mpl_rcParams
5
+
6
+ LAYOUTS = ["icml", "iclr", "neurips", "jmlr", "poster-portrait", "poster-landscape"]
7
+
8
+
9
+ @pytest.mark.parametrize("layout", LAYOUTS)
10
+ def test_correct_func(layout):
11
+ rc_params, width_in, height_in = get_mpl_rcParams(1, 0.15, layout)
12
+ plt.rcParams.update(rc_params)
13
+
14
+
15
+ def test_incorrect_width():
16
+ with pytest.raises(ValueError):
17
+ _, _, _ = get_mpl_rcParams(12, 0.1, "iclr")
18
+
19
+ with pytest.raises(ValueError):
20
+ _, _, _ = get_mpl_rcParams(0, 0.1, "iclr")
21
+
22
+ with pytest.raises(ValueError):
23
+ _, _, _ = get_mpl_rcParams(-3.2, 0.1, "iclr")
24
+
25
+
26
+ def test_incorrect_height():
27
+ with pytest.raises(ValueError):
28
+ _, _, _ = get_mpl_rcParams(0.15, 12, "iclr")
29
+
30
+ with pytest.raises(ValueError):
31
+ _, _, _ = get_mpl_rcParams(0.15, 0, "iclr")
32
+
33
+ with pytest.raises(ValueError):
34
+ _, _, _ = get_mpl_rcParams(0.15, -1.2, "iclr")
35
+
36
+
37
+ def test_incorrect_layout():
38
+ with pytest.raises(ValueError):
39
+ _, _, _ = get_mpl_rcParams(1, 1, "predatory_journal")