diff --git a/plot_mu_trajectories.py b/plot_mu_trajectories.py index c47eb45..e6c4bbf 100644 --- a/plot_mu_trajectories.py +++ b/plot_mu_trajectories.py @@ -26,6 +26,7 @@ CASES = { } N_PER_BRANCH = 266 # mu samples between consecutive poles +N_TAIL = 100 # extra samples extending the outer branches geometrically up to |mu| ~ 1e4 / lambda_min EPS = 0.01 # gap left on each side of a pole MU_HALF_WIDTH = 3 # mu is sampled in [m - MU_HALF_WIDTH, m + MU_HALF_WIDTH], m the mean of the poles N_DOTTED_OUTER = 2 # points drawn dotted at the ends of the outer branches @@ -68,11 +69,19 @@ def plot_trajectories(Q, x0): mu_min = poles.mean() - MU_HALF_WIDTH mu_max = poles.mean() + MU_HALF_WIDTH - mu = np.concatenate([np.linspace(lo, hi, N_PER_BRANCH) for lo, hi in - [(mu_min, poles[0] - EPS), (poles[0] + EPS, poles[1] - EPS), (poles[1] + EPS, mu_max)]]) + # x(mu) only reaches the centre as |mu| -> inf, so the outer branches continue geometrically + # beyond [mu_min, mu_max]; these samples show up in the trajectory but not on the mu axes. + tail = np.geomspace(MU_HALF_WIDTH / N_PER_BRANCH, 1e4 / Q.eig.min(), N_TAIL) + branch_samples = [ + np.concatenate((mu_min - tail[::-1], np.linspace(mu_min, poles[0] - EPS, N_PER_BRANCH))), + np.linspace(poles[0] + EPS, poles[1] - EPS, N_PER_BRANCH), + np.concatenate((np.linspace(poles[1] + EPS, mu_max, N_PER_BRANCH), mu_max + tail)), + ] + mu = np.concatenate(branch_samples) idx = np.arange(len(mu)) + pole_indices = np.cumsum([len(samples) for samples in branch_samples[:-1]]) # A pole where x0 has a zero standardized component vanishes and joins its neighbouring branches. - branches = np.split(idx, [k * N_PER_BRANCH for k in (1, 2) if pole_active[k - 1]]) + branches = np.split(idx, pole_indices[pole_active]) cmap = colormaps[COLORMAP] norm = Normalize(0, len(mu) - 1) @@ -115,8 +124,8 @@ def plot_trajectories(Q, x0): ax_x.scatter(*Q.x(root, x0), **style) if not degenerate: - for k, label in zip((1, 2), POLE_LABELS): - for i in (k * N_PER_BRANCH - 1, k * N_PER_BRANCH): + for pole_index, label in zip(pole_indices, POLE_LABELS): + for i in (pole_index - 1, pole_index): ax_x.text(*xs[i], label, **TEXT_STYLE) for k in range(Q.dim): point, direction = Q.pole_line(x0, k)