Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use enum etc #21

Merged
merged 1 commit into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ advocate for the latter ([proof](https://agustinus.kristia.de/blog/plotting/)).
<br />

```diff
import pub_ready_plots
import pub_ready_plots as prp

...

pub_ready_plots.get_context(
...
- layout="icml",
+ layout="poster-landscape",
prp.get_context(
- layout=prp.Layout.ICML,
+ layout=prp.Layout.POSTER_LANDSCAPE,
...
)

Expand All @@ -59,18 +58,12 @@ pip install pub-ready-plots
## Quick usage

```python
import pub_ready_plots
import pub_ready_plots as prp

with pub_ready_plots.get_context(
width_frac=1, # Multiplier for `\linewidth`
height_frac=0.15, # Multiplier for `\textheight`
layout="icml", # or "iclr", "neurips", "aistats", "uai", "tmlr", "poster-portrait", "poster-landscape"
single_col=False, # only works for the "icml", "aistats", "uai" layouts
nrows=1, # depending on your subplots, default = 1
ncols=2, # depending on your subplots, default = 1
override_rc_params={"lines.linewidth": 4.123}, # Overriding rcParams
sharey=True, # Additional keyword args for `plt.subplots`
) as (fig, axs):
# Wrap you current plotting script with this `with` statement.
# By default, this will create a full-width, 0.15*\textheight plot that conforms
# to the ICLR template.
with prp.get_context(layout=prp.Layout.ICLR) as (fig, axs):
# Do whatever you want with `fig` and `axs`
...

Expand All @@ -91,6 +84,7 @@ Then in your LaTeX file, include the plot as follows:

That's it! But you should use TikZ more.
Anyway, see the full, runnable example in [`examples/simple_plot.py`](https://github.com/wiseodd/pub-ready-plots/blob/master/examples/simple_plot.py)
See [here](#all-available-options) for available options for `get_context()`!

> [!TIP]
> I recommend using this library in conjunction with
Expand All @@ -100,17 +94,37 @@ Anyway, see the full, runnable example in [`examples/simple_plot.py`](https://gi

## Advanced usages

### All available options

```python
import pub_ready_plots as prp

with prp.get_context(
layout=prp.Layout.ICML, # check `Layout` for all available layouts
width_frac=1, # multiplier for `\linewidth`
height_frac=0.15, # multiplier for `\textheight`
single_col=False, # only works for the "icml", "aistats", "uai" layouts
nrows=1, # depending on your subplots, default = 1
ncols=2, # depending on your subplots, default = 1
override_rc_params={"lines.linewidth": 4.123}, # Overriding rcParams
sharey=True, # Additional keyword args for `plt.subplots`
) as (fig, axs):
...

fig.savefig("filename.pdf")
```

### Creating plots for `\wrapfigure`

Say we want to have an inline figure of size `0.4\textwidth` and
height `0.15\textheight` in our NeurIPS paper.
Then all we have to do is the following:

```python
import pub_ready_plots
import pub_ready_plots as prp

with pub_ready_plots.get_context(
width_frac=0.4, height_frac=0.15, layout="neurips",
with prp.get_context(
layout=prp.Layout.NEURIPS, width_frac=0.4, height_frac=0.15,
) as (fig, axs):
# Your plot here!
...
Expand Down
12 changes: 7 additions & 5 deletions examples/advanced_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
import numpy as np
from matplotlib.axes import Axes

import pub_ready_plots
import pub_ready_plots as prp

########################################################################################
# User-specified rcParams override
########################################################################################
with pub_ready_plots.get_context(
with prp.get_context(
layout=prp.Layout.ICLR,
width_frac=1,
height_frac=0.15,
layout="iclr",
override_rc_params={"lines.linewidth": 5}, # Pass your style overrides here!
) as (fig, ax):
assert isinstance(ax, Axes)
Expand All @@ -28,10 +28,10 @@
########################################################################################
# Manual, most-flexible way to use this library
########################################################################################
rc_params, fig_width_in, fig_height_in = pub_ready_plots.get_mpl_rcParams(
rc_params, fig_width_in, fig_height_in = prp.get_mpl_rcParams(
layout=prp.Layout.POSTER_PORTRAIT,
width_frac=1,
height_frac=0.15,
layout="poster-portrait",
single_col=False,
)

Expand All @@ -47,6 +47,8 @@

x = np.linspace(-1, 1, 100)

assert isinstance(axs, np.ndarray)

axs[0].plot(x, np.sin(x))
axs[0].set_title("Sine")
axs[0].set_xlabel(r"$x$")
Expand Down
34 changes: 19 additions & 15 deletions examples/simple_plot.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import numpy as np
from matplotlib.axes import Axes

import pub_ready_plots
import pub_ready_plots as prp

########################################################################################
# Single plot (i.e. no subplots)
########################################################################################
with pub_ready_plots.get_context(
width_frac=1, # between 0 and 1
height_frac=0.15, # between 0 and 1
layout="iclr", # or "iclr", "neurips", "poster-portrait", "poster-landscape"
) as (fig, ax):
with (
prp.get_context(
layout=prp.Layout.ICLR, # or "iclr", "neurips", "poster-portrait", "poster-landscape"
width_frac=1, # between 0 and 1
height_frac=0.15, # between 0 and 1
) as (fig, ax)
):
# Just like in `plt.subplots`, `ax` is a matplotlib Axes if
# nrows & ncols are not specified (both default to 1).
assert isinstance(ax, Axes)
Expand All @@ -27,15 +29,17 @@
########################################################################################
# Multiple subplots
########################################################################################
with pub_ready_plots.get_context(
width_frac=1, # between 0 and 1
height_frac=0.15, # between 0 and 1
nrows=1, # depending on your subplots
ncols=2, # depending on your subplots
layout="iclr", # or "iclr", "neurips", "poster-portrait", "poster-landscape"
single_col=False, # only works for the "icml" layout
sharey=True, # Additional keyword args for `plt.subplots`
) as (fig, axs):
with (
prp.get_context(
layout=prp.Layout.ICLR, # or "iclr", "neurips", "poster-portrait", "poster-landscape"
width_frac=1, # between 0 and 1
height_frac=0.15, # between 0 and 1
nrows=1, # depending on your subplots
ncols=2, # depending on your subplots
single_col=False, # only works for the "icml" layout
sharey=True, # Additional keyword args for `plt.subplots`
) as (fig, axs)
):
# If `nrows` or `ncols` are not 1, `axs` is a NumPy array containing Axes'
assert isinstance(axs, np.ndarray)

Expand Down
3 changes: 3 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
test:
uv run pytest --cov

ruff:
-uv run ruff format
@uv run ruff check --fix
Expand Down
3 changes: 2 additions & 1 deletion pub_ready_plots/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pub_ready_plots.pub_ready_plots import get_context, get_mpl_rcParams
from pub_ready_plots.styles import Layout

__all__ = ["get_mpl_rcParams", "get_context"]
__all__ = ["get_mpl_rcParams", "get_context", "Layout"]
43 changes: 28 additions & 15 deletions pub_ready_plots/pub_ready_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@
from matplotlib.figure import Figure
from numpy import ndarray

from .styles import PAPER_FORMATS, Style
from .styles import PAPER_FORMATS, Layout, Style


@contextmanager
def get_context(
layout: Layout,
width_frac: float = 1,
height_frac: float = 0.15,
layout: str = "neurips",
single_col: bool = False,
nrows: int = 1,
ncols: int = 1,
override_rc_params: dict[str, Any] = dict(),
**kwargs: Any,
) -> Generator[tuple[Figure, Union[Axes, ndarray[Any, Any]]], None, None]:
rc_params, fig_width_in, fig_height_in = get_mpl_rcParams(
width_frac, height_frac, layout, single_col
layout=layout,
width_frac=width_frac,
height_frac=height_frac,
single_col=single_col,
)
rc_params.update(override_rc_params)

Expand All @@ -32,9 +35,9 @@ def get_context(


def get_mpl_rcParams(
layout: Layout,
width_frac: float = 1,
height_frac: float = 0.15,
layout: str = "neurips",
single_col: bool = False,
) -> tuple[dict[str, Any], float, float]:
"""Get matplotlib rcParams dict and fig width & height in inches, depending on the
Expand All @@ -44,7 +47,7 @@ def get_mpl_rcParams(

```python
rc_params, fig_width_in, fig_height_in = pub_ready_plots.get_mpl_rcParams(
width_frac=fig_width_frac, height_frac=fig_height_frac, layout="icml"
layout=Layout.ICML, width_frac=fig_width_frac, height_frac=fig_height_frac
)
plt.rcParams.update(rc_params)

Expand All @@ -69,12 +72,13 @@ def get_mpl_rcParams(
The arg. `width=\\linewidth` is important!

Args:
layout: The LaTeX template used. Possible values are Layout.ICML, Layout.NeurIPS,
Layout.ICLR, Layout.AISTATS, Layout.UAI, Layout.JMLR, Layout.TMLR,
Layout.POSTER_PORTRAIT (A1, 2-column), and Layout.POSTER_LANDSCAPE (A0, 3-col).
width_frac: Fraction of `\\linewidth` as the figure width. Usually set to 1.
height_frac: Fraction of `\\textheight` as the figure height. Try 0.175.
layout: The LaTeX template used. Possible values are "icml", "iclr", "neurips",
"jmlr", "poster-portrait" (A1, 2-column), and "poster-landscape" (A0, 3-col).
single_col: Whether the plot is single column in a layout that has two columns
(e.g. ICML). Not supported for any other layout.
single_col: Whether the plot is single column in a layout that has multiple columns
(e.g. ICML, posters). Not supported for any other layout.

Returns:
rc_params: Matplotlib key-value rc-params. Use it via
Expand All @@ -86,14 +90,23 @@ def get_mpl_rcParams(
if (width_frac <= 0 or width_frac > 1) or (height_frac <= 0 or height_frac > 1):
raise ValueError("Both `width_frac` and `height_frac` must be between 0 and 1.")

if layout not in PAPER_FORMATS.keys():
raise ValueError(f"Layout must be in {list(PAPER_FORMATS.keys())}.")

if layout not in ["icml", "aistats", "uai"] and single_col:
raise ValueError("Double-column is only supported for ICML, AISTATS, and UAI.")
if (
layout
not in [
Layout.ICML,
Layout.AISTATS,
Layout.UAI,
Layout.POSTER_PORTRAIT,
Layout.POSTER_LANDSCAPE,
]
and single_col
):
raise ValueError(
"Double-column is only supported for ICML, AISTATS, UAI, POSTER_PORTRAIT, and POSTER_LANDSCAPE."
)

format: Style = PAPER_FORMATS[layout]
is_poster = "poster" in layout
is_poster: bool = "poster" in layout._name_.lower()

rc_params = {
"text.usetex": False,
Expand Down
Loading