mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 22:50:25 -05:00
#14192 Python: Update discrete property color legend in place instead of delete/create
Address review feedback on #14199: deleting and recreating the legend left views bound to the old legend pointing at a deleted object. Add RimColorLegendCollection::updateColorLegend and a matching UpdateColorLegend scriptable method that mutate the existing custom legend (name and items) so referring views keep their binding and are notified once. A new legend is only created when none is registered for the result or the registered legend is a standard legend. set_discrete_property_category_names now performs a single atomic call instead of delete + create + per-item appends. The empty-dict removal path still uses DeleteColorLegend.
This commit is contained in:
1 parent
5a083331b0
commit
a4fe22508a
8 files changed
+200
-17
No files matched your search
@@ -3,8 +3,9 @@ Category name/color binding for discrete (INTEGER) grid cell results.
|
||||
|
||||
Provides a convenience API on Case for labeling integer result values with
|
||||
human-readable names and optional colors. Internally, this reuses the existing
|
||||
ColorLegend infrastructure: a new custom ColorLegend is created and registered
|
||||
as the default legend for the (case, resultName) pair. When the property is
|
||||
ColorLegend infrastructure: a custom ColorLegend is registered as the default
|
||||
legend for the (case, resultName) pair, and repeated calls update that legend
|
||||
in place so views referencing it keep their binding. When the property is
|
||||
shown in a 3D view, the legend's item names are used as the category labels.
|
||||
"""
|
||||
|
||||
@@ -55,10 +56,14 @@ def set_discrete_property_category_names(
|
||||
data_type="INTEGER") or set_active_cell_property(..., data_type="INTEGER")
|
||||
to display text labels instead of raw integers in the 3D view legend.
|
||||
|
||||
Repeated calls for the same property update the existing color legend in
|
||||
place, so views referencing the legend keep their binding.
|
||||
|
||||
Arguments:
|
||||
property_name (str): Name of the discrete property result.
|
||||
value_names (Dict[int, str]): Mapping from integer value to label.
|
||||
An empty dict removes any existing mapping for this property.
|
||||
Labels must not contain commas. An empty dict removes any
|
||||
existing mapping for this property.
|
||||
value_colors (Optional[Dict[int, str]]): Optional per-value colors as
|
||||
strings accepted by QColor (e.g. "red", "#ff8800"). Values without
|
||||
a color entry get an auto-assigned palette color.
|
||||
@@ -66,7 +71,7 @@ def set_discrete_property_category_names(
|
||||
Defaults to the property name.
|
||||
|
||||
Returns:
|
||||
The created ColorLegend, or None if value_names was empty.
|
||||
The created or updated ColorLegend, or None if value_names was empty.
|
||||
"""
|
||||
project = self.ancestor(Project)
|
||||
if project is None:
|
||||
@@ -76,35 +81,35 @@ def set_discrete_property_category_names(
|
||||
if collection is None:
|
||||
raise RuntimeError("Could not find ColorLegendCollection in project")
|
||||
|
||||
collection.delete_color_legend(case=self, result_name=property_name)
|
||||
|
||||
if not value_names:
|
||||
collection.delete_color_legend(case=self, result_name=property_name)
|
||||
return None
|
||||
|
||||
name = legend_name if legend_name else property_name
|
||||
legend = collection.create_color_legend(name=name)
|
||||
|
||||
category_values = []
|
||||
category_names = []
|
||||
category_colors = []
|
||||
colors = value_colors or {}
|
||||
palette_index = 0
|
||||
for value, label in value_names.items():
|
||||
for value, label in sorted(value_names.items()):
|
||||
color = colors.get(value)
|
||||
if color is None:
|
||||
color = _DEFAULT_PALETTE[palette_index % len(_DEFAULT_PALETTE)]
|
||||
palette_index += 1
|
||||
legend.add_color_legend_item(
|
||||
category_value=value,
|
||||
category_name=label,
|
||||
color=color,
|
||||
)
|
||||
category_values.append(value)
|
||||
category_names.append(label)
|
||||
category_colors.append(color)
|
||||
|
||||
collection.set_default_color_legend_for_result(
|
||||
return collection.update_color_legend(
|
||||
case=self,
|
||||
result_name=property_name,
|
||||
color_legend=legend,
|
||||
legend_name=name,
|
||||
category_values=category_values,
|
||||
category_names=category_names,
|
||||
colors=category_colors,
|
||||
)
|
||||
|
||||
return legend
|
||||
|
||||
|
||||
def _find_default_legend(case: Case, property_name: str) -> Optional[ColorLegend]:
|
||||
"""Look up the color legend bound to (case, property_name).
|
||||
|
||||
@@ -130,3 +130,43 @@ def test_discrete_property_category_no_duplicate_legend(rips_instance, initializ
|
||||
1: "Shale",
|
||||
2: "Coal",
|
||||
}
|
||||
|
||||
|
||||
def test_discrete_property_category_update_preserves_legend_identity(
|
||||
rips_instance, initialize_test
|
||||
):
|
||||
case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID"
|
||||
case = rips_instance.project.load_case(path=case_path)
|
||||
assert case is not None
|
||||
|
||||
collection = rips_instance.project.color_legend_collection()
|
||||
|
||||
def legend_count():
|
||||
return len(collection.descendants(rips.ColorLegend))
|
||||
|
||||
legend1 = case.set_discrete_property_category_names(
|
||||
property_name="FACIES", value_names={0: "Sand", 1: "Shale"}
|
||||
)
|
||||
assert legend1 is not None
|
||||
after_first = legend_count()
|
||||
|
||||
# A repeated call must update the existing legend object in place so that
|
||||
# views referencing it keep their binding.
|
||||
new_names = {0: "Sandstone", 1: "Shale", 2: "Coal"}
|
||||
new_colors = {0: "#e6c878", 1: "#646464", 2: "#202020"}
|
||||
legend2 = case.set_discrete_property_category_names(
|
||||
property_name="FACIES", value_names=new_names, value_colors=new_colors
|
||||
)
|
||||
assert legend2.address() == legend1.address()
|
||||
assert legend_count() == after_first
|
||||
|
||||
# The items are fully replaced, with no leftovers from the first call.
|
||||
assert case.discrete_property_category_names("FACIES") == new_names
|
||||
assert case.discrete_property_category_colors("FACIES") == new_colors
|
||||
|
||||
# The legend can be renamed in place as well.
|
||||
legend3 = case.set_discrete_property_category_names(
|
||||
property_name="FACIES", value_names=new_names, legend_name="My Facies"
|
||||
)
|
||||
assert legend3.address() == legend1.address()
|
||||
assert legend3.color_legend_name == "My Facies"
|
||||
Reference in new issue
Block a user