"""
This module provides dictionaries for generating
`~matplotlib.colors.LinearSegmentedColormap`, and a dictionary of these
dictionaries.
"""
import pathlib
import matplotlib.colors as colors
import numpy as np
import astropy.units as u
__all__ = [
'aia_color_table', 'sswidl_lasco_color_table', 'eit_color_table',
'sxt_color_table', 'xrt_color_table', 'trace_color_table',
'sot_color_table', 'hmi_mag_color_table', 'suvi_color_table',
'rhessi_color_table', 'std_gamma_2', 'euvi_color_table', 'solohri_lya1216_color_table',
]
CMAP_DATA_DIR = pathlib.Path(__file__).parent.absolute() / 'data'
def create_cdict(r, g, b):
"""
Create the color tuples in the correct format.
"""
i = np.linspace(0, 1, r.size)
cdict = {name: list(zip(i, el / 255.0, el / 255.0))
for el, name in [(r, 'red'), (g, 'green'), (b, 'blue')]}
return cdict
def _cmap_from_rgb(r, g, b, name):
cdict = create_cdict(r, g, b)
return colors.LinearSegmentedColormap(name, cdict)
def cmap_from_rgb_file(name, fname):
"""
Create a colormap from a RGB .csv file.
The .csv file must have 3 equal-length columns of integer data, with values
between 0 and 255, which are the red, green, and blue values for the colormap.
Parameters
----------
name : str
Name of the colormap.
fname : str
Filename of data file. Relative to the sunpy colormap data directory.
Returns
-------
matplotlib.colors.LinearSegmentedColormap
"""
data = np.loadtxt(CMAP_DATA_DIR / fname, delimiter=',')
if data.shape[1] != 3:
raise RuntimeError(f'RGB data files must have 3 columns (got {data.shape[1]})')
return _cmap_from_rgb(data[:, 0], data[:, 1], data[:, 2], name)
def get_idl3():
# The following values describe color table 3 for IDL (Red Temperature)
return np.loadtxt(CMAP_DATA_DIR / 'idl_3.csv', delimiter=',')
[docs]
def solohri_lya1216_color_table():
solohri_lya1216 = get_idl3()
solohri_lya1216[:, 2] = solohri_lya1216[:, 0] * np.linspace(0, 1, 256)
return _cmap_from_rgb(*solohri_lya1216.T, 'SolO EUI HRI Lyman Alpha')
def create_aia_wave_dict():
idl_3 = get_idl3()
r0, g0, b0 = idl_3[:, 0], idl_3[:, 1], idl_3[:, 2]
c0 = np.arange(256, dtype='f')
c1 = (np.sqrt(c0) * np.sqrt(255.0)).astype('f')
c2 = (np.arange(256)**2 / 255.0).astype('f')
c3 = ((c1 + c2 / 2.0) * 255.0 / (c1.max() + c2.max() / 2.0)).astype('f')
aia_wave_dict = {
1600*u.angstrom: (c3, c3, c2),
1700*u.angstrom: (c1, c0, c0),
4500*u.angstrom: (c0, c0, b0 / 2.0),
94*u.angstrom: (c2, c3, c0),
131*u.angstrom: (g0, r0, r0),
171*u.angstrom: (r0, c0, b0),
193*u.angstrom: (c1, c0, c2),
211*u.angstrom: (c1, c0, c3),
304*u.angstrom: (r0, g0, b0),
335*u.angstrom: (c2, c0, c1)
}
return aia_wave_dict
[docs]
@u.quantity_input
def aia_color_table(wavelength: u.angstrom):
"""
Returns one of the fundamental color tables for SDO AIA images.
Based on aia_lct.pro part of SDO/AIA on SSWIDL written by Karel
Schrijver (2010/04/12).
Parameters
----------
wavelength : `~astropy.units.quantity`
Wavelength for the desired AIA color table.
"""
aia_wave_dict = create_aia_wave_dict()
try:
r, g, b = aia_wave_dict[wavelength]
except KeyError:
raise ValueError("Invalid AIA wavelength. Valid values are "
"1600,1700,4500,94,131,171,193,211,304,335.")
return _cmap_from_rgb(r, g, b, f'SDO AIA {str(wavelength):s}')
[docs]
@u.quantity_input
def eit_color_table(wavelength: u.angstrom):
"""
Returns one of the fundamental color tables for SOHO EIT images.
"""
# SOHO EIT Color tables
# EIT 171 IDL Name EIT Dark Bot Blue
# EIT 195 IDL Name EIT Dark Bot Green
# EIT 284 IDL Name EIT Dark Bot Yellow
# EIT 304 IDL Name EIT Dark Bot Red
try:
color = {171*u.angstrom: 'dark_blue', 195*u.angstrom: 'dark_green',
284*u.angstrom: 'yellow', 304*u.angstrom: 'dark_red',
}[wavelength]
except KeyError:
raise ValueError("Invalid EIT wavelength. Valid values are "
"171, 195, 284, 304.")
return cmap_from_rgb_file(f'SOHO EIT {str(wavelength):s}', f'eit_{color}.csv')
[docs]
def sswidl_lasco_color_table(number):
"""
Returns one of the SSWIDL-defined color tables for SOHO LASCO images.
This function is included to allow users to access the SSWIDL-
defined LASCO color tables provided by SunPy. It is recommended to
use the function 'lasco_color_table' to obtain color tables for use
with LASCO data and Helioviewer JP2 images.
"""
try:
return cmap_from_rgb_file(f'SOHO LASCO C{number}', f'lasco_c{number}.csv')
except OSError:
raise ValueError("Invalid LASCO number. Valid values are 2, 3.")
# Translated from the JP2Gen IDL SXT code lct_yla_gold.pro. Might be better
# to explicitly copy the numbers from the IDL calculation. This is a little
# more compact.
sxt_gold_r = np.concatenate((np.linspace(0, 255, num=185,
endpoint=False), 255 * np.ones(71)))
sxt_gold_g = 255 * (np.arange(256)**1.25) / (255.0**1.25)
sxt_gold_b = np.concatenate((np.zeros(185), 255.0 * np.arange(71) / 71.0))
grayscale = np.arange(256)
grayscale.setflags(write=False)
[docs]
def sxt_color_table(sxt_filter):
"""
Returns one of the fundamental color tables for Yokhoh SXT images.
"""
try:
r, g, b = {
'al': (sxt_gold_r, sxt_gold_g, sxt_gold_b),
'wh': (grayscale, grayscale, grayscale)
}[sxt_filter]
except KeyError:
raise ValueError("Invalid SXT filter type number. Valid values are "
"'al', 'wh'.")
return _cmap_from_rgb(r, g, b, f'Yohkoh SXT {sxt_filter.title():s}')
[docs]
def xrt_color_table():
"""
Returns the color table used for all Hinode XRT images.
"""
idl_3 = get_idl3()
r0, g0, b0 = idl_3[:, 0], idl_3[:, 1], idl_3[:, 2]
return _cmap_from_rgb(r0, g0, b0, 'Hinode XRT')
def cor_color_table(number):
"""
Returns one of the fundamental color tables for STEREO coronagraph images.
"""
# STEREO COR Color tables
if number not in [1, 2]:
raise ValueError("Invalid COR number. Valid values are " "1, 2.")
return cmap_from_rgb_file(f'STEREO COR{number}', f'stereo_cor{number}.csv')
[docs]
def trace_color_table(measurement):
"""
Returns one of the standard color tables for TRACE JP2 files.
"""
if measurement == 'WL':
return cmap_from_rgb_file(f'TRACE {measurement}', 'grayscale.csv')
try:
return cmap_from_rgb_file(f'TRACE {measurement}', f'trace_{measurement}.csv')
except OSError:
raise ValueError(
"Invalid TRACE filter waveband passed. Valid values are "
"171, 195, 284, 1216, 1550, 1600, 1700, WL")
[docs]
def sot_color_table(measurement):
"""
Returns one of the standard color tables for SOT files (following osdc
convention).
The relations between observation and color have been defined in
hinode.py
"""
idl_3 = get_idl3()
r0, g0, b0 = idl_3[:, 0], idl_3[:, 1], idl_3[:, 2]
try:
r, g, b = {
'intensity': (r0, g0, b0),
}[measurement]
except KeyError:
raise ValueError(
"Invalid (or not supported) SOT type. Valid values are: "
"intensity")
return _cmap_from_rgb(r, g, b, f'Hinode SOT {measurement:s}')
def iris_sji_color_table(measurement, aialike=False):
"""
Return the standard color table for IRIS SJI files.
"""
# base vectors for IRIS SJI color tables
c0 = np.arange(0, 256)
c1 = (np.sqrt(c0) * np.sqrt(255)).astype(np.uint8)
c2 = (c0**2 / 255.).astype(np.uint8)
c3 = ((c1 + c2 / 2.) * 255. / (np.max(c1) + np.max(c2) / 2.)).astype(
np.uint8)
c4 = np.zeros(256).astype(np.uint8)
c4[50:256] = (1 / 165. * np.arange(0, 206)**2).astype(np.uint8)
c5 = ((1 + c1 + c3.astype(np.uint)) / 2.).astype(np.uint8)
rr = np.ones(256, dtype=np.uint8) * 255
rr[0:176] = np.arange(0, 176) / 175. * 255.
gg = np.zeros(256, dtype=np.uint8)
gg[100:256] = np.arange(0, 156) / 155. * 255.
bb = np.zeros(256, dtype=np.uint8)
bb[150:256] = np.arange(0, 106) / 105. * 255.
agg = np.zeros(256, dtype=np.uint8)
agg[120:256] = np.arange(0, 136) / 135. * 255.
abb = np.zeros(256, dtype=np.uint8)
abb[190:256] = np.arange(0, 66) / 65. * 255.
if aialike:
color_table = {
'1330': (c1, c0, c2),
'1400': (rr, agg, abb),
'2796': (rr, c0, abb),
'2832': (c3, c3, c2),
}
else:
color_table = {
'1330': (rr, gg, bb),
'1400': (c5, c2, c4),
'2796': (c1, c3, c2),
'2832': (c0, c0, c2),
}
color_table.update({
'1600': (c1, c0, c0),
'5000': (c1, c1, c0),
'FUV': (rr, gg, bb),
'NUV': (c1, c3, c2),
'SJI_NUV': (c0, c0, c0)
})
try:
r, g, b = color_table[measurement]
except KeyError:
raise ValueError("Invalid IRIS SJI waveband. Valid values are \n" +
str(list(color_table.keys())))
return _cmap_from_rgb(r, g, b, f'IRIS SJI {measurement:s}')
[docs]
def hmi_mag_color_table():
"""
Returns an alternate HMI Magnetogram color table; from Stanford
University/JSOC.
This is used by default for the `~sunpy.map.sources.HMISynopticMap`.
But by default, for `~sunpy.map.sources.HMIMap` a grayscale colormap is used.
Examples
--------
.. plot::
:include-source:
:context: close-figs
import matplotlib.pyplot as plt
import astropy.units as u
import sunpy.map
from sunpy.data.sample import HMI_LOS_IMAGE
smap = sunpy.map.Map(HMI_LOS_IMAGE)
fig = plt.figure()
ax = fig.add_subplot(111, projection=smap)
smap.plot(axes=ax, cmap="hmimag", norm=None, vmin=-1500.0, vmax=1500.0)
plt.show()
References
----------
* `Stanford Colortable (pdf) <http://jsoc.stanford.edu/data/hmi/HMI_M.ColorTable.pdf>`__
"""
return cmap_from_rgb_file('SDO HMI magnetogram', 'hmi_mag.csv')
def stereo_hi_color_table(camera):
if camera not in [1, 2]:
raise ValueError("Valid HI cameras are 1 and 2")
return cmap_from_rgb_file(f'STEREO HI{camera}', f'hi{camera}.csv')
[docs]
@u.quantity_input
def suvi_color_table(wavelength: u.angstrom):
"""
Returns one of the fundamental color tables for SUVI images.
SUVI uses AIA color tables.
"""
aia_wave_dict = create_aia_wave_dict()
try:
if wavelength == 195*u.angstrom:
r, g, b = aia_wave_dict[193*u.angstrom]
elif wavelength == 284*u.angstrom:
r, g, b = aia_wave_dict[335*u.angstrom]
else:
r, g, b = aia_wave_dict[wavelength]
except KeyError:
raise ValueError(
"Invalid SUVI wavelength. Valid values are "
"94, 131, 171, 195, 284, 304."
)
return _cmap_from_rgb(r, g, b, f'GOES-R SUVI {str(wavelength):s}')
[docs]
def rhessi_color_table():
return cmap_from_rgb_file("rhessi", "rhessi.csv")
[docs]
def std_gamma_2():
return cmap_from_rgb_file("std_gamma_2", "std_gamma_2.csv")
[docs]
def euvi_color_table(wavelength: u.angstrom):
try:
return cmap_from_rgb_file(f'EUVI {str(wavelength)}', f'euvi_{int(wavelength.value)}.csv')
except OSError:
raise ValueError(
"Invalid EUVI wavelength. Valid values are "
"171, 195, 284, 304."
)