bachelor_thesis/prog/python/qqgg/tangled/plot_utils.py

245 lines
7.2 KiB
Python
Raw Normal View History

2020-04-18 20:00:18 +02:00
"""
Some shorthands for common plotting tasks related to the investigation
of monte-carlo methods in one rimension.
Author: Valentin Boettcher <hiro at protagon.space>
"""
import matplotlib.pyplot as plt
2020-04-19 17:34:00 +02:00
import numpy as np
from utility import *
2020-04-18 20:00:18 +02:00
def plot_increments(ax, increment_borders, label=None, *args, **kwargs):
"""Plot the increment borders from a list. The first and last one
:param ax: the axis on which to draw
:param list increment_borders: the borders of the increments
:param str label: the label to apply to one of the vertical lines
"""
ax.axvline(x=increment_borders[1], label=label, *args, **kwargs)
2020-04-10 14:51:26 +02:00
for increment in increment_borders[1:-1]:
ax.axvline(x=increment, *args, **kwargs)
2020-04-12 14:42:29 +02:00
def plot_vegas_weighted_distribution(
2020-06-04 16:12:04 +02:00
ax, points, dist, increment_borders, integral=None, color="orange", *args, **kwargs
2020-04-12 14:42:29 +02:00
):
"""Plot the distribution with VEGAS weights applied.
:param ax: axis
:param points: points
:param dist: distribution
:param increment_borders: increment borders
"""
num_increments = increment_borders.size
weighted_dist = dist.copy()
2020-06-04 16:12:04 +02:00
var = 0
total_weight = points.max() - points.min()
2020-04-12 14:42:29 +02:00
for left_border, right_border in zip(increment_borders[:-1], increment_borders[1:]):
length = right_border - left_border
mask = (left_border <= points) & (points <= right_border)
2020-04-12 14:42:29 +02:00
weighted_dist[mask] = dist[mask] * num_increments * length
2020-06-04 16:12:04 +02:00
if integral:
var += (
np.sum((integral - weighted_dist[mask]) ** 2)
/ (weighted_dist[mask].size - 1)
* length
/ total_weight
)
if integral:
std = np.sqrt(var)
ax.axhline(weighted_dist.mean(), color=color, linestyle="--")
ax.axhspan(
weighted_dist.mean() - std,
weighted_dist.mean() + std,
color=color,
alpha=0.2,
linestyle="--",
)
ax.plot(
points, weighted_dist, *args, color=color, **kwargs,
)
2020-04-10 14:51:26 +02:00
2020-04-12 14:42:29 +02:00
def plot_stratified_rho(ax, points, increment_borders, *args, **kwargs):
"""Plot the weighting distribution resulting from the increment
borders.
:param ax: axis
:param points: points
:param increment_borders: increment borders
"""
num_increments = increment_borders.size
ρ = np.empty_like(points)
for left_border, right_border in zip(increment_borders[:-1], increment_borders[1:]):
length = right_border - left_border
mask = (left_border <= points) & (points <= right_border)
ρ[mask] = 1 / (num_increments * length)
ax.plot(points, ρ, *args, **kwargs)
2020-04-24 12:14:15 +02:00
import matplotlib.gridspec as gridspec
def draw_ratio_plot(histograms, normalize_to=1, **kwargs):
fig, (ax_hist, ax_ratio) = set_up_plot(
2, 1, sharex=True, gridspec_kw=dict(height_ratios=[3, 1], hspace=0), **kwargs
)
reference, edges = histograms[0]["hist"]
reference_error = np.sqrt(reference)
ref_int = hist_integral(histograms[0]["hist"])
reference = reference / ref_int
reference_error = reference_error / ref_int
for histogram in histograms:
2020-05-17 18:05:21 +02:00
heights, _ = (
histogram["hist"]
if "hist" in histogram
else np.histogram(histogram["samples"], bins=edges)
)
2020-04-24 12:14:15 +02:00
integral = hist_integral([heights, edges])
errors = np.sqrt(heights) / integral
heights = heights / integral
draw_histogram(
ax_hist,
[heights, edges],
errorbars=errors,
hist_kwargs=(
histogram["hist_kwargs"] if "hist_kwargs" in histogram else dict()
),
errorbar_kwargs=(
histogram["errorbar_kwargs"]
if "errorbar_kwargs" in histogram
else dict()
),
normalize_to=normalize_to,
)
set_up_axis(ax_ratio, pimp_top=False)
draw_histogram(
ax_ratio,
2020-05-03 11:21:12 +02:00
[
np.divide(
heights, reference, out=np.ones_like(heights), where=reference != 0
),
edges,
],
errorbars=np.divide(
errors, reference, out=np.zeros_like(heights), where=reference != 0
),
2020-04-24 12:14:15 +02:00
hist_kwargs=(
histogram["hist_kwargs"] if "hist_kwargs" in histogram else dict()
),
errorbar_kwargs=(
histogram["errorbar_kwargs"]
if "errorbar_kwargs" in histogram
else dict()
),
normalize_to=None,
)
ax_ratio.set_ylabel("ratio")
2020-04-24 12:14:15 +02:00
return fig, (ax_hist, ax_ratio)
def hist_integral(hist):
heights, edges = hist
return heights @ (edges[1:] - edges[:-1])
2020-04-22 11:26:13 +02:00
def draw_histogram(
ax,
histogram,
errorbars=True,
hist_kwargs=dict(color="#1f77b4"),
2020-04-24 15:01:39 +02:00
errorbar_kwargs=dict(),
autoau=True,
2020-04-22 11:26:13 +02:00
normalize_to=None,
):
"""Draws a histogram with optional errorbars using the step style.
:param ax: axis to draw on
:param histogram: an array of the form [heights, edges]
:param hist_kwargs: keyword args to pass to `ax.step`
:param errorbar_kwargs: keyword args to pass to `ax.errorbar`
:param autoau: if set, the y axis will receive an a.u. label
2020-04-22 11:26:13 +02:00
:param normalize_to: if set, the histogram will be normalized to the value
:returns: the given axis
"""
heights, edges = histogram
2020-04-14 16:57:10 +02:00
centers = (edges[1:] + edges[:-1]) / 2
2020-04-22 16:11:53 +02:00
deviations = (
(errorbars if isinstance(errorbars, (np.ndarray, list)) else np.sqrt(heights))
if errorbars is not False
else None
)
2020-04-22 11:26:13 +02:00
if normalize_to is not None:
2020-04-22 16:11:53 +02:00
integral = hist_integral(histogram)
2020-04-22 11:26:13 +02:00
heights = heights / integral * normalize_to
2020-04-22 16:11:53 +02:00
if errorbars is not False:
deviations = deviations / integral * normalize_to
2020-04-24 12:14:15 +02:00
hist_plot = ax.step(edges, [heights[0], *heights], **hist_kwargs)
2020-04-22 16:11:53 +02:00
if errorbars is not False:
2020-04-24 15:01:39 +02:00
if "color" not in errorbar_kwargs:
errorbar_kwargs["color"] = hist_plot[0].get_color()
ax.errorbar(centers, heights, deviations, linestyle="none", **errorbar_kwargs)
2020-04-22 11:26:13 +02:00
ax.set_xlim(*[edges[0], edges[-1]])
ax.set_ylabel("a.u.")
2020-04-22 11:26:13 +02:00
return ax
2020-04-24 12:14:15 +02:00
def draw_histo_auto(points, xlabel, bins=50, range=None, rethist=False, **kwargs):
2020-04-22 11:26:13 +02:00
"""Creates a histogram figure from sample points, normalized to unity.
:param points: samples
:param xlabel: label of the x axis
:param bins: number of bins
:param range: the range of the values
2020-04-22 16:11:53 +02:00
:param rethist: whether to return the histogram as third argument
2020-04-22 11:26:13 +02:00
:returns: figure, axis
"""
2020-04-24 12:14:15 +02:00
hist = np.histogram(points, bins, range=range, **kwargs)
fig, ax = set_up_plot()
draw_histogram(ax, hist, normalize_to=1)
2020-04-10 14:51:26 +02:00
2020-04-24 12:14:15 +02:00
ax.set_xlabel(xlabel)
ax.set_ylabel("Count")
2020-04-22 11:26:13 +02:00
2020-04-24 12:14:15 +02:00
return (fig, ax, hist) if rethist else (fig, ax)
2020-04-15 16:55:14 +02:00
2020-04-22 16:11:53 +02:00
def yoda_to_numpy(histo):
2020-05-15 18:36:41 +02:00
edges = histo.xEdges()
heights = np.array([bi.numEntries() for bi in histo])
2020-04-22 16:11:53 +02:00
return heights, edges
2020-04-17 09:58:50 +02:00
2020-04-22 16:11:53 +02:00
def draw_yoda_histo_auto(h, xlabel, **kwargs):
2020-04-22 18:02:20 +02:00
hist = yoda_to_numpy(h)
2020-04-19 17:34:00 +02:00
fig, ax = set_up_plot()
2020-04-22 16:11:53 +02:00
draw_histogram(ax, hist, errorbars=True, normalize_to=1, **kwargs)
2020-04-17 09:58:50 +02:00
2020-04-19 17:34:00 +02:00
ax.set_xlabel(xlabel)
return fig, ax