Skip to content

Commit

Permalink
ADD: Transparency options for geotiff writer
Browse files Browse the repository at this point in the history
  • Loading branch information
qubitqualia committed Dec 15, 2023
1 parent 90a9b93 commit 98c04b1
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 6 deletions.
39 changes: 35 additions & 4 deletions pyart/io/output_to_geotiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def write_grid_geotiff(
warp=False,
sld=False,
use_doublequotes=True,
transparent_bg=True,
opacity=1.0
):
"""
Write a Py-ART Grid object to a GeoTIFF file.
Expand Down Expand Up @@ -100,6 +102,17 @@ def write_grid_geotiff(
False - Use single quotes instead.
transparent_bg : bool, optional
True - Sets alpha value of masked pixels to zero producing a
transparent background
False - Sets alpha value of masked pixels to value assigned by
opacity parameter
opacity : float, optional
Alpha value to be assigned to all pixels (except for transparent background)
Value must be between 0 (transparent) and 1 (opaque)
"""
if not IMPORT_FLAG:
raise MissingOptionalDependency("GDAL not detected, GeoTIFF output failure!")
Expand Down Expand Up @@ -156,9 +169,10 @@ def write_grid_geotiff(
)
else:
# Assign data RGB levels based on value relative to vmax/vmin
rarr, garr, barr = _get_rgb_values(data, vmin, vmax, color_levels, cmap)
rarr, garr, barr, aarr = _get_rgb_values(data, vmin, vmax, color_levels, cmap,
transparent_bg, opacity)
dst_ds = out_driver.Create(
ofile, data.shape[1], data.shape[0], 3, gdal.GDT_Byte
ofile, data.shape[1], data.shape[0], 4, gdal.GDT_Byte
)

# Common Projection and GeoTransform
Expand All @@ -172,6 +186,7 @@ def write_grid_geotiff(
dst_ds.GetRasterBand(1).WriteArray(rarr[::-1, :])
dst_ds.GetRasterBand(2).WriteArray(garr[::-1, :])
dst_ds.GetRasterBand(3).WriteArray(barr[::-1, :])
dst_ds.GetRasterBand(4).WriteArray(aarr[::-1, :])
dst_ds.FlushCache()
dst_ds = None

Expand Down Expand Up @@ -202,7 +217,7 @@ def write_grid_geotiff(
shutil.move(ofile + "_tmp.tif", ofile)


def _get_rgb_values(data, vmin, vmax, color_levels, cmap):
def _get_rgb_values(data, vmin, vmax, color_levels, cmap, transpbg, op):
"""
Get RGB values for later output to GeoTIFF, given a 2D data field,
display min/max and color table info. Missing data get numpy.nan.
Expand All @@ -221,6 +236,11 @@ def _get_rgb_values(data, vmin, vmax, color_levels, cmap):
with steps << 255 (e.g., hydrometeor ID).
cmap : str or matplotlib.colors.Colormap object, optional
Colormap to use for RGB output or SLD file.
transpbg : bool
True - generate alpha channel with masked values set to 0
False - generate alpha channel with masked values set to op value
op : float
Opacity of image, value of 0 is transparent, value of 1 is opaque
Returns
-------
Expand All @@ -230,6 +250,8 @@ def _get_rgb_values(data, vmin, vmax, color_levels, cmap):
Blue channel indices (range = 0-255).
garr : numpy.ndarray object, dtype int
Green channel indices (range = 0-255).
aarr : numpy.ndarray object, dtype int
Alpha channel indices (range = 0-255).
"""
frac = (data - vmin) / float(vmax - vmin)
Expand All @@ -242,6 +264,7 @@ def _get_rgb_values(data, vmin, vmax, color_levels, cmap):
rarr = []
garr = []
barr = []
aarr = []
cmap = plt.cm.get_cmap(cmap)
for val in index:
if not np.isnan(val):
Expand All @@ -250,14 +273,22 @@ def _get_rgb_values(data, vmin, vmax, color_levels, cmap):
rarr.append(int(np.round(r * 255)))
garr.append(int(np.round(g * 255)))
barr.append(int(np.round(b * 255)))
aarr.append(int(np.round(op * 255)))
else:
rarr.append(np.nan)
garr.append(np.nan)
barr.append(np.nan)
if not transpbg:
aarr.append(int(np.round(op * 255)))
else:
aarr.append(0)


rarr = np.reshape(rarr, data.shape)
garr = np.reshape(garr, data.shape)
barr = np.reshape(barr, data.shape)
return rarr, garr, barr
aarr = np.reshape(aarr, data.shape)
return rarr, garr, barr, aarr


def _create_sld(cmap, vmin, vmax, filename, color_levels=None):
Expand Down
71 changes: 69 additions & 2 deletions tests/io/test_output_to_geotiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import pytest

import pyart
from PIL import Image
from pathlib import Path

# TODO : inspect the output file to verify their contents, currently only the
# fact that something was written is confirmed
Expand All @@ -16,14 +18,15 @@ def test__get_rgb_values_nan():
data[5] = np.nan
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
rarr, barr, garr = pyart.io.output_to_geotiff._get_rgb_values(
data, 0, 10, None, "jet"
rarr, barr, garr, aarr = pyart.io.output_to_geotiff._get_rgb_values(
data, 0, 10, None, "jet", False, 1
)
assert np.isnan(rarr[5])
assert np.isnan(barr[5])
assert np.isnan(garr[5])



def test_raise_missingoptionaldepedency():
backup = bool(pyart.io.output_to_geotiff.IMPORT_FLAG)
pyart.io.output_to_geotiff.IMPORT_FLAG = False
Expand Down Expand Up @@ -52,6 +55,20 @@ def make_tiny_grid():
grid.fields = {"reflectivity": rdic}
return grid

def make_tiny_grid_with_mask():
"""Make a tiny grid."""
grid_shape = (2, 10, 8)
grid_limits = ((0, 500), (-400000, 400000), (-300000, 300000))
grid = pyart.testing.make_empty_grid(grid_shape, grid_limits)
fdata = np.zeros((2, 10, 8), dtype="float32")
fdata[:, 2:-2, 1:-1] = 10.0
fdata[:, 3:-3, 2:-2] = 20.0
fdata[:, 4:-4, 3:-3] = 30.0
fdata[1] += 5
fdata[fdata == 0] = np.nan
rdic = {"data": fdata, "long_name": "reflectivity", "units": "dBz"}
grid.fields = {"reflectivity": rdic}
return grid

@pytest.mark.skipif(
not pyart.io.output_to_geotiff.IMPORT_FLAG, reason="GDAL is not installed."
Expand Down Expand Up @@ -132,3 +149,53 @@ def test_write_grid_geotiff_sld():
def test_write_grid_geotiff_missing_field():
grid = make_tiny_grid()
pytest.raises(KeyError, pyart.io.write_grid_geotiff, grid, "test.foo", "foobar")

@pytest.mark.skipif(
not pyart.io.output_to_geotiff.IMPORT_FLAG, reason="GDAL is not installed."
)
def test_write_grid_geotiff_transparent_background():
grid = make_tiny_grid_with_mask()

try:
with pyart.testing.InTemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
outname = tmp / "transparent_bg.tif"
pyart.io.write_grid_geotiff(grid, str(outname), "reflectivity",
rgb=True,
cmap='pyart_HomeyerRainbow',
vmin=0,
vmax=40,
transparent_bg=True,
opacity=1)
imgname = outname.rename(tmp / "transparent_bg.tiff")
img = Image.open(imgname)
img.show()
except PermissionError:
pass



@pytest.mark.skipif(
not pyart.io.output_to_geotiff.IMPORT_FLAG, reason="GDAL is not installed."
)
def test_write_grid_geotiff_opacity():
grid = make_tiny_grid_with_mask()
try:
with pyart.testing.InTemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
outname = tmp / "opacity.tif"
pyart.io.write_grid_geotiff(grid, str(outname), 'reflectivity',
rgb=True,
cmap='pyart_HomeyerRainbow',
vmin=0,
vmax=40,
transparent_bg=False,
opacity=0.25)
imgname = outname.rename(tmp / "opacity.tiff")
img = Image.open(imgname)
img.show()
except PermissionError:
pass



0 comments on commit 98c04b1

Please sign in to comment.