Adding dynamic legend based on colormap #509
Replies: 4 comments 4 replies
-
👋 @dvd3v Sounds like a nice addition (as long as we avoid adding new requirements). I'm not quite sure about the best approach here tbh. I'm not sure we want this directly within the def register_legend_endpoint(app: FastAPI, **kwargs):
@app.get("/legend")
def get_legend_graphic(
colormap: Depends(ColorMapParams)
min: int,
max: int,
):
... and then let the user register this endpoint to the main application |
Beta Was this translation helpful? Give feedback.
-
Just sharing what I used for making an image of the colorbar next to the map for reference: # FastAPI endpoint
@app.get("/colorbar/{cmap_name}")
async def get_colorbar(cmap_name: str):
"""Get a WEBP image of a matplotlib colorbar."""
try:
colorbar_bytes = generate_colorbar(cmap_name)
return Response(content=colorbar_bytes, media_type="image/webp")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@cache
def generate_colorbar(cmap_name: str) -> bytes:
"""Generate a colorbar image using a specified matplotlib colormap.
Parameters
----------
cmap_name : str
Name of the colormap to be used.
Returns
-------
bytes
WEBP image data as bytes
"""
from io import BytesIO
import matplotlib.pyplot as plt
import numpy as np
gradient = np.array([[0, 1]])
fig, ax = plt.subplots(figsize=(9, 1.5))
ax.imshow(gradient, cmap=cmap_name)
ax.set_visible(False)
# Create colorbar in a tightly fitted axis
cax = fig.add_axes([0.05, 0.2, 0.9, 0.6])
colorbar = plt.colorbar(
ax.imshow(gradient, cmap=cmap_name), cax=cax, orientation="horizontal"
)
colorbar.set_ticks([])
# Adjust subplot parameters and apply tight layout
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
buf = BytesIO()
plt.savefig(buf, format="webp", bbox_inches="tight", pad_inches=0)
plt.close(fig)
buf.seek(0)
return buf.read() I also had to add a hack to get around the difference in case sensitivity (e.g. titiler wants "rdbu", matplotlib wants "RbBu") def desensitize_mpl_case():
"""Make `cmap` case insensitive by registering repeated cmap names."""
import matplotlib as mpl
cmap_names = list(mpl.colormaps)
for name in cmap_names:
if name.lower() in mpl.colormaps:
continue
mpl.colormaps.register(mpl.colormaps[name], name=name.lower()) |
Beta Was this translation helpful? Give feedback.
-
We have a similar need for our STAC/TiTiler-based application VEDA UI that currently among others powers https://earth.gov. However, we do not want a static legend image generated but just a couple of hex codes extracted from the colormap, similar to this code snippet: import matplotlib as mpl
import numpy as np
cmap = mpl.colormaps['Spectral_r']
for step in np.linspace(0, 1, 5):
print(mpl.colors.rgb2hex(cmap(step))) Our frontend application can then generate a nice interactive UI component for the legend, as it already does. So I think we could provide a pretty generic feature by adding an endpoint that accepts the TiTiler parameters that specify a colormap, plus a number of stops to extract, or the coordinates (pixel values) for those stops. Would it make sense to add this as a default endpoint in TiTiler? |
Beta Was this translation helpful? Give feedback.
-
Dear all, I've started #796 to implement 2 new endpoints:
Would be lovely to have some feedback. Note: I haven't implemented |
Beta Was this translation helpful? Give feedback.
-
Hi,
We are using Titiler for showing various data data maps, like elevation rasters. I would like to build a 'GetLegendGraphic' endpoint where we can get a legend based on scaling and/or custom (rio-tiler) colormaps. What would be the best approach create such a get legend endpoint? My idea is to use the band statistics and the rio_tiler.colormap lib to get the cmap for the chosen colormap. Is it possible to get these cmap values for the default rio-tiler's colormaps?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions