Source code for ekomark.plots

"""Plotting tools to show the evolved PDF and the computed operators."""

import io
import pprint

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib.cm import get_cmap
from matplotlib.colors import LogNorm

from eko import basis_rotation as br
from eko.io.struct import EKO


[docs] def input_figure(theory, ops, pdf_name=None): """Pretty-prints the setup to a figure. Parameters ---------- theory : dict theory card ops : dict operator card pdf_name : str PDF name Returns ------- firstPage : matplotlib.pyplot.Figure figure """ firstPage = plt.figure(figsize=(25, 20)) # theory firstPage.text(0.05, 0.97, "Theory:", size=20, ha="left", va="top") str_stream = io.StringIO() th_copy = theory.copy() th_copy.update({"hash": theory["hash"][:7]}) pprint.pprint(th_copy, stream=str_stream, width=50) firstPage.text(0.05, 0.92, str_stream.getvalue(), size=14, ha="left", va="top") # operators firstPage.text(0.55, 0.87, "Operators:", size=20, ha="left", va="top") str_stream = io.StringIO() ops_copy = ops.copy() ops_copy.update({"hash": ops["hash"][:7]}) pprint.pprint(ops_copy, stream=str_stream, width=50) firstPage.text(0.55, 0.82, str_stream.getvalue(), size=14, ha="left", va="top") # pdf if pdf_name is not None: firstPage.text(0.55, 0.97, "source pdf:", size=20, ha="left", va="top") firstPage.text(0.55, 0.92, pdf_name, size=14, ha="left", va="top") firstPage.tight_layout() return firstPage
[docs] def plot_dist(x, y, yerr, yref, title=None, oMx_min=1e-2, oMx_max=0.5): """Compare two distributions. Generates a plot with 3 areas: - small x, i.e. log(x) as abscissa - linear x, i.e. with id(x) as abscissa - large x, i.e. with log(1-x) as abscissa Parameters ---------- x : numpy.ndarray list of abscisses y : numpy.ndarray computed list of ordinates yerr : numpy.ndarray list of ordinate errors yref : numpy.ndarray reference list of ordinates Other Parameters ---------------- title : str, optional additional overall title oMx_min : float maximum value for the large x region, i.e. 1-x > 1 - `oMx_min` oMx_max : float minimum value for the large x region, i.e. 1 - `oMx_max` > 1-x Returns ------- fig : matplotlib.pyplot.figure created figure """ np.seterr(divide="ignore", invalid="ignore") fig = plt.figure(figsize=(15, 5)) fig.subplots_adjust(hspace=0.05) if title is not None: fig.suptitle(title) # small x ax1 = plt.subplot(2, 3, 1) plt.setp(ax1.get_xticklabels(), visible=False) plt.title("small x") ax1.set_xscale("log", nonpositive="clip") ax1.set_yscale("log", nonpositive="clip") plt.errorbar(x, y, yerr=yerr, fmt="o") plt.loglog(x, yref, "x") ax1b = plt.subplot(2, 3, 4, sharex=ax1) ax1b.set_xscale("log", nonpositive="clip") # ax1b.set_yscale("log", nonpositive="clip") # plt.errorbar(x, np.abs((y - yref) / yref), yerr=np.abs(yerr / yref), fmt="s") y_rel_diff = (y - yref) / yref ax1b.set_yscale("symlog", linthresh=np.min(np.abs(y_rel_diff)), linscale=0.1) plt.errorbar(x, y_rel_diff, yerr=np.abs(yerr / yref), fmt="s") plt.axhline(0, linestyle="--", color="grey") plt.xlabel("x") # linear x ax2 = plt.subplot(2, 3, 2) plt.setp(ax2.get_xticklabels(), visible=False) plt.title("linear x") plt.errorbar(x, y, yerr=yerr, fmt="o") plt.plot(x, yref, "x") ax2b = plt.subplot(2, 3, 5, sharex=ax2) ax2b.set_yscale("log", nonpositive="clip") plt.errorbar(x, np.abs((y - yref) / yref), yerr=np.abs(yerr / yref), fmt="s") plt.xlabel("x") # large x ax3 = plt.subplot(2, 3, 3) ax3.set_xscale("log", nonpositive="clip") ax3.set_yscale("log", nonpositive="clip") x = np.array(x) oMx = 1.0 - x plt.setp(ax3.get_xticklabels(), visible=False) ax3.set_xlim(oMx_min, oMx_max) plt.title("large x, i.e. small (1-x)") plt.errorbar(oMx, y, yerr=yerr, fmt="o") plt.loglog(oMx, yref, "x") ax3b = plt.subplot(2, 3, 6, sharex=ax3) ax3b.set_xscale("log", nonpositive="clip") ax3b.set_yscale("log", nonpositive="clip") plt.errorbar(oMx, np.abs((y - yref) / yref), yerr=np.abs(yerr / yref), fmt="s") plt.xlabel("1-x") return fig
[docs] def plot_operator(var_name, op, op_err, log_operator=True, abs_operator=True): """Plot a single operator as heat map. Parameters ---------- ret : dict DGLAP result var_name : str operator name log_operator : bool, optional plot on logarithmic scale abs_operator : bool, optional plot absolute value (instead of true value) Returns ------- fig : matplotlib.pyplot.figure created figure """ # get # op = ret["operators"][var_name] # op_err = ret["errors"][var_name] # empty? thre = 1e-8 if np.max(np.abs(op)) <= thre: return None fig = plt.figure(figsize=(25, 5)) fig.suptitle(var_name) # TODO fix File "/usr/lib/python3/dist-packages/matplotlib/colors.py", # line 1181, in _check_vmin_vmax # raise ValueError("minvalue must be positive") # Settings colormap = "coolwarm" ax = plt.subplot(1, 3, 1) if abs_operator: plt.title("|operator|") colormap = "inferno" op = np.abs(op) else: plt.title("operator") norm = LogNorm() if log_operator else None cmap = get_cmap(colormap) # Plotting operator im = plt.imshow(op, cmap=cmap, norm=norm, aspect="auto") plt.colorbar(im, ax=ax, fraction=0.034, pad=0.04) # Plotting operator error ax = plt.subplot(1, 3, 2) plt.title("operator_error") im = plt.imshow(op_err, norm=norm, aspect="auto") plt.colorbar(im, ax=ax, fraction=0.034, pad=0.04) # Plotting ratio ax = plt.subplot(1, 3, 3) plt.title("|error/value|") # Avoid the numpy warning old_settings = np.seterr(divide="ignore", invalid="ignore") err_to_val = np.abs(np.array(op_err) / np.array(op)) np.seterr(**old_settings) im = plt.imshow(err_to_val, norm=norm, aspect="auto") plt.colorbar(im, ax=ax, fraction=0.034, pad=0.04) return fig
[docs] def save_operators_to_pdf(path, theory, ops, me: EKO, skip_pdfs, change_lab=False): """Output all operator heatmaps to PDF. Parameters ---------- path : str path to the plot theory : dict theory card ops : dict operator card me : eko.output.Output DGLAP result skip_pdfs : list PDF to skip change_lab : bool set whether to rename the labels """ ops_names = list(me.bases.targetpids) if np.allclose(ops_names, br.rotate_flavor_to_evolution): ops_names = br.evol_basis_pids else: raise ValueError("Can not reconstruct PDF names") ops_id = f"o{ops['hash'][:6]}_t{theory['hash'][:6]}" path = f"{path}/{ops_id}.pdf" print(f"Plotting operators plots to {path}") with PdfPages(path) as pp: # print setup firstPage = input_figure(theory, ops) pp.savefig() plt.close(firstPage) # plot the operators # it's necessary to reshuffle the eko output for mu2 in me.mu2grid: results = me[mu2].operator errors = me[mu2].error # loop on pids for label_out, res, res_err in zip(ops_names, results, errors): if label_out in skip_pdfs: continue new_op = {} new_op_err = {} # loop on xgrid point for j in range(len(me.xgrid)): # loop on pid in for label_in, val, val_err in zip(ops_names, res[j], res_err[j]): if label_in in skip_pdfs: continue if label_in not in new_op: new_op[label_in] = [] new_op_err[label_in] = [] new_op[label_in].append(val) new_op_err[label_in].append(val_err) for label_in in ops_names: if label_in in skip_pdfs: continue lab_in = label_in lab_out = label_out if change_lab: index_in = br.evol_basis_pids.index(label_in) index_out = br.evol_basis_pids.index(label_out) lab_in = br.evol_basis[index_in] lab_out = br.evol_basis[index_out] fig = None try: fig = plot_operator( f"Operator ({lab_in};{lab_out}) ยต_F^2 = {mu2} GeV^2", new_op[label_in], new_op_err[label_in], ) if fig is not None: pp.savefig() finally: if fig: plt.close(fig)