# Licensed under a MIT style license - see LICENSE.txt
"""MUSE-PHANGS plotting routines
"""
__authors__ = "Eric Emsellem"
__copyright__ = "(c) 2017, ESO + CRAL"
__license__ = "MIT License"
__contact__ = " <eric.emsellem@eso.org>"
# This module provides some functions to plot and check the data reduction
#
# Eric Emsellem adapted a March 2018 version, provided by Rebecca
# and adapted it to the pymusepipe package
# Importing modules
import numpy as np
# Standard modules
from os.path import join as joinpath
# Plotting routines
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.gridspec as gridspec
from .mpdaf_pipe import MuseSetImages, MuseSetSpectra
from .util_pipe import my_linear_model, get_flux_range
__version__ = '0.0.1 (23 March 2018)'
############################################################
# BEGIN
# The following parameters can be adjusted for the need of
# the specific pipeline to be used
############################################################
############################################################
# END
############################################################
PLOT = '\033[1;35;20m'
ENDC = '\033[0m'
[docs]def print_fig(text) :
print(PLOT + "# GraphPipeInfo " + ENDC + text)
[docs]def plot_compare_contours(data1, data2, plotwcs=None, labels=('Data1', 'Data2'), levels=None,
nlevels=10, fignum=1, namefig='dummy_contours.png', figfolder="",
savefig=False, **kwargs):
"""Creates a plot with the contours of two input datasets for comparison
Input
-----
data1
data2: 2d np.arrays
Input arrays to compare
plotwcs: WCS
WCS used to set the plot if provided
labels: tuple/list of 2 str
Labels for the plot
levels: list of floats
Levels to be used for the contours. Calculated if None.
fignum: int
Number for the figure
namefig: str
Name of the figure to be saved (if savefig is True)
figfolder: str
Name of the folder for the figure
savefig: bool
If True, will save the figure as namefig
Creates
-------
Plot with contours of the two input dataset
"""
np.seterr(divide='ignore', invalid='ignore')
# Getting the range of relevant fluxes
lowlevel_d1, highlevel_d1 = get_flux_range(data1)
fig, ax = open_new_wcs_figure(fignum, plotwcs)
# Defining the levels for MUSE
if levels is not None:
levels_d1 = levels
else:
levels_d1 = np.linspace(np.log10(lowlevel_d1),
np.log10(highlevel_d1),
nlevels)
# Plot contours for MUSE
cdata1 = ax.contour(np.log10(data1), levels_d1, colors='k',
origin='lower', linestyles='solid')
levels_d2 = cdata1.levels
# Plot contours for Ref
cdata2 = ax.contour(np.log10(data2), levels=levels_d2, colors='r',
origin='lower', alpha=0.5, linestyles='solid')
ax.set_aspect('equal')
h1, _ = cdata1.legend_elements()
h2, _ = cdata2.legend_elements()
ax.legend([h1[0], h2[0]], [labels[0], labels[1]])
if "title" in kwargs:
plt.title(kwargs.pop('title'))
plt.tight_layout()
if savefig:
plt.savefig(joinpath(figfolder, namefig))
np.seterr(divide='warn', invalid='warn')
[docs]def plot_compare_diff(data1, data2, plotwcs=None, figfolder="", percentage=5, fignum=1,
namefig="dummy_diff.ong", savefig=False, **kwargs):
"""
Parameters
----------
data1
data2
figfolder
fignum
namefig
savefig
kwargs
Returns
-------
"""
fig, ax = open_new_wcs_figure(fignum, plotwcs)
ratio = 100. * (data2 - data1) / (data1 + 1.e-12)
im = ax.imshow(ratio, vmin=-percentage, vmax=percentage)
cbar = fig.colorbar(im, shrink=0.8)
if "title" in kwargs:
plt.title(kwargs.pop('title'))
plt.tight_layout()
if savefig:
plt.savefig(joinpath(figfolder, namefig))
[docs]def plot_compare_cuts(data1, data2, labels=('X', 'Y'), figfolder="", fignum=1,
namefig="dummy_polypar.png", ncuts=11, savefig=False, **kwargs):
"""
Input
-----
data1
data2
label1
label2
figfolder
fignum
namefig
savefig
kwargs
Creates
-------
Plot with a comparison of the two data arrays using regular X and Y cuts
"""
fig, ax = open_new_wcs_figure(fignum)
# Getting the range of relevant fluxes
lowlevel_d1, highlevel_d1 = get_flux_range(data1)
diffima = (data2 - data1) * 200. / (lowlevel_d1 + highlevel_d1)
chunk_x = data1.shape[0] // (ncuts + 1)
chunk_y = data1.shape[1] // (ncuts + 1)
c1 = ax.plot(diffima[np.arange(ncuts) * chunk_x, :].T, 'k-', label=labels[0])
c2 = ax.plot(diffima[:, np.arange(ncuts) * chunk_y], 'r-', label=labels[1])
ax.legend(handles=[c1[0], c2[0]], loc=0)
ax.set_ylim(-20, 20)
ax.set_xlabel("[pixels]", fontsize=20)
ax.set_ylabel("[%]", fontsize=20)
if "title" in kwargs:
plt.title(kwargs.pop('title'))
plt.tight_layout()
if savefig:
plt.savefig(joinpath(figfolder, namefig))
[docs]def plot_polypar(polypar, labels=("Data 1","Data 2"), figfolder="", fignum=1,
namefig="dummy_polypar.png", savefig=False, **kwargs):
"""Creating a plot showing the normalisation arising from a polypar object
Parameters
----------
polypar
label1
label2
foldfig
namefig
Returns
-------
"""
# Opening the figure
fig, ax = open_new_wcs_figure(fignum)
# Getting the x, y to plot
(x, y) = (polypar.med[0][polypar.selection],
polypar.med[1][polypar.selection])
ax.plot(x, y, '.')
ax.set_xlabel(labels[0])
ax.set_ylabel(labels[1])
ax.plot(x, my_linear_model(polypar.beta, x), 'k')
if "title" in kwargs:
plt.title(kwargs.pop('title'))
plt.tight_layout()
if savefig:
plt.savefig(joinpath(figfolder, namefig))
#########################################################################
# Main class
# GraphMuse
#########################################################################
[docs]class GraphMuse(object):
"""Graphic output to check MUSE data reduction products
"""
def __init__(self, pdf_name='drs_check.pdf',
figsize=(10,14), rect_layout=[0, 0.03, 1, 0.95], verbose=True):
"""Initialise the class for plotting the outcome results
"""
self.verbose = verbose
self.pdf_name = pdf_name
self.pp = PdfPages(pdf_name)
self.figsize = figsize
self.rect_layout = rect_layout
self.npages = 0
[docs] def close(self):
self.pp.close()
[docs] def savepage(self):
self.pp.savefig()
plt.close()
self.npages += 1
[docs] def start_page(self):
"""Start the page
"""
if self.verbose :
print_fig("Starting page {0}".format(self.npages+1))
plt.figure(figsize=self.figsize)
[docs] def plot_page(self, list_data):
"""Plot a set of blocks, each made of a set of spectra or
images. This is for 1 page
It first counts the number of lines needed according to the
separation for images (default is 2 per line, each image taking 2 lines)
and spectra (1 spectrum per line over 2 columns)
"""
if len(list_data) == 0 :
print_fig("WARNING: datalist is empty, no plots will be created")
return
self.start_page()
nspectra_blocks, nimages_blocks = 0, 0
nlines = 0
if isinstance(list_data, MuseSetSpectra) | isinstance(list_data, MuseSetImages):
plt.suptitle(list_data.subtitle)
list_data = [list_data]
for data in list_data :
if isinstance(data, MuseSetSpectra):
nspectra_blocks += 1
nlines += data.__len__()
elif isinstance(data, MuseSetImages):
nimages_blocks += 1
nlines += 2 * data.__len__()
self.gs = gridspec.GridSpec(nlines, 2)
self.list_ax = []
self.count_lines = 0
for data in list_data :
if isinstance(data, MuseSetSpectra):
self.plot_set_spectra(data)
elif isinstance(data, MuseSetImages):
self.plot_set_images(data)
self.savepage()
[docs] def plot_set_spectra(self, set_of_spectra=None):
"""Plotting a set of spectra
Skipping the ones that are 'None'
"""
# Set of sky lines to plot when relevant - add_sky_lines to True
sky_lines = [5577., 6300., 6864., 7914., 8344., 8827.]
if set_of_spectra is None:
print_fig("ERROR: list of spectra is empty")
return
for spec in set_of_spectra:
self.list_ax.append(plt.subplot(self.gs[self.count_lines,:]))
self.count_lines += 1
if spec is not None:
spec.plot(title=spec.title, ax=self.list_ax[-1])
if spec.add_sky_lines:
for line in sky_lines:
plt.axvline(x=line, color=spec.color_sky, linestyle=spec.linestyle_sky, alpha=spec.alpha_sky)
plt.tight_layout(rect=self.rect_layout)
[docs] def plot_set_images(self, set_of_images=None):
"""Plotting a set of images
Skipping the ones that are 'None'
"""
if set_of_images is None :
print_fig("ERROR: list of images is empty")
return
for i in range(set_of_images.__len__()):
image = set_of_images[i]
count_cols = i%2
if image is not None:
self.list_ax.append(plt.subplot(self.gs[self.count_lines: self.count_lines + 2, count_cols]))
image.plot(scale=image.scale, vmin=image.vmin, colorbar=image.colorbar, title=image.title, ax=self.list_ax[-1])
self.count_lines += count_cols * 2
plt.tight_layout(rect=self.rect_layout)