Source code for lib.fig_config
tex_installed = False
import sys
import plotly.graph_objects as go
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib import pyplot as plt
if not sys.platform.startswith("win"):
import subprocess
try:
# print("WORKING ON WINDOWS")
bashCommand = "yum info texlive-latex-base"
process = subprocess.Popen(
bashCommand.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
except FileNotFoundError:
# print("WORKING ON UBUNTU")
bashCommand = "apt list --installed | grep texlive-latex-base"
process = subprocess.Popen(
bashCommand.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
output, error = process.communicate()
if "Error" in str(output):
print(
"You don't have latex installed. Changing default configuration to tex=False"
)
tex_installed = False
else:
print("You have latex installed!. Applying default configuration (tex=True)")
tex_installed = True
from matplotlib import pyplot as plt
from matplotlib.ticker import MultipleLocator
[docs]def figure_features(tex=tex_installed, font="serif", dpi=600):
"""Customize figure settings.
:param tex: use LaTeX, defaults to tex_installed
:type tex: bool, optional
:param font: font type, defaults to "serif"
:type font: str, optional
:param dpi: dots per inch, defaults to 600
:type dpi: int, optional
"""
plt.rcParams.update(
{
"font.size": 16, # Taille de police générale
"font.family": font, # Famille de police (passée par variable 'font')
"font.weight": "bold", # Épaisseur de police (gras ici)
"text.usetex": tex, # Utiliser LaTeX pour le rendu du texte (booléen passé par 'tex')
"figure.subplot.top": 0.92, # Marge supérieure de la figure (0 = bord bas, 1 = bord haut)
"figure.subplot.right": 0.95, # Marge droite de la figure
"figure.subplot.left": 0.10, # Marge gauche de la figure
"figure.subplot.bottom": 0.12, # Marge inférieure de la figure
"figure.subplot.hspace": 0.2, # Espacement vertical entre les subplots
"figure.subplot.wspace": 0.2, # Espacement horizontal entre les subplots
"savefig.dpi": dpi, # Résolution (dpi) lors de la sauvegarde de la figure (variable 'dpi')
"savefig.format": "png", # Format de sauvegarde des figures (ici PNG)
"axes.titlesize": 16, # Taille de police pour le titre des axes
"axes.labelsize": 16, # Taille de police pour les labels des axes
"axes.axisbelow": True, # Placer la grille sous les éléments du graphique
"xtick.direction": "in", # Orientation des ticks en X (vers l'intérieur)
"ytick.direction": "in", # Orientation des ticks en Y (vers l'intérieur)
"xtick.major.size": 5, # Taille des ticks majeurs en X
"xtick.minor.size": 2.25, # Taille des ticks mineurs en X
"xtick.major.pad": 7.5, # Espace entre les ticks majeurs X et les labels
"xtick.minor.pad": 7.5, # Espace entre les ticks mineurs X et les labels
"ytick.major.pad": 7.5, # Espace entre les ticks majeurs Y et les labels
"ytick.minor.pad": 7.5, # Espace entre les ticks mineurs Y et les labels
"ytick.major.size": 5, # Taille des ticks majeurs en Y
"ytick.minor.size": 2.25, # Taille des ticks mineurs en Y
"xtick.labelsize": 15, # Taille de police pour les labels des ticks en X
"ytick.labelsize": 15, # Taille de police pour les labels des ticks en Y
"legend.fontsize": 12, # Taille de police pour la légende
"legend.framealpha": 1, # Transparence du cadre de la légende (1 = opaque)
"figure.titlesize": 18, # Taille de police pour le titre global de la figure
"lines.linewidth": 2, # Épaisseur des lignes tracées
"figure.constrained_layout.use": True, # Activation du layout contraint (optimise la disposition auto)
}
)
[docs]def add_grid(ax, lines=True, locations=None):
"""Add a grid to the current plot.
:param ax: axis object in which to draw the grid.
:type ax: Axis
:param lines: add lines to the grid, defaults to True
:type lines: bool, optional
:param locations: (xminor, xmajor, yminor, ymajor), defaults to None
:type locations: tuple, optional
"""
if lines:
ax.grid(lines, alpha=0.5, which="minor", ls=":")
ax.grid(lines, alpha=0.7, which="major")
if locations is not None:
assert len(locations) == 4, "Invalid entry for the locations of the markers"
xmin, xmaj, ymin, ymaj = locations
ax.xaxis.set_minor_locator(MultipleLocator(xmin))
ax.xaxis.set_major_locator(MultipleLocator(xmaj))
ax.yaxis.set_minor_locator(MultipleLocator(ymin))
ax.yaxis.set_major_locator(MultipleLocator(ymaj))
[docs]def format_coustom_plotly(
fig: go.Figure,
title: str = None,
legend: dict = dict(),
fontsize: int = 16,
figsize: int = None,
ranges: tuple = (None, None),
matches: tuple = ("x", "y"),
tickformat: tuple = (".s", ".s"),
log: tuple = (False, False),
margin: dict = {"auto": True},
add_units: bool = True,
debug: bool = False,
):
"""Format a plotly figure
:param fig: plotly figure
:type fig: go.Figure
:param title: title of the figure, defaults to None
:type title: str, optional
:param legend: legend options, defaults to dict()
:type legend: dict, optional
:param fontsize: font size, defaults to 16
:type fontsize: int, optional
:param figsize: figure size, defaults to None
:type figsize: tuple, optional
:param ranges: axis ranges, defaults to (None,None)
:type ranges: tuple, optional
:param matches: axis matches, defaults to ("x","y")
:type matches: tuple, optional
:param tickformat: axis tick format, defaults to ('.s','.s')
:type tickformat: tuple, optional
:param log: axis log scale, defaults to (False,False)
:type log: tuple, optional
:param margin: figure margin, defaults to {"auto":True}
:type margin: dict, optional
:param add_units: True to add units to axis labels, False otherwise, defaults to True
:type add_units: bool, optional
:param debug: True to print debug statements, False otherwise, defaults to False
:type debug: bool, optional
:return: plotly figure
:rtype: go.Figure
"""
# Find the number of subplots
if type(fig) == go.Figure:
try:
rows, cols = fig._get_subplot_rows_columns()
rows, cols = rows[-1], cols[-1]
except Exception:
rows, cols = 1, 1
print("[red]Error: unknown figure type[/red]")
else:
rows, cols = 1, 1
print("[red]Error: unknown figure type[/red]")
if debug:
print("[cyan]Detected number of subplots: " + str(rows * cols) + "[/cyan]")
if figsize == None:
figsize = (800 + 400 * (cols - 1), 600 + 200 * (rows - 1))
default_margin = {"color": "white", "margin": (0, 0, 0, 0)}
if margin != None:
for key in default_margin.keys():
if key not in margin.keys():
margin[key] = default_margin[key]
fig.update_layout(
title=title,
legend=legend,
template="presentation",
font=dict(size=fontsize),
paper_bgcolor=margin["color"],
bargap=0,
) # font size and template
fig.update_xaxes(
matches=matches[0],
showline=True,
mirror="ticks",
showgrid=True,
minor_ticks="inside",
tickformat=tickformat[0],
# range=ranges[0],
) # tickformat=",.1s" for scientific notation
if ranges[0] != None:
fig.update_xaxes(range=ranges[0])
if ranges[1] != None:
fig.update_yaxes(range=ranges[1])
fig.update_yaxes(
matches=matches[1],
showline=True,
mirror="ticks",
showgrid=True,
minor_ticks="inside",
tickformat=tickformat[1],
# range=ranges[1],
) # tickformat=",.1s" for scientific notation
if figsize != None:
fig.update_layout(width=figsize[0], height=figsize[1])
if log[0]:
fig.update_xaxes(type="log", tickmode="linear")
if log[1]:
fig.update_yaxes(type="log", tickmode="linear")
if margin["auto"] == False:
fig.update_layout(
margin=dict(
l=margin["margin"][0],
r=margin["margin"][1],
t=margin["margin"][2],
b=margin["margin"][3],
)
)
# Update axis labels to include units
if add_units:
try:
fig.update_xaxes(
title_text=fig.layout.xaxis.title.text
+ get_run_units(fig.layout.xaxis.title.text, debug=debug)
)
except AttributeError:
pass
try:
fig.update_yaxes(
title_text=fig.layout.yaxis.title.text
+ get_run_units(fig.layout.yaxis.title.text, debug=debug)
)
except AttributeError:
pass
return fig
[docs]def get_run_units(var, debug=False):
"""Returns the units of a variable based on the variable name
:param var: variable name
:type var: str
:param debug: True to print debug statements, False otherwise, defaults to False
:type debug: bool
:return: units
:rtype: str
"""
units = {
"R": " (cm) ",
"X": " (cm) ",
"Y": " (cm) ",
"Z": " (cm) ",
"E": " (MeV) ",
"P": " (MeV) ",
"PE": " (counts) ",
"Time": " (s) ",
"Energy": " (MeV) ",
"Charge": " (ADC x tick) ",
}
unit = ""
for unit_key in list(units.keys()):
if debug:
print("Checking for " + unit_key + " in " + var)
if var.endswith(unit_key):
unit = units[unit_key]
if debug:
print("Unit found for " + var)
return unit
[docs]def unicode(x):
"""Returns the unicode character for a given string
:param x: string to convert to unicode
:type x: str
:return: unicode character
:rtype: str
"""
if type(x) != str:
raise TypeError("Input must be a string")
unicode_greek = {
"Delta": "\u0394",
"mu": "\u03BC",
"pi": "\u03C0",
"gamma": "\u03B3",
"Sigma": "\u03A3",
"Lambda": "\u039B",
"alpha": "\u03B1",
"beta": "\u03B2",
"gamma": "\u03B3",
"delta": "\u03B4",
"epsilon": "\u03B5",
"zeta": "\u03B6",
"eta": "\u03B7",
"theta": "\u03B8",
"iota": "\u03B9",
"kappa": "\u03BA",
"lambda": "\u03BB",
"mu": "\u03BC",
"nu": "\u03BD",
"xi": "\u03BE",
"omicron": "\u03BF",
"pi": "\u03C0",
"rho": "\u03C1",
"sigma": "\u03C3",
"tau": "\u03C4",
"upsilon": "\u03C5",
"phi": "\u03C6",
"chi": "\u03C7",
"psi": "\u03C8",
"omega": "\u03C9",
}
unicode_symbol = {
"PlusMinus": "\u00B1",
"MinusPlus": "\u2213",
"Plus": "\u002B",
"Minus": "\u2212",
"Equal": "\u003D",
"NotEqual": "\u2260",
"LessEqual": "\u2264",
"GreaterEqual": "\u2265",
"Less": "\u003C",
"Greater": "\u003E",
"Approximately": "\u2248",
"Proportional": "\u221D",
"Infinity": "\u221E",
"Degree": "\u00B0",
"Prime": "\u2032",
"DoublePrime": "\u2033",
"TriplePrime": "\u2034",
"QuadruplePrime": "\u2057",
"Micro": "\u00B5",
"PerMille": "\u2030",
"Permyriad": "\u2031",
"Minute": "\u2032",
"Second": "\u2033",
"Dot": "\u02D9",
"Cross": "\u00D7",
"Star": "\u22C6",
"Circle": "\u25CB",
"Square": "\u25A1",
"Diamond": "\u25C7",
"Triangle": "\u25B3",
"LeftTriangle": "\u22B2",
"RightTriangle": "\u22B3",
"LeftTriangleEqual": "\u22B4",
"RightTriangleEqual": "\u22B5",
"LeftTriangleBar": "\u29CF",
"RightTriangleBar": "\u29D0",
"LeftTriangleEqualBar": "\u29CF",
"RightTriangleEqualBar": "\u29D0",
"LeftRightArrow": "\u2194",
"UpDownArrow": "\u2195",
"UpArrow": "\u2191",
"DownArrow": "\u2193",
"LeftArrow": "\u2190",
"RightArrow": "\u2192",
"UpArrowDownArrow": "\u21C5",
"LeftArrowRightArrow": "\u21C4",
"LeftArrowLeftArrow": "\u21C7",
"UpArrowUpArrow": "\u21C8",
"RightArrowRightArrow": "\u21C9",
"DownArrowDownArrow": "\u21CA",
"LeftRightVector": "\u294E",
"RightUpDownVector": "\u294F",
"DownLeftRightVector": "\u2950",
"LeftUpDownVector": "\u2951",
"LeftVectorBar": "\u2952",
"RightVectorBar": "\u2953",
"RightUpVectorBar": "\u2954",
"RightDownVectorBar": "\u2955",
}
unicode_dict = {**unicode_greek, **unicode_symbol}
return unicode_dict[x]