Source code for pygappy.visualization

# -*- coding: utf-8 -*-
"""

Authors
-------
John Weaver <john.weaver.astro@gmail.com>


About
-----
Visulization tools to examine output from pca_projection routines.

Regions are defined from the SDSS/MaNGA MPL-6 sample by K. Rowlands (priv. comm.)

Known Issues
------------
None


"""

# ------------------------------------------------------------------------------
# Standard Packages
# ------------------------------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.path import Path

# ------------------------------------------------------------------------------
# Main Program
# ------------------------------------------------------------------------------
[docs]def model(data, wave, pcs, espec, error=None, mean=None, norm=1.0, nshow=3, show_labels=True, ax=None, normalize=False): """ Plots the output model fit of a PCA analysis. Parameters ---------- data : ndarray 1D spectrum with 'float' type. wave : ndarray 1D array of wavelengths. pcs : ndarray 1D array of principal components. espec : ndarray 2D array of eiegenspectra. error: ndarray, optional 1D error spectrum. Required for windows to work. mean : float, optional 1D mean spectrum, required for normgappy pcs. norm : float, optional Normalization constant, required for normgappy pcs. nshow : float, optional Number of eigenspectra to plot. Default is '3'. show_labels: bool, optional Turns on/off default x/y labels. Default is 'True'. normalize: bool, optional Turns on/off scaling normalization using norm. Default is 'False'. ax : :obj:axes, optional Existing ax object to draw on. Default is 'None' Returns ------- ax : axes-object Axes containing the model plot. fig : figure-object, optional If enabled, figure containing the axes. """ # deal with mean being None if mean is None: mean = np.zeros(len(espec[0])) # reconstruction pcs_nshow = norm * (mean + pcs[:nshow] @ espec[:nshow]) yp = norm * (mean + pcs[:, None] * espec) precon = norm * (mean + pcs @ espec) # setup figure if ax is None: fig, ax = plt.subplots(figsize=(10, 4)) if normalize: data = data / norm precon = precon / norm yp = yp / norm # plot stuff ax.plot(wave, data, c='k', alpha=1) ax.plot(wave, precon, c='r', ls='solid', alpha=1) for i in np.arange(nshow): color = next(ax._get_lines.prop_cycler)['color'] ax.plot(wave, yp[i], c=color, alpha=0.5) ax.text( 0.75 + (i * 0.05), 0.15, s='{:2.1f}'.format(pcs[i]), color=color, transform=ax.transAxes, horizontalalignment='right') ax.set_xlim([wave.min(), wave.max()]) if show_labels: ax.set_xlabel('Wavelength ($\AA$)', fontsize=15) ax.set_ylabel('Normalised Flux', fontsize=15) if ax is None: return fig, ax else: return ax
[docs]def pc_plane(logmass=1., ax=None, monochromatic=False): """ Returns an ax object with PC1/2 plane patches. Parameters ---------- logmass : float, optional Log10 stellar mass, used to select suitable region patches. Default is '1.', for low-mass. ax : axes-object, optional Existing axes object to populate. Default is 'None'. monochromatic : bool, optional If enabled, only shows region boundaries, not colors. Default is 'False'. Returns ------- ax : axes-object Axes containing the model plot. fig : figure-object, optional If enabled, figure containing the axes. """ # Make axis if ax is None: fig, ax = plt.subplots() fig.subplots_adjust(bottom=0.15) # Decide mass range if (logmass < 10): pca_patches = get_patches_lowmass() else: pca_patches = get_patches_highmass() for patch_verts in pca_patches: facecolor = patch_verts[1][1] if monochromatic: facecolor = "white" patch = patches.PathPatch( Path(patch_verts[0]), facecolor=facecolor, edgecolor='k', lw=1, alpha=0.2) ax.add_patch(patch) ax.set(xlim=(-7.1, 2), ylim=(-2.3, 2), aspect='auto') ax.set_xlabel('PC1 (4000$\AA$)', fontsize=15) ax.set_ylabel('PC2 (Excess H$\delta$ Abs.)', fontsize=15) if ax is None: return fig, ax else: return ax
[docs]def get_patches_lowmass(): """ Patches for PCA-defined regions calibrated with MPL-6. Suitable for low-z, with Log10(M*) < 10. Parameters ---------- None Returns ------- pca_patches_lowmass : ndarray Series of patches for low-mass objects. """ vertices_lowmass = { "psb_cut":0.39, \ "sb_vert1":-3.0, \ "sf_vert1":-5.8, \ "sf_vert2":-5.5, \ "sf_vert3":-2.2, \ "sf_vert4":-3.2, \ "green_vert1": -0.2, \ "green_vert2": -2.1, \ "junk_y_lower": -1.4, \ "junk_y_lower2": -3., \ "junk_y_upper": 2., \ "left_cut": -7.1, \ "right_cut": 2., \ } pca_patches_lowmass = [] # SF sf_verts = [ (vertices_lowmass["sf_vert1"], vertices_lowmass["junk_y_lower"]), # left, bottom (vertices_lowmass["sf_vert2"], vertices_lowmass["psb_cut"]), # left, top (vertices_lowmass["sf_vert3"], vertices_lowmass["psb_cut"]), # right, top (vertices_lowmass["sf_vert4"], vertices_lowmass["junk_y_lower"]) # right, bottom ] pca_patches_lowmass.append([sf_verts, ('SF','blue')]) # PSB psb_verts = [ (vertices_lowmass["left_cut"], vertices_lowmass["psb_cut"]), # left, bottom (vertices_lowmass["left_cut"], vertices_lowmass["junk_y_upper"]), # left, top (vertices_lowmass["green_vert1"] - 2., vertices_lowmass["junk_y_upper"]), # right, top (vertices_lowmass["green_vert1"], vertices_lowmass["psb_cut"]) # right, bottom ] pca_patches_lowmass.append([psb_verts, ('PSB', 'purple')]) # SB sb_verts = [ (vertices_lowmass["left_cut"], vertices_lowmass["sb_vert1"]), # left, bottom (vertices_lowmass["left_cut"], vertices_lowmass["psb_cut"]), # left, top (vertices_lowmass["sf_vert2"], vertices_lowmass["psb_cut"]), # right, top (vertices_lowmass["sf_vert1"] - 0.3, vertices_lowmass["sb_vert1"]) # right, bottom ] pca_patches_lowmass.append([sb_verts, ('SB', 'yellow')]) # Green valley green_verts = [ (vertices_lowmass["sf_vert4"], vertices_lowmass["junk_y_lower"]), # left, bottom (vertices_lowmass["sf_vert3"], vertices_lowmass["psb_cut"]), # left, top (vertices_lowmass["green_vert1"], vertices_lowmass["psb_cut"]), # right, top (vertices_lowmass["green_vert2"], vertices_lowmass["junk_y_lower"]) # right, bottom ] pca_patches_lowmass.append([green_verts, ('GV', 'green')]) # Red red_verts = [ (vertices_lowmass["green_vert2"], vertices_lowmass["junk_y_lower"]), # left, bottom (vertices_lowmass["green_vert1"] + 1.7, vertices_lowmass["junk_y_upper"]), # left, top (vertices_lowmass["right_cut"], vertices_lowmass["junk_y_upper"]), # right, top (vertices_lowmass["right_cut"], vertices_lowmass["junk_y_lower"]) # right, bottom ] pca_patches_lowmass.append([red_verts, ('QG', 'red')]) # Junk junk_verts = [ (vertices_lowmass["sf_vert1"] - 0.3, vertices_lowmass["junk_y_lower2"]), # left, bottom (vertices_lowmass["sf_vert2"] - 0.3, vertices_lowmass["junk_y_lower"]), # left, top (vertices_lowmass["right_cut"], vertices_lowmass["junk_y_lower"]), # right, top (vertices_lowmass["right_cut"], vertices_lowmass["junk_y_lower2"]) # right, bottom ] pca_patches_lowmass.append([junk_verts, ('JUNK', 'grey')]) return pca_patches_lowmass
[docs]def get_patches_highmass(): """ Patches for PCA-defined regions calibrated with MPL-6. Suitable for low-z, with Log10(M*) > 10. Parameters ---------- None Returns ------- pca_patches_highmass : ndarray Series of patches for high-mass objects. """ vertices_highmass = { "psb_cut":0.39, \ "sb_vert1":-1.9, \ "sf_vert1":-5.3-0.07, \ "sf_vert2":-5.0-0.07, \ "sf_vert3":-2.2-0.07, \ "sf_vert4":-3.2-0.07, \ "green_vert1": -0.3-0.07, \ "green_vert2": -2.0-0.07, \ "junk_y_lower": -1.2, \ "junk_y_lower2": -3., \ "junk_y_upper": 2., \ "left_cut": -7.1, \ "right_cut": 2.-0.07, \ } # PCA Paths pca_patches_highmass = [] # SF sf_verts = [ (vertices_highmass["sf_vert1"], vertices_highmass["junk_y_lower"]), # left, bottom (vertices_highmass["sf_vert2"], vertices_highmass["psb_cut"]), # left, top (vertices_highmass["sf_vert3"], vertices_highmass["psb_cut"]), # right, top (vertices_highmass["sf_vert4"], vertices_highmass["junk_y_lower"]) # right, bottom ] pca_patches_highmass.append([sf_verts, ('SF','blue')]) # PSB psb_verts = [ (vertices_highmass["left_cut"], vertices_highmass["psb_cut"]), # left, bottom (vertices_highmass["left_cut"], vertices_highmass["junk_y_upper"]), # left, top (vertices_highmass["green_vert1"] - 2., vertices_highmass["junk_y_upper"]), # right, top (vertices_highmass["green_vert1"], vertices_highmass["psb_cut"]) # right, bottom ] pca_patches_highmass.append([psb_verts, ('PSB', 'purple')]) # SB sb_verts = [ (vertices_highmass["left_cut"], vertices_highmass["sb_vert1"] - 1.07), # left, bottom (vertices_highmass["left_cut"], vertices_highmass["psb_cut"]), # left, top (vertices_highmass["sf_vert2"], vertices_highmass["psb_cut"]), # right, top (vertices_highmass["sf_vert1"] - 0.29, vertices_highmass["sb_vert1"] - 1.07) # right, bottom ] pca_patches_highmass.append([sb_verts, ('SB', 'yellow')]) # Green valley green_verts = [ (vertices_highmass["sf_vert4"], vertices_highmass["junk_y_lower"]), # left, bottom (vertices_highmass["sf_vert3"], vertices_highmass["psb_cut"]), # left, top (vertices_highmass["green_vert1"], vertices_highmass["psb_cut"]), # right, top (vertices_highmass["green_vert2"], vertices_highmass["junk_y_lower"]) # right, bottom ] pca_patches_highmass.append([green_verts, ('GV', 'green')]) # Red red_verts = [ (vertices_highmass["green_vert2"], vertices_highmass["junk_y_lower"]), # left, bottom (vertices_highmass["green_vert1"] + 4.9, vertices_highmass["junk_y_upper"]), # left, top (vertices_highmass["right_cut"] + 0.07, vertices_highmass["junk_y_upper"]), # right, top (vertices_highmass["right_cut"] + 0.07, vertices_highmass["junk_y_lower"]) # right, bottom ] pca_patches_highmass.append([red_verts, ('QG', 'red')]) # Junk junk_verts = [ (vertices_highmass["sf_vert1"] - 0.3, vertices_highmass["junk_y_lower2"]), # left, bottom (vertices_highmass["sf_vert2"] - 0.3, vertices_highmass["junk_y_lower"]), # left, top (vertices_highmass["right_cut"] + 0.07, vertices_highmass["junk_y_lower"]), # right, top (vertices_highmass["right_cut"] + 0.07, vertices_highmass["junk_y_lower2"]) # right, bottom ] pca_patches_highmass.append([junk_verts, ('JUNK', 'grey')]) return pca_patches_highmass