diff --git a/src/goes2go/accessors.py b/src/goes2go/accessors.py index b586123..4c1109b 100644 --- a/src/goes2go/accessors.py +++ b/src/goes2go/accessors.py @@ -741,6 +741,75 @@ def DayCloudPhase(self): return ds["DayCloudPhase"] + def DayCloudPhaseEUMETSAT(self): + """Create the Day Cloud Phase EUMETSAT RGB. + + (See `Quick Guide `__ for reference) + + .. image:: /_static/DayCloudPhaseEUMETSAT.png + + + """ + ds = self._obj + + # Load the three channels into appropriate R, G, and B variables + R, G, B = self._load_RGB_channels((5, 6, 2)) + + # _normalize each channel by the appropriate range of values. (Clipping happens inside function) + R = _normalize(R, 0, .5) + G = _normalize(G, 0, .5) + B = _normalize(B, 0, 1) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + ds["DayCloudPhaseEUMETSAT"] = (("y", "x", "rgb"), RGB) + ds["rgb"] = ["R", "G", "B"] + ds["DayCloudPhaseEUMETSAT"].attrs["Quick Guide"] = ( + "https://eumetrain.org/sites/default/files/2023-01/CloudPhaseRGB.pdf" + ) + ds["DayCloudPhaseEUMETSAT"].attrs["long_name"] = "Day Cloud Phase EUMETSAT" + + return ds["DayCloudPhaseEUMETSAT"] + + def DayCloudType(self): + """Create the Day Cloud Phase Type RGB. + + (See `Quick Guide `__ for reference) + + .. image:: /_static/DayCloudType.png + + + """ + ds = self._obj + + # Load the three channels into appropriate R, G, and B variables + R, G, B = self._load_RGB_channels((4, 2, 5)) + + # _normalize each channel by the appropriate range of values. (Clipping happens inside function) + R = _normalize(R, 0, .1) + G = _normalize(G, 0, .8) + B = _normalize(B, 0, .8) + + # Apply the gamma correction to Red channel. + # corrected_value = value^(1/gamma) + gamma = 1.5 + R = _gamma_correction(R, gamma) + gamma = .75 + G = _gamma_correction(G, gamma) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + ds["DayCloudType"] = (("y", "x", "rgb"), RGB) + ds["rgb"] = ["R", "G", "B"] + ds["DayCloudType"].attrs["Quick Guide"] = ( + "https://eumetrain.org/sites/default/files/2021-05/CloudTypeRGB.pdf" + ) + ds["DayCloudType"].attrs["long_name"] = "Day Cloud Type" + + return ds["DayCloudType"] + def DayConvection(self): """Create the Day Convection RGB. @@ -1309,3 +1378,40 @@ def SeaSpray(self, **kwargs): ds["SeaSpray"].attrs["long_name"] = "Sea Spray" return ds["SeaSpray"] + + def BlowingSnow(self, **kwargs): + """Create the Blowing Snow RGB. + + (See `Quick Guide `__ for reference) + + .. image:: /_static/BlowingSnow.png + + """ + ds = self._obj + + # Load the three channels into appropriate R, G, and B variables + R = ds["CMI_C02"].data + G = ds["CMI_C05"].data + B = ds["CMI_C07"].data - ds["CMI_C13"].data + + # Normalize each channel by the appropriate range of values. e.g. R = (R-minimum)/(maximum-minimum) + R = _normalize(R, 0, .5) # values for this channel go from 0 to 1. + G = _normalize(G, 0, 0.2) # values for this channel go from 0 to 1. + B = _normalize(B, 0, 30) + + # Apply a gamma correction to each R, G, B channel + R = _gamma_correction(R, 1/0.7) + G = _gamma_correction(G, 1.0) + B = _gamma_correction(B, 1/0.7) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + ds["BlowingSnow"] = (("y", "x", "rgb"), RGB) + ds["rgb"] = ["R", "G", "B"] + ds["BlowingSnow"].attrs["Quick Guide"] = ( + "https://rammb2.cira.colostate.edu/wp-content/uploads/2024/11/GOES-BlowingSnowRGB1_QuickGuide_24April2024.pdf" + ) + ds["BlowingSnow"].attrs["long_name"] = "Blowing Snow" + + return ds["BlowingSnow"] diff --git a/src/goes2go/rgb.py b/src/goes2go/rgb.py index 7f66f68..763af71 100644 --- a/src/goes2go/rgb.py +++ b/src/goes2go/rgb.py @@ -20,7 +20,10 @@ - TrueColor - FireTemperature - AirMass + - BlowingSnow - DayCloudPhase + - DayCloudPhaseEUMETSAT + - DayCloudType - DayConvection - DayCloudConvection - DayLandCloud @@ -30,6 +33,7 @@ - DaySnowFog - NighttimeMicrophysics - Dust + - SeaSpray - SulfurDioxide - Ash - SplitWindowDifference @@ -562,6 +566,42 @@ def AirMass(C, **kwargs): return rgb_as_dataset(C, RGB, "Air Mass", **kwargs) +def BlowingSnow(C, **kwargs): + """ + Blowing Snow RGB: + (See `Quick Guide `__ for reference) + + .. image:: /_static/BlowingSnow.png + + Parameters + ---------- + C : xarray.Dataset + A GOES ABI multichannel file opened with xarray. + \*\*kwargs : + Keyword arguments for ``rgb_as_dataset`` function. + - latlon : derive latitude and longitude of each pixel + + """ + # Load the three channels into appropriate R, G, and B variables + R = C["CMI_C02"].data + G = C["CMI_C05"].data + B = C["CMI_C07"].data - C["CMI_C13"].data + + # Normalize each channel by the appropriate range of values. e.g. R = (R-minimum)/(maximum-minimum) + R = normalize(R, 0, 0.5) + G = normalize(G, 0, 0.2) + B = normalize(B, 0, 30) + + # Apply the gamma correction to Red channel. + # corrected_value = value^(1/gamma) + gamma = 1/.7 + R = gamma_correction(R, gamma) + B = gamma_correction(B, gamma) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + return rgb_as_dataset(C, RGB, "Blowing Snow", **kwargs) def DayCloudPhase(C, **kwargs): """ @@ -595,6 +635,71 @@ def DayCloudPhase(C, **kwargs): return rgb_as_dataset(C, RGB, "Day Cloud Phase", **kwargs) +def DayCloudPhaseEUMETSAT(C, **kwargs): + """ + Day Cloud Phase EUMETSAT RGB: + (See `Quick Guide `__ for reference) + + .. image:: /_static/DayCloudPhaseEUMETSAT.png + + Parameters + ---------- + C : xarray.Dataset + A GOES ABI multichannel file opened with xarray. + \*\*kwargs : + Keyword arguments for ``rgb_as_dataset`` function. + - latlon : derive latitude and longitude of each pixel + + """ + # Load the three channels into appropriate R, G, and B variables + R, G, B = load_RGB_channels(C, (5, 6, 2)) + + # Normalize each channel by the appropriate range of values. (Clipping happens inside function) + R = normalize(R, 0, .5) + G = normalize(G, 0, .5) + B = normalize(B, 0, 1) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + return rgb_as_dataset(C, RGB, "Day Cloud Phase EUMETSAT", **kwargs) + +def DayCloudType(C, **kwargs): + """ + Day Cloud Type RGB: + (See `Quick Guide `__ for reference) + + .. image:: /_static/DayCloudType.png + + Parameters + ---------- + C : xarray.Dataset + A GOES ABI multichannel file opened with xarray. + \*\*kwargs : + Keyword arguments for ``rgb_as_dataset`` function. + - latlon : derive latitude and longitude of each pixel + + """ + # Load the three channels into appropriate R, G, and B variables + R, G, B = load_RGB_channels(C, (4, 2, 5)) + + # Normalize each channel by the appropriate range of values. (Clipping happens inside function) + R = normalize(R, 0, .1) + G = normalize(G, 0, .8) + B = normalize(B, 0, .8) + + # Apply the gamma correction to Red channel. + # corrected_value = value^(1/gamma) + gamma = 1.5 + R = gamma_correction(R, gamma) + gamma = .75 + G = gamma_correction(G, gamma) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + return rgb_as_dataset(C, RGB, "Day Cloud Type", **kwargs) + def DayConvection(C, **kwargs): """ @@ -910,6 +1015,42 @@ def Dust(C, **kwargs): return rgb_as_dataset(C, RGB, "Dust", **kwargs) +def SeaSpray(C, **kwargs): + """ + Sea Spray RGB: + (See `Quick Guide `__ for reference) + + .. image:: /_static/SeaSpray.png + + Parameters + ---------- + C : xarray.Dataset + A GOES ABI multichannel file opened with xarray. + \*\*kwargs : + Keyword arguments for ``rgb_as_dataset`` function. + - latlon : derive latitude and longitude of each pixel + + """ + # Load the three channels into appropriate R, G, and B variables + R = C["CMI_C07"].data - C["CMI_C13"].data + G = C["CMI_C03"].data + B = C["CMI_C02"].data + + # Normalize values + R = normalize(R, 0, 5) + G = normalize(G, .01, .09) + B = normalize(B, .02, .12) + + # Apply a gamma correction to the image + gamma = 1/.6 + G = gamma_correction(G, gamma) + B = gamma_correction(B, gamma) + + # The final RGB array :) + RGB = np.dstack([R, G, B]) + + return rgb_as_dataset(C, RGB, "Sea Spray", **kwargs) def SulfurDioxide(C, **kwargs): """