Skip to content

Commit

Permalink
Merge pull request #38 from Deltares/ticks-overlap
Browse files Browse the repository at this point in the history
Added overlap funvtionality in plot and unit tests
  • Loading branch information
aronnoordam authored Jan 13, 2025
2 parents 35c59e3 + db77340 commit cfb8a93
Show file tree
Hide file tree
Showing 20 changed files with 356 additions and 49 deletions.
12 changes: 7 additions & 5 deletions geolib_plus/bro_xml_cpt/bro_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,15 @@ def get_all_data_from_bro(self, root: _Element) -> None:
# cpt time of result
for cpt in root.iter(ns + "conePenetrationTest"):
for loc in cpt.iter(ns5 + "resultTime"):
if loc.text and loc.text.strip():
# If loc.text is not None and not empty, use its value
self.bro_data.result_time = loc.text
else:
# Fallback: Look for nested timePosition element
if loc.text is None:
for loc2 in loc.iter(ns3 + "timePosition"):
self.bro_data.result_time = loc2.text
else:
if loc.text.strip() == "":
for loc2 in loc.iter(ns3 + "timePosition"):
self.bro_data.result_time = loc2.text
else:
self.bro_data.result_time = loc.text

# Pre drilled depth
z = self.search_values_in_root(root=root, search_item=ns + "predrilledDepth")
Expand Down
4 changes: 4 additions & 0 deletions geolib_plus/plot_cpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,10 @@ def generate_plot(
plot_utils.set_local_reference_line(
cpt, axes[0], axes[0].get_xlim(), settings["language"]
)
# set predrill line
plot_utils.create_predrilled_depth_line_and_box(
cpt, axes[0], axes[0].get_xlim(), settings["language"]
)

# create custom grid
plot_utils.create_custom_grid(axes[0], axes[0].get_xlim(), ylim, settings["grid"])
Expand Down
166 changes: 140 additions & 26 deletions geolib_plus/plot_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import Any, Dict, List, Tuple

import numpy as np
from matplotlib.axes import Axes
Expand Down Expand Up @@ -98,20 +98,20 @@ def set_textbox_at_thresholds(


def set_multicolor_label(
ylim,
ax,
label_txt,
color,
font_size_text,
font_size_arrow,
line_style,
x_axis_type,
location="bottom_left",
axis="x",
anchorpad=0,
extra_label_spacing=0.02,
**kw,
):
ylim: List[float],
ax: Axes,
label_txt: str,
color: str,
font_size_text: int,
font_size_arrow: int,
line_style: str,
x_axis_type: str,
location: str = "bottom_left",
axis: str = "x",
anchorpad: int = 0,
extra_label_spacing: float = 0.02,
**kw: Any,
) -> None:
"""
This function creates axes labels with multiple colors
Expand Down Expand Up @@ -206,7 +206,9 @@ def set_multicolor_label(
ax.add_artist(anchored_xbox)


def set_local_reference_line(cpt, ax, xlim, language):
def set_local_reference_line(
cpt: Any, ax: Axes, xlim: List[float], language: str
) -> None:
"""
Sets a line in the plot at the depth of the local reference line, e.g. surface level or sea bed level.
Also set a textbox with the depth of the reference line relative to the vertical datum.
Expand Down Expand Up @@ -265,7 +267,62 @@ def set_local_reference_line(cpt, ax, xlim, language):
ax.add_artist(anchored_xbox)


def create_custom_grid(ax, xlim, ylim, grid):
def create_predrilled_depth_line_and_box(
cpt: Any, ax: Axes, xlim: List[float], language: str
) -> None:
"""
Sets a black line at the left most side of the plot from the local_reference_level to the
local_reference_level - predrilled_depth. Also sets a textbox with the depth of the predrilled depth.
This should only happen if the predrilled depth is present and more than 0.5 m.
:param ax: current axis
:param cpt: cpt data
:param xlim: horizontal limit
:param language: language of the plot
:return:
"""
if cpt.predrilled_z == None:
predrill_value = 0
else:
predrill_value = cpt.predrilled_z

ax.plot(
[xlim[0], xlim[0]],
[cpt.local_reference_level, cpt.local_reference_level - cpt.predrilled_z],
color="black",
linewidth=7,
)

if language == "Nederlands":
text = "Voorboordiepte = " + str(cpt.predrilled_z) + " m"
else:
text = "Predrilled depth = " + str(cpt.predrilled_z) + " m"

box = [
TextArea(
text,
textprops=dict(color="black", fontsize=9, horizontalalignment="left"),
)
]

xbox = HPacker(children=box, align="center", pad=0, sep=5)
y_lims = ax.get_ylim()
# place the textbox at the left side of the plot in the middle of the plot
bbox_to_anchor = (5 / 16, 0.975) # top middle default value
anchored_xbox = AnchoredOffsetbox(
loc=2,
child=xbox,
pad=0.25,
bbox_to_anchor=bbox_to_anchor,
bbox_transform=ax.transAxes,
borderpad=0.0,
)
ax.add_artist(anchored_xbox)


def create_custom_grid(
ax: Axes, xlim: List[float], ylim: List[float], grid: Dict[str, Any]
) -> None:
"""
Creates custom grid with custom line colours, custom line distances and custom line widths
Expand Down Expand Up @@ -331,7 +388,9 @@ def create_custom_grid(ax, xlim, ylim, grid):
]


def set_x_axis(ax, graph, settings, ylim):
def set_x_axis(
ax: Axes, graph: Dict[str, Any], settings: Dict[str, Any], ylim: List[float]
) -> None:
"""
Sets the x-limit, the x-label, and the x-ticks
Expand Down Expand Up @@ -362,6 +421,36 @@ def set_x_axis(ax, graph, settings, ylim):
ax.set_xticks(ticks)
ax.tick_params(axis="x", colors=graph["graph_color"])

# Get tick positions and labels
tick_labels = ax.get_xticklabels()
label_extents = [
label.get_window_extent(renderer=ax.figure.canvas.get_renderer())
for label in tick_labels
]
start_label_positions = [tick.intervalx[0] for tick in label_extents]
end_label_positions = [tick.intervalx[1] for tick in label_extents]
first_start = start_label_positions[0]
first_end = end_label_positions[0]
new_ticks = []

# Iterate over the tick label positions and their extents
for counter, (start, end) in enumerate(
zip(start_label_positions, end_label_positions)
):
# Check if the current label overlaps with the previous label
if first_start < start < first_end or first_start < end < first_end:
# If it overlaps, add an empty string to the new ticks list
new_ticks.append("")
else:
# If it does not overlap, add the current label to the new ticks list
new_ticks.append(tick_labels[counter])
# Update the positions of the first label to the current label's positions
first_start = start
first_end = end

# update the new labels
ax.set_xticklabels(new_ticks)

set_multicolor_label(
ylim,
ax,
Expand All @@ -379,8 +468,13 @@ def set_x_axis(ax, graph, settings, ylim):


def set_y_axis(
ax, ylim, settings, cpt, tick_locations_inclination, tick_labels_inclination
):
ax: Axes,
ylim: List[float],
settings: Dict[str, Any],
cpt: Any,
tick_locations_inclination: List[float],
tick_labels_inclination: List[str],
) -> None:
"""
Sets the y-limit, the y-label, the y-ticks and inverts y-axis
Expand Down Expand Up @@ -420,7 +514,13 @@ def set_y_axis(
ax2.invert_yaxis()


def __add_text_in_rectangle(ax, text, rectangle, rel_vertical_position, hor_spacing):
def __add_text_in_rectangle(
ax: Axes,
text: str,
rectangle: Rectangle,
rel_vertical_position: float,
hor_spacing: float,
) -> None:
"""
Adds text into rectangles
Expand All @@ -443,8 +543,13 @@ def __add_text_in_rectangle(ax, text, rectangle, rel_vertical_position, hor_spac


def create_bro_information_box(
ax, scale, cpt, plot_nr, ylims, distance_meta_data_from_plot
):
ax: Axes,
scale: float,
cpt: Any,
plot_nr: int,
ylims: List[Tuple[float, float]],
distance_meta_data_from_plot: float,
) -> None:
"""
:param ax: current axis
Expand Down Expand Up @@ -635,7 +740,9 @@ def create_bro_information_box(
ax.add_patch(empty_box)


def create_gef_information_box(ax, scale, cpt, plot_nr, ylims):
def create_gef_information_box(
ax: Axes, scale: float, cpt: Any, plot_nr: int, ylims: List[Tuple[float, float]]
) -> None:
"""
Sets textboxes with meta data
Expand Down Expand Up @@ -813,14 +920,21 @@ def create_gef_information_box(ax, scale, cpt, plot_nr, ylims):
ax.add_patch(empty_box)


def create_information_box(ax, scale, cpt, plot_nr, ylims, distance_from_plot):
def create_information_box(
ax: Axes,
scale: float,
cpt: Any,
plot_nr: int,
ylims: List[Tuple[float, float]],
distance_from_plot: float,
) -> None:
if cpt.__class__.__name__ == "BroXmlCpt":
create_bro_information_box(ax, scale, cpt, plot_nr, ylims, distance_from_plot)
elif cpt.__class__.__name__ == "GefCpt":
create_gef_information_box(ax, scale, cpt, plot_nr, ylims)


def set_figure_size(fig, ylim):
def set_figure_size(fig: Any, ylim: List[float]) -> None:
"""
Sets the figure size in inches
Expand Down
51 changes: 39 additions & 12 deletions tests/bro_xml_cpt/test_bro_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,45 @@ def test_parse_bro_xml_warning(self, caplog):
# test warning
assert warning in caplog.text

@pytest.mark.systemtest
def test_that_xml_is_passed(self):
xml_files = [
"CPT000000129426.xml",
"CPT000000129429.xml",
"CPT000000179090.xml",
"CPT000000179092.xml",
"CPT000000179095.xml",
"CPT000000179099.xml",
"CPT000000179101.xml",
"CPT000000179103.xml",
"CPT000000179106.xml",
"CPT000000179107.xml",
"CPT000000179108.xml",
"CPT000000179109.xml",
"CPT000000179114.xml",
"CPT000000179122.xml",
"CPT000000179124.xml",
]
# open xml file as byte object
for file in xml_files:
fn = TestUtils.get_local_test_data_dir(
Path("cpt", "bro_xml", "xmls_with_various_formats", file)
)
# test initial expectations
assert fn.is_file()
with open(fn, "r") as f:
# memory-map the file, size 0 means whole file
xml = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)[:]
# read test xml
root = etree.fromstring(xml)
# initialise model
cpt_data = XMLBroCPTReader()
# test initial expectations
assert cpt_data
# run test
cpt_data.get_all_data_from_bro(root=root)
assert cpt_data.bro_data.id == file.split(".")[0]

@pytest.mark.systemtest
def test_get_all_data_from_bro(self):
# open xml file as byte object
Expand All @@ -200,15 +239,3 @@ def test_get_all_data_from_bro(self):
assert cpt_data
# run test
cpt_data.get_all_data_from_bro(root=root)
# test that the data are read
assert cpt_data.bro_data
assert cpt_data.bro_data.a == 0.58 # <ns14:frictionSleeveSurfaceArea
assert cpt_data.bro_data.id == "CPT000000064413"
assert cpt_data.bro_data.cone_penetrometer_type == "F7.5CKEHG/B-1701-0745"
assert cpt_data.bro_data.cpt_standard == "NEN5140"
assert cpt_data.bro_data.offset_z == -1.530
assert cpt_data.bro_data.local_reference == "maaiveld"
assert cpt_data.bro_data.vertical_datum == "NAP"
assert cpt_data.bro_data.quality_class == "klasse2"
assert cpt_data.bro_data.result_time == "2011-06-29"
assert cpt_data.bro_data.predrilled_z == 0.01

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading

0 comments on commit cfb8a93

Please sign in to comment.