Skip to content

Commit

Permalink
WIP: Attempt to replicate QGIS layer number formatting behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
mfisher87 committed Aug 4, 2023
1 parent 06e7d0a commit a47aa9a
Showing 1 changed file with 67 additions and 8 deletions.
75 changes: 67 additions & 8 deletions qgreenland/util/model_validators/layer_style.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import re
from xml.etree import ElementTree

from qgis.core import QgsRendererRangeLabelFormat

import qgreenland.exceptions as exc
from qgreenland.util.layer_style import get_style_filepath

Expand Down Expand Up @@ -43,7 +46,7 @@ def validate_style_file_only_contains_allowed_fonts(style_name: str):
return style_name


def validate_style_file_unit_suffixes(style_name: str): # noqa: C901
def validate_style_file_unit_suffixes(style_name: str):
"""Ensure common errors in style configuration of unit suffixes are avoided.
For example, the "Label unit suffix" field in the QGIS Layer Symbology menu seems
Expand Down Expand Up @@ -82,13 +85,12 @@ def validate_style_file_unit_suffixes(style_name: str): # noqa: C901
first_value = first_item.attrib["value"]
first_label = first_item.attrib["label"]

# If the label is rounded, we have to round the value before subtracting.
if (
label_precision := colorrampshader.attrib.get("labelPrecision", "0")
) != "0":
first_value = f"{float(first_value):.{label_precision}f}"

unit_suffix = first_label.removeprefix(first_value)
label_precision = colorrampshader.attrib.get("labelPrecision", "0")
unit_suffix = _get_unit_suffix(
value=first_value,
label=first_label,
label_precision=label_precision,
)

if not unit_suffix:
# The first colorrampitem's label does not contain a suffix set by the
Expand Down Expand Up @@ -121,3 +123,60 @@ def validate_style_file_unit_suffixes(style_name: str): # noqa: C901
' menu and ensure that the "Label unit suffix" exactly matches the "suffix"'
' field in the "Legend Settings" menu.'
)


def _get_unit_suffix(*, label: str, value: str, label_precision: int = 0) -> str | None:
"""Calculate the unit suffix for a QGIS colormap entry.
A QGIS style has a `<colorrampshader>` with a `labelPrecision` setting. Each
`<item>` has a `label` and a `value` attribute. In order to calculate the suffix
from the `label`, we need to calculate the non-suffix part of the `label` based on
`value`. Then we can difference the calculated label (sans suffix) and the real
label to get the suffix.
"""
# expected_label = _label_generation_emulator(
# value,
# label_precision=label_precision,
# )

formatter = QgsRendererRangeLabelFormat()
formatter.setTrimTrailingZeroes(True)
formatter.setPrecision(label_precision)

# This doesn't handle the case:
# value: "-0.0936000000000003" -> label: "-0.093600"
formatted_value = formatter.formatNumber(float(value))
return label.removeprefix(formatted_value)


def _label_generation_emulator(value: str, *, label_precision: int) -> str:
"""Emulate QGIS label-generation behavior, excluding unit suffix.
Labels for a labelPrecision setting of `6` might look like:
{label: "-2 m/y", value: "-2"},
{label: "-1.922 m/y", value: "-1.922"}
{label: "-0.093600 m/y", value: "-0.0936000000000003"}
We can't just use Python's float-formatting behavior:
>>> f"{-0.0936000000000003:.6f}"
'-0.093600'
>>> f"{-1.922:.6f}"
'-1.922000'
>>> f"{-2:.6f}"
'-2.000000'
This function emulates the behavior of this QGIS function:
https://github.com/qgis/QGIS/blob/ac45ceb072e57d398c4678f2ab790c5e920a6e12/src/core/classification/qgsclassificationmethod.cpp#L158
https://qgis.org/pyqgis/3.28/search.html?q=formatNumber&check_keywords=yes&area=default
"""
re.compile(r"[.,]?0*$")
re.compile(r"^\\-0(?:[.,]0*)?$")

if label_precision > 0:
...
else:
...

0 comments on commit a47aa9a

Please sign in to comment.