Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions abloc/src/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ def plot_profile(

# Add traces
fig.add_trace(
go.Scatter(x=df[x], y=df[y1], name="depth", line=dict(color="navy")),
go.Scatter(x=df[x], y=df[y1], name="Depth", line=dict(color="navy")),
secondary_y=False,
)

fig.update_traces(fill="tozeroy", line_color="rgba(0,100,80,0.2)")

fig.add_trace(
go.Scatter(x=df[x], y=df[y2], name="bloc", line=dict(color="navy")),
go.Scatter(x=df[x], y=df[y2], name="Bloc pressure", line=dict(color="navy")),
secondary_y=True,
)

Expand All @@ -70,7 +70,7 @@ def plot_profile(
x=df["mid_interval"],
y=df["mid_pressure"],
mode="text",
name="segment",
name="Segment",
text=df["segment"],
textposition="bottom center",
textfont=dict(size=18, color="navy", weight=900),
Expand All @@ -79,7 +79,10 @@ def plot_profile(
)

# Add figure title
fig.update_layout(title_text="Dive Profile", template="plotly_white")
fig.update_layout(
title=dict(text="Dive Profile", font=dict(size=20, weight=900)),
template="plotly_white",
)

# Set x-axis title
fig.update_xaxes(title_text="<b>Dive time</b> (min)")
Expand Down Expand Up @@ -131,7 +134,10 @@ def format_profile(dp: DiveProfile) -> GT:
.when(pl.col("depth") < pl.col("depth").shift(1))
.then(pl.lit("up"))
.otherwise(pl.lit("stable"))
.alias("direction")
.alias("direction"),
speed=(
(pl.col("depth").shift(1) - pl.col("depth")) / pl.col("time_interval")
).round(2),
)

required_columns = {"conso_totale", "conso_remaining", "bar_remaining"}
Expand All @@ -141,6 +147,7 @@ def format_profile(dp: DiveProfile) -> GT:
[
"segment",
"direction",
"speed",
"time_interval",
"depth",
"bar_remaining",
Expand All @@ -155,6 +162,7 @@ def format_profile(dp: DiveProfile) -> GT:
columns=[
"segment",
"direction",
"speed",
"time_interval",
"depth",
"conso_per_min",
Expand All @@ -165,6 +173,7 @@ def format_profile(dp: DiveProfile) -> GT:
.cols_label(
segment=html("<b>Segment</b>"),
direction=html("<b>Direction</b>"),
speed=html("<b>Speed</b> (m/min)"),
time_interval=html("<b>Time</b> (min)"),
depth=html("<b>Depth</b> (m)"),
conso_per_min=html("<b>Air consumption</b> (L/min)"),
Expand All @@ -188,6 +197,12 @@ def format_profile(dp: DiveProfile) -> GT:
domain=[0, 50 * dp.volume],
na_color="white",
)
.data_color(
columns=["speed"],
palette=["firebrick", "lightcoral"],
domain=[10, 30],
na_color="white",
)
.sub_missing(missing_text="")
)
return table_output
17 changes: 17 additions & 0 deletions abloc/src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,23 @@ def update_segment(
self.profile, segment, time_interval, depth, conso
)

def delete_segment(self, segment: str) -> None:
"""
Delete a specific segment from the dive profile.
Parameters:
- segment: Segment label to delete.
Returns:
- None : Remove the specified segment from the profile.
"""
if segment in self.profile["segment"].to_list():
self.profile = self.profile.filter(
pl.col("segment") != segment
).with_columns(
segment=pl.Series(list(ascii_uppercase[: len(self.profile) - 1]))
)
else:
raise ValueError(f"Segment {segment} does not exist in the profile.")


def compute_conso_from_profile(df: pl.DataFrame) -> pl.DataFrame:
"""
Expand Down
27 changes: 24 additions & 3 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@
"Update Segment",
icon=ui.tags.i(class_="fa-solid fa-wand-magic-sparkles"),
),
ui.panel_conditional(
"input.row_select != 'new segment'",
ui.input_action_button(
"delete_segment",
"Delete Segment",
icon=ui.tags.i(class_="fa-solid fa-eraser"),
),
),
),
),
output_widget("profile_plot"),
Expand All @@ -55,9 +63,9 @@ def server(input, output, session):

# create a basic initial dive profile and set up reactivity
dp = DiveProfile(
time=[5.0, 20.0, 10.0],
depth=[20.0, 20.0, 0.0],
conso=[20, 20, 20],
time=[3.0, 20.0, 3.0, 3.0, 1.0],
depth=[20.0, 20.0, 3.0, 3.0, 0.0],
conso=[20, 20, 20, 20, 20],
volume=12,
pressure=200,
)
Expand Down Expand Up @@ -124,6 +132,19 @@ def _():
segment_list.set(newdp.profile["segment"].to_list())
reactive_dp.set(newdp)

@reactive.effect
@reactive.event(input.delete_segment)
def _():
req(input.row_select())
if input.row_select() == "new segment":
return
newdp = copy(reactive_dp.get())
newdp.delete_segment(input.row_select())
newdp.update_time()
newdp.update_conso()
segment_list.set(newdp.profile["segment"].to_list())
reactive_dp.set(newdp)

@gts.render_gt
def dive_profile():
return format_profile(dp=reactive_dp.get())
Expand Down
27 changes: 18 additions & 9 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
},
"files": {
"requirements.txt": {
"checksum": "9ba2c280624f3de704c122ccc5fcaa62"
"checksum": "33768a7e614fdb3249f75f2bbb4d7439"
},
".bumpversion.toml": {
"checksum": "16cb9e5de362f70897c096d978cf96a8"
},
".github/workflows/deploy.yml": {
"checksum": "0c08e0b1f3d7b0e71ddffd139d3dea46"
"checksum": "54cd7177719f46d3c9262d0aac041a40"
},
".github/workflows/lint_and_req.yml": {
"checksum": "99c16780899a0a8bc70816788efc89ac"
Expand All @@ -46,14 +46,23 @@
"VERSION": {
"checksum": "335e29d8085b1816c6304031b6a592af"
},
"abloc/src/img/logo-diver-down.svg": {
"checksum": "f3aee2242b1ff7cfd0cbe7fb26c661c3"
},
"abloc/src/img/logo-diver-stable.svg": {
"checksum": "47934d80096018725714e03110cdc5d0"
},
"abloc/src/img/logo-diver-up.svg": {
"checksum": "1fbc206d026f08d3ef9fa5a42b7ac34c"
},
"abloc/src/plot.py": {
"checksum": "39d82a84120565f65c82e2df8cfb294e"
"checksum": "69f81fd6176a77318d0f7d266f644a09"
},
"abloc/src/utils.py": {
"checksum": "9e000e991f9ec40b791679848f43cad9"
"checksum": "c1354963e4a1d87167c8869cf134eec7"
},
"app.py": {
"checksum": "90c978ac28eda7f05fe1779875014a9d"
"checksum": "a680962177b02c42ef7ac36267cd399d"
},
"css/styles.css": {
"checksum": "67b43094cfad8ece0f65272419dc4ec3"
Expand All @@ -65,19 +74,19 @@
"checksum": "3d5f00114c2380be69a4e88c5ca3b269"
},
"pyproject.toml": {
"checksum": "00f604988cd16a70dcf40ec776faa1ca"
"checksum": "55f8eb5b6d2f281dd44591a5a4cda5ad"
},
"tests/__init__.py": {
"checksum": "d41d8cd98f00b204e9800998ecf8427e"
},
"tests/test_plot.py": {
"checksum": "6befd647c3f9ea4f4bd1d349686c7acb"
"checksum": "b594e7f6dd39a3198dad9ecebde79322"
},
"tests/test_utils.py": {
"checksum": "c7cf5f829b046450a53c565d5f76d4c1"
"checksum": "06dd0f99aa43ff614a2d299f88f6d4d5"
},
"uv.lock": {
"checksum": "3b3fabcf66e1dfdba2586b9170ffe04b"
"checksum": "fef457356e93fa18edf723eeb467cb0d"
}
}
}
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ idna==3.10
importlib-metadata==8.7.0
# via great-tables
importlib-resources==6.5.2
# via great-tables
# via
# abloc
# great-tables
iniconfig==2.1.0
# via pytest
ipython==9.3.0
Expand Down
6 changes: 3 additions & 3 deletions tests/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def test_plot():
# Test if the figure has the expected number of traces
data = fig.data
assert len(data) == 3
assert data[0].name == "depth"
assert data[1].name == "bloc"
assert data[2].name == "segment"
assert data[0].name == "Depth"
assert data[1].name == "Bloc pressure"
assert data[2].name == "Segment"
# Test if the x-axis and y-axes titles are set correctly
assert fig.layout.xaxis.title.text == "<b>Dive time</b> (min)"
assert fig.layout.yaxis.title.text == "<b>Depth</b> (m)"
Expand Down
12 changes: 12 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ def test_update_segment():
), "New B segment is correct"


def test_delete_segment():
dp = utils.DiveProfile(
time=[5, 20, 10], depth=[20, 20, 0], conso=[20, 20, 20], volume=12, pressure=200
)
assert dp.profile.shape == (3, 5), "Initial profile has 3 rows"
dp.delete_segment(segment="B")
assert "B" in dp.profile["segment"].to_list(), "B segment is reassign"
assert dp.profile.shape == (2, 5), "Profile has 2 rows after deletion"
with pytest.raises(ValueError):
dp.delete_segment(segment="D")


def test_format_profile():
dp = utils.DiveProfile(
time=[5, 20, 10], depth=[20, 20, 0], conso=[20, 20, 20], volume=12, pressure=200
Expand Down