HOPSFlow-Paper/figsaver.py
2023-11-28 13:08:17 -05:00

196 lines
5 KiB
Python

import matplotlib
import matplotlib.pyplot as plt
import os
from pathlib import Path
import pickle
from contextlib import contextmanager
import numpy as np
try:
import tikzplotlib
except:
tikzplotlib = None # dirty
fig_path = Path(os.getcwd()) / "figures"
val_path = Path(os.getcwd()) / "values"
def export_fig(
name,
fig=None,
x_scaling=1,
y_scaling=0.4,
tikz=True,
save_pickle=True,
data=None,
**kwargs,
):
fig_path.mkdir(parents=True, exist_ok=True)
if fig is None:
fig = plt.gcf()
w, _ = fig.get_size_inches()
fig.set_size_inches((w * x_scaling, w * y_scaling))
if not fig.get_constrained_layout():
fig.tight_layout()
fig.canvas.draw()
# fig.savefig(fig_path / f"{name}.pdf")
# fig.savefig(fig_path / f"{name}.svg")
# fig.savefig(fig_path / f"{name}.pgf")
fig.savefig(fig_path / f"{name}.pdf", bbox_inches="tight")
if tikz and tikzplotlib:
tikzplotlib.clean_figure()
tikzplotlib.save(
fig_path / f"{name}.tex",
figure=fig,
axis_width="\\figW",
axis_height="\\figH",
**kwargs,
)
if save_pickle:
with open(fig_path / f"{name}.pickle", "wb") as file:
pickle.dump(fig, file)
if data is not None:
with open(fig_path / f"{name}.data.pickle", "wb") as file:
pickle.dump(data, file)
def scientific_round(val, *err, retprec=False):
"""Scientifically rounds the values to the given errors."""
val, err = np.asarray(val), np.asarray(err)
if len(err.shape) == 1:
err = np.array([err])
err = err.T
err = err.T
if err.size == 1 and val.size > 1:
err = np.ones_like(val) * err
if len(err.shape) == 0:
err = np.array([err])
if val.size == 1 and err.shape[0] > 1:
val = np.ones_like(err) * val
i = np.floor(np.log10(err))
first_digit = (err // 10 ** i).astype(int)
prec = (-i + np.ones_like(err) * (first_digit <= 3)).astype(int)
prec = np.max(prec, axis=1)
def smart_round(value, precision):
value = np.round(value, precision)
if precision <= 0:
value = value.astype(int)
return value
if val.size > 1:
rounded = np.empty_like(val)
rounded_err = np.empty_like(err)
for n, (value, error, precision) in enumerate(zip(val, err, prec)):
rounded[n] = smart_round(value, precision)
rounded_err[n] = smart_round(error, precision)
if retprec:
return rounded, rounded_err, prec
else:
return rounded, rounded_err
else:
prec = prec[0]
if retprec:
return (smart_round(val, prec), *smart_round(err, prec)[0], prec)
else:
return (smart_round(val, prec), *smart_round(err, prec)[0])
def tex_value(val, err=None, unit=None, prefix="", suffix="", prec=0, save=None):
"""Generates LaTeX output of a value with units and error."""
if err:
val, err, prec = scientific_round(val, err, retprec=True)
else:
val = np.round(val, prec)
if prec == 0:
val = int(val)
if err:
err = int(err)
val_string = rf"{val:.{prec}f}" if prec > 0 else str(val)
if err:
val_string += rf"\pm {err:.{prec}f}" if prec > 0 else str(err)
ret_string = r"\(" + prefix
if unit is None:
ret_string += val_string
else:
ret_string += rf"\SI{{{val_string}}}{{{unit}}}"
ret_string += suffix + r"\)"
if save is not None:
val_path.mkdir(parents=True, exist_ok=True)
with open(val_path / f"{save}.tex", "w") as f:
f.write(ret_string)
return ret_string
###############################################################################
# SIDE EFFECTS #
###############################################################################
MPL_RC = {
"lines.linewidth": 1,
"text.color": "black",
"axes.labelcolor": "black",
"xtick.color": "black",
"ytick.color": "black",
"figure.figsize": (5.78, 2.4),
"text.usetex": True,
"font.family": "serif",
# "font.serif": ["Roman"],
"font.size": 15,
"axes.labelsize": 13,
"axes.titlesize": 15,
"legend.fontsize": 13,
"xtick.labelsize": 13,
"ytick.labelsize": 13,
"figure.constrained_layout.use": True,
# "text.latex.preamble": r"\usepackage{mathtools}",
}
MPL_RC_POSTER = {
"font.family": "sans",
"text.usetex": False,
"pgf.rcfonts": False,
"lines.linewidth": 1.5,
"font.size": 17.28,
"axes.labelsize": 17.28,
"axes.titlesize": 17.28,
"legend.fontsize": 10,
"xtick.labelsize": 14.4,
"ytick.labelsize": 14.4,
}
@contextmanager
def hiro_style():
with plt.style.context("seaborn-deep"):
with matplotlib.rc_context(MPL_RC):
yield True
plt.style.use("default")
plt.style.use("seaborn-paper")
matplotlib.rcParams.update(MPL_RC)