Skip to content

Commit cbb28e3

Browse files
Added gradient color legend with feature for user specific color scheme alongside
1 parent b153b09 commit cbb28e3

File tree

1 file changed

+42
-52
lines changed

1 file changed

+42
-52
lines changed

python/grass/jupyter/interactivemap.py

Lines changed: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -381,22 +381,24 @@ def add_layer_control(self, **kwargs):
381381
else:
382382
self.layer_control_object = self._ipyleaflet.LayersControl(**kwargs)
383383

384-
def add_legend(self, raster, position="bottomright"):
385-
import subprocess
386-
387-
# Getting all in-built colour scheme for elevations
388-
all_colours = subprocess.check_output(f"r.colors.out map={raster}", shell=True).decode("utf-8").strip()
389-
colors = {}
390-
last_ht = None
391-
for colour in all_colours.split("\n"):
392-
if "nv" in colour or "default" in colour:
393-
continue
394-
elev_col_info = colour.split()
395-
ht = float(elev_col_info[0])
396-
rgb = elev_col_info[1]
397-
label = f"{last_ht:.1f} - {ht:.1f} m" if last_ht else f"≤ {ht:.1f} m"
398-
colors[label] = f"rgb({rgb.replace(':', ',')})"
399-
last_ht = ht
384+
def add_legend(self, raster, color="viridis", position="bottomright"):
385+
from grass.tools import Tools
386+
import matplotlib.pyplot as plt
387+
388+
tools = Tools()
389+
# Setting color scheme for raster rendering
390+
tools.r_colors(map=raster, color=color)
391+
# Retrieving all the colors based on the above set color scheme
392+
color_maps = tools.r_colors_out(map=raster, format='json')["table"]
393+
# Joining the retrieved colors to form smooth gradient.
394+
colors = [item["color"] for item in color_maps]
395+
css_gradient = ", ".join(colors)
396+
# Setting some interval ticks to compare values relatively.
397+
info = tools.r_info(map=raster, format='json')
398+
minv = float(info["min"])
399+
maxv = float(info["max"])
400+
num_ticks = 5
401+
ticks = [minv + i * (maxv - minv) / (num_ticks - 1) for i in range(num_ticks)]
400402

401403
# Position Coordinates
402404
position_map = {
@@ -410,13 +412,10 @@ def add_legend(self, raster, position="bottomright"):
410412
# Creating legend
411413
legend_html = f"""
412414
<div style="
413-
display: flex;
414-
flex-direction: column;
415-
align-items: center;
415+
width: 300px;
416416
position: absolute;
417417
{pos_style}
418418
z-index: 9999;
419-
min-width: 130px;
420419
padding: 5px;
421420
background: rgba(255, 255, 255, 0.3);
422421
backdrop-filter: blur(8px);
@@ -428,35 +427,24 @@ def add_legend(self, raster, position="bottomright"):
428427
font-size: 12px;
429428
">
430429
<div style="
431-
background: rgba(255, 255, 255, 0.5)
432430
font-size: 14px;
433431
font-weight: bold;
434-
padding-bottom: 6px;
435-
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
436432
color: black;
437433
">
438-
{raster.capitalize()} Map
434+
{info["title"]}
439435
</div>
440-
<div style="display: flex; flex-direction: column; gap: 6px;">
441-
"""
442436
443-
for label, color in colors.items():
444-
legend_html += f"""
445-
<div style="display: flex; align-items: center; gap: 10px;">
446-
<div style="
447-
width: 20px;
448-
height: 20px;
449-
background: {color};
450-
border-radius: 4px;
451-
border: 1px solid rgba(255,255,255,0.5);
452-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
453-
"></div>
454-
<span style="color: black;">{label}</span>
455-
</div>
456-
"""
457-
458-
legend_html += """
437+
<div style="
438+
height: 15px;
439+
border-radius: 6px;
440+
border: 1px solid #999;
441+
background: linear-gradient(to right, {css_gradient});
442+
"></div>
443+
444+
<div style="display: flex; justify-content: space-between;">
445+
{''.join([f'<span>{round(t,1)}</span>' for t in ticks])}
459446
</div>
447+
460448
</div>
461449
"""
462450

@@ -469,26 +457,28 @@ def add_legend(self, raster, position="bottomright"):
469457
return self
470458

471459
elif self._folium:
472-
from branca.element import MacroElement
460+
import folium
461+
from folium.map import MacroElement
473462
from jinja2 import Template
474463

475464
class Legend(MacroElement):
476465
def __init__(self, html):
477466
super().__init__()
478467
self.html = html
479468
self._name = "Legend"
480-
481-
def render(self, **kwargs):
482-
template = Template("""
483-
{% macro html(this, kwargs) %}
484-
{{ this.html|safe }}
469+
self._template = Template("""
470+
{% macro script(this, kwargs) %}
471+
var legend = $(`{{ this.html | safe }}`);
472+
$('body').append(legend);
485473
{% endmacro %}
486474
""")
487-
return template.module.html(self)
488475

489-
self.map.get_root().add_child(Legend(legend_html))
490-
return self
476+
def render(self, **kwargs):
477+
super().render(**kwargs)
491478

479+
legend = Legend(legend_html)
480+
self.map.add_child(legend)
481+
return self
492482

493483
else:
494484
return self
@@ -959,4 +949,4 @@ def clear_popups(self):
959949
"""Clears the popups."""
960950
for item in reversed(list(self.map.layers)):
961951
if isinstance(item, self._ipyleaflet.Popup):
962-
self.map.remove(item)
952+
self.map.remove(item)

0 commit comments

Comments
 (0)