Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow named color palettes to be used by all sources. #724

Merged
merged 3 commits into from
Dec 14, 2021
Merged

Conversation

manthey
Copy link
Member

@manthey manthey commented Dec 13, 2021

This also increase the ability to handle css and named colors.

This generalized and supercedes #714. This closes #716.

Copy link
Contributor

@banesullivan banesullivan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is excellent! However, I'm having some trouble getting this to work:

No problem:

>>> large_image.open('/Users/bane/Desktop/TC_NG_SFBay_US_Geo.tif', style=json.dumps({"band": 1, "palette": ["#000", "#f00"]}))
<large_image_source_gdal.GDALFileTileSource object at 0x7fa138fe3430>
>>>

Problem:

>>> large_image.open('/Users/bane/Desktop/TC_NG_SFBay_US_Geo.tif', style=json.dumps({"band": 1, "palette": "viridis"}))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/bane/Software/kw/large_image/large_image/tilesource/__init__.py", line 140, in open
    return getTileSource(*args, **kwargs)
  File "/Users/bane/Software/kw/large_image/large_image/tilesource/__init__.py", line 128, in getTileSource
    return getTileSourceFromDict(AvailableTileSources, *args, **kwargs)
  File "/Users/bane/Software/kw/large_image/large_image/tilesource/__init__.py", line 113, in getTileSourceFromDict
    sourceName = getSourceNameFromDict(availableSources, pathOrUri, *args, **kwargs)
  File "/Users/bane/Software/kw/large_image/large_image/tilesource/__init__.py", line 98, in getSourceNameFromDict
    if availableSources[sourceName].canRead(pathOrUri, *args, **kwargs):
  File "/Users/bane/Software/kw/large_image/large_image/tilesource/base.py", line 2360, in canRead
    cls(path, *args, **kwargs)
  File "/Users/bane/Software/kw/large_image/large_image/cache_util/cache.py", line 193, in __call__
    instance = super().__call__(*args, **kwargs)
  File "/Users/bane/Software/kw/large_image/sources/gdal/large_image_source_gdal/__init__.py", line 156, in __init__
    self._setDefaultStyle()
  File "/Users/bane/Software/kw/large_image/sources/gdal/large_image_source_gdal/__init__.py", line 227, in _setDefaultStyle
    bstyle['palette'] = self.getHexColors(bstyle['palette'])
  File "/Users/bane/Software/kw/large_image/sources/gdal/large_image_source_gdal/__init__.py", line 358, in getHexColors
    return ['#%02X%02X%02X%02X' % tuple(clr) for clr in palette]
  File "/Users/bane/Software/kw/large_image/sources/gdal/large_image_source_gdal/__init__.py", line 358, in <listcomp>
    return ['#%02X%02X%02X%02X' % tuple(clr) for clr in palette]
TypeError: %X format: an integer is required, not numpy.float64
>>>

@manthey
Copy link
Member Author

manthey commented Dec 14, 2021

Should be fixed and tested now.

except (ImportError, ValueError):
pass
if palette is None:
raise TileSourceError('Value cannot be used as a color palette.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this should be a ValueError. Any particular reason that TileSourceError is used here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was that it prevents the tile source from working, but I'll change it to a ValueError.

@banesullivan
Copy link
Contributor

Would it make sense to fail back to a known value? For example, jet is a valid colormap if colorcet is installed. I'd prefer for this getPaletteColors to raise a ValueError if the named colormap does not exist and for large_image.open to safely fail back to a known palette issuing a warning if a bad palette name is passed

This might not be desired by everyone though...

@banesullivan
Copy link
Contributor

Also could we implement an isValidPalette() function to let downstream packages quickly check a palette?

@manthey
Copy link
Member Author

manthey commented Dec 14, 2021

Also could we implement an isValidPalette() function to let downstream packages quickly check a palette?

Sure -- this would just be

try:
    large_image.tilesource.utilities.getPaletteColors(<value>)
    return True
except ValueError:
    return False

@banesullivan
Copy link
Contributor

banesullivan commented Dec 14, 2021

Could we also have a getAvailablePalettes() method to list all available named palettes - this would be particularly useful when making front-end that let you select from a list of colormaps. For example what I have here: https://tileserver.banesullivan.com/?band=2&min=&max=&palette=magma

@manthey
Copy link
Member Author

manthey commented Dec 14, 2021

Would it make sense to fail back to a known value? For example, jet is a valid colormap if colorcet is installed. I'd prefer for this getPaletteColors to raise a ValueError if the named colormap does not exist and for large_image.open to safely fail back to a known palette issuing a warning if a bad palette name is passed

I'd rather not. It seems like passing something like #fffff should throw, rather than produce something unexpected.

@banesullivan
Copy link
Contributor

I'd rather not. It seems like passing something like #fffff should throw, rather than produce something unexpected.

Fair enough - leaving it as is works for me

@manthey
Copy link
Member Author

manthey commented Dec 14, 2021

Could we also have a getAvailablePalettes() method to list all available palettes - this would be particularly useful when making front-end that let you select from a list of colormaps. For example what I have here: https://tileserver.banesullivan.com/?band=2&min=&max=&palette=magma

Should such a function actually be called getAvailableNamedPalettes(), since it is basically a list of all of the palettable palettes and matplotlib palettes. Or, since you can pass a single color to get a palette, would such a function return named colors, too?

@banesullivan
Copy link
Contributor

getAvailableNamedPalettes

I was just thinking that -- yes

would such a function return named colors, too?

I think so, I think anything named should be returned (e.g., "red", etc.)

Add isValidPalette utility function.
@manthey
Copy link
Member Author

manthey commented Dec 14, 2021

getAvailableNamedPalettes

Let's push off adding getAvailableNamedPalettes into a separate PR.

@manthey
Copy link
Member Author

manthey commented Dec 14, 2021

@banesullivan There is a now a isValidPalette method.

@manthey manthey merged commit 42f49d9 into master Dec 14, 2021
@manthey manthey deleted the general-colors branch December 14, 2021 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generalize named colors and palettes
2 participants