Skip to content

Commit 56a6652

Browse files
authored
feat: add variable comparison plots (#8)
1 parent 60a23a8 commit 56a6652

File tree

2 files changed

+106
-43
lines changed

2 files changed

+106
-43
lines changed

action.yml

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -201,24 +201,57 @@ runs:
201201
ssh-key: ${{ inputs.validator_key }}
202202
path: validator-repo
203203

204+
- name: Setup environment and retrieve scripts
205+
if: ${{ inputs.step == 'create-comment' }}
206+
run: |
207+
cd $GITHUB_WORKSPACE/validator-repo
208+
209+
# Get potential changes from main branch
210+
git fetch origin
211+
if [ "${{ inputs.dev }}" = true ]; then
212+
echo "Merging from dev instead of main."
213+
git merge origin/dev --allow-unrelated-histories -X theirs
214+
else
215+
git merge origin/main --allow-unrelated-histories -X theirs
216+
fi
217+
218+
# Install requirements
219+
pip install -r requirements.txt
220+
221+
shell: bash
222+
204223
- name: Upload relevant plots
205224
id: upload-plots
206225
if: ${{ inputs.step == 'create-comment' }}
207226
run: |
208227
cd $GITHUB_WORKSPACE/validator-repo
209228
229+
# Get static plot list (from input)
230+
read -a plots_array_input <<< ${{ inputs.plots }}
231+
# Get dynamic plot list (from comment script)
232+
read -a plots_array_dynamic <<< "$(python draft_comment.py plots)"
233+
234+
plots_array=("${plots_array_input[@]}" "${plots_array_dynamic[@]}")
235+
236+
# Empty directory
210237
rm -rf _validation-images
211238
mkdir -p _validation-images/feature
212239
mkdir -p _validation-images/main
213240
214241
# Copy plots
215-
read -a plots_array <<< ${{ inputs.plots }}
216242
echo "Plots: ${plots_array[@]}"
217-
for plot in "${plots_array[@]}"
243+
for plotpath in "${plots_array[@]}"
218244
do
219-
echo "Copying ${plot}"
220-
cp -r "$HOME/artifacts/results (main branch)/${PREFIX_MAIN}/${plot}" "_validation-images/main" || true # ignore if run failed
221-
cp -r "$HOME/artifacts/results (feature branch)/${PREFIX_FEATURE}/${plot}" "_validation-images/feature" || true # ignore if run failed
245+
subpath="${plotpath%/*}"
246+
plot="${plotpath##*/}"
247+
echo "Copying plot: ${plot} from path: ${subpath}"
248+
249+
# Create directories
250+
mkdir -p "_validation-images/main/${subpath}"
251+
mkdir -p "_validation-images/feature/${subpath}"
252+
253+
cp "$HOME/artifacts/results (main branch)/${PREFIX_MAIN}/${subpath}/${plot}" "_validation-images/main/${subpath}/" || true # ignore if run failed
254+
cp "$HOME/artifacts/results (feature branch)/${PREFIX_FEATURE}/${subpath}/${plot}" "_validation-images/feature/${subpath}/" || true # ignore if run failed
222255
done
223256
224257
# Add plots to repo branch
@@ -230,7 +263,7 @@ runs:
230263
231264
shell: bash
232265

233-
- name: Set env for comment script
266+
- name: Setup env variables for comment
234267
if: ${{ inputs.step == 'create-comment' }}
235268
run: |
236269
# This needs to be done in a separate step to ensure the output is available
@@ -244,26 +277,6 @@ runs:
244277
run: |
245278
cd $GITHUB_WORKSPACE/validator-repo
246279
247-
# Get potential changes from main branch
248-
git fetch origin
249-
if [ "${{ inputs.dev }}" = true ]; then
250-
echo "Merging from dev instead of main."
251-
git merge origin/dev --allow-unrelated-histories
252-
else
253-
git merge origin/main --allow-unrelated-histories
254-
fi
255-
256-
# Install requirements
257-
pip install -r requirements.txt
258-
259-
# # Set env for multiline plots string
260-
# read -a plots_array <<< ${{ inputs.plots }}
261-
# IFS=' '
262-
# plots_string="${plots_array[*]}"
263-
# echo "${plots_string}"
264-
# echo "PLOTS=\"${plots_string}\"" >> $GITHUB_ENV
265-
# unset IFS
266-
267280
# Draft comment
268281
# Note: The script uses many env variables. See the script for more details.
269282
python draft_comment.py > $GITHUB_WORKSPACE/comment.txt

draft_comment.py

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import numpy as np
1414
import pandas as pd
1515
from numpy.typing import ArrayLike
16+
import argparse
1617

1718

1819
def min_max_normalized_mae(y_true: ArrayLike, y_pred: ArrayLike) -> float:
@@ -124,8 +125,8 @@ def get_env_var(var_name: str, default: Any = None) -> Any:
124125
if value == "" and default is None:
125126
msg = f"The environment variable '{var_name}' is not set."
126127
raise OSError(msg)
127-
if value.lower() in ["true", "false"]:
128-
return value.lower() == "true"
128+
if str(value).lower() in ["true", "false"]:
129+
return str(value).lower() == "true"
129130
return value
130131

131132

@@ -147,8 +148,8 @@ class CommentData:
147148
get_env_var("DIR_ARTIFACTS", Path(get_env_var("HOME")) / "artifacts")
148149
)
149150
# For RunSuccessfull body
150-
plots_hash: str = get_env_var("PLOTS_HASH")
151-
plots_string: str = get_env_var("PLOTS")
151+
plots_hash: str = get_env_var("PLOTS_HASH", "")
152+
plots_string: str = get_env_var("PLOTS", "")
152153

153154
_sucessfull_run = None
154155

@@ -216,13 +217,15 @@ def __init__(self):
216217
self.dir_feature = self.dir_feature[0]
217218

218219
self.plots_list = [
219-
plot.split("/")[-1]
220+
plot
220221
for plot in self.plots_string.split(" ")
221222
if plot.split(".")[-1] in ["png", "jpg", "jpeg", "svg"]
222223
]
223224

224225
self._variables_deviation_ds = None
225226

227+
self.plots_base_url = f"https://raw.githubusercontent.com/lkstrp/pypsa-validator/{self.plots_hash}/_validation-images/"
228+
226229
# Status strings for file comparison table
227230
STATUS_FILE_MISSING = " :warning: Missing"
228231
STATUS_EQUAL = ":white_check_mark: Equal"
@@ -235,6 +238,7 @@ def __init__(self):
235238
STATUS_NEW = ":warning: New"
236239

237240
VARIABLES_FILE = "KN2045_Bal_v4/ariadne/exported_variables_full.xlsx"
241+
VARIABLES_THRESHOLD = 5
238242

239243
@property
240244
def variables_deviation_ds(self):
@@ -258,10 +262,22 @@ def variables_deviation_ds(self):
258262
np.round(deviation, 2).mean(axis=1), index=vars1.index
259263
).sort_values(ascending=False)
260264

261-
self._variables_deviation_ds = deviation
265+
# Filter for threshold
266+
deviation = deviation.loc[deviation > self.VARIABLES_THRESHOLD]
262267

268+
self._variables_deviation_ds = deviation
263269
return self._variables_deviation_ds
264270

271+
@property
272+
def variables_plot_strings(self):
273+
plots = (
274+
self.variables_deviation_ds.index.to_series()
275+
.apply(lambda x: re.sub(r"[ |/]", "-", x))
276+
.apply(lambda x: "ariadne_comparison/" + x + ".png")
277+
.to_list()
278+
)
279+
return plots
280+
265281
@property
266282
def variables_comparison(self) -> str:
267283
if (
@@ -270,11 +286,9 @@ def variables_comparison(self) -> str:
270286
):
271287
return ""
272288

273-
df = self.variables_deviation_ds.loc[self.variables_deviation_ds > 5].apply(
274-
lambda x: f"{x:.2f}%"
275-
)
289+
df = self.variables_deviation_ds.apply(lambda x: f"{x:.2f}%")
276290
df = pd.DataFrame(df, columns=["MAPE"])
277-
df.index.name = ""
291+
df.index.name = None
278292

279293
return (
280294
f"{df.to_html(escape=False)}\n"
@@ -292,18 +306,32 @@ def changed_variables_plots(self) -> str:
292306
or not (self.dir_feature / self.VARIABLES_FILE).exists()
293307
):
294308
return ""
295-
# Not implemented yet
296-
return ""
309+
310+
rows: list = []
311+
for plot in self.variables_plot_strings:
312+
url_a = self.plots_base_url + "main/" + plot
313+
url_b = self.plots_base_url + "feature/" + plot
314+
rows.append(
315+
[
316+
f'<img src="{url_a}" alt="Error in loading image.">',
317+
f'<img src="{url_b}" alt="Error in loading image.">',
318+
]
319+
)
320+
321+
df = pd.DataFrame(
322+
rows,
323+
columns=pd.Index(["Main branch", "Feature branch"]),
324+
)
325+
return df.to_html(escape=False, index=False) + "\n"
297326

298327
@property
299328
def plots_table(self) -> str:
300329
"""Plots comparison table."""
301-
base_url = f"https://raw.githubusercontent.com/lkstrp/pypsa-validator/{self.plots_hash}/_validation-images/"
302330

303331
rows: list = []
304332
for plot in self.plots_list:
305-
url_a = base_url + "main/" + plot
306-
url_b = base_url + "feature/" + plot
333+
url_a = self.plots_base_url + "main/" + plot
334+
url_b = self.plots_base_url + "feature/" + plot
307335
rows.append(
308336
[
309337
f'<img src="{url_a}" alt="Image not found in results">',
@@ -575,6 +603,14 @@ def subtext(self) -> str:
575603
f"Last updated on `{time}`."
576604
)
577605

606+
def needed_plots(self):
607+
if self.sucessfull_run:
608+
body_sucessfull = RunSuccessfull()
609+
plots_string = " ".join(body_sucessfull.variables_plot_strings)
610+
return plots_string
611+
else:
612+
""
613+
578614
def __repr__(self) -> str:
579615
"""Return full formatted comment."""
580616
if self.sucessfull_run:
@@ -598,7 +634,21 @@ def __repr__(self) -> str:
598634
)
599635

600636

601-
if __name__ == "__main__":
637+
def main():
638+
parser = argparse.ArgumentParser(description="Process some comments.")
639+
parser.add_argument(
640+
"command", nargs="?", default="", help='Command to run, e.g., "plots".'
641+
)
642+
args = parser.parse_args()
643+
602644
comment = Comment()
603645

604-
print(comment) # noqa T201
646+
if args.command == "plots":
647+
print(comment.needed_plots())
648+
649+
else:
650+
print(comment) # noqa T201
651+
652+
653+
if __name__ == "__main__":
654+
main()

0 commit comments

Comments
 (0)