Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

patch.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import typing
  2. import numpy as np
  3. import pandas as pd
  4. import pathlib as pl
  5. from PIL import Image
  6. from .tapestry_config import TapestryConfig
  7. import pprint
  8. def sanitize_formats(formats: typing.Iterable[str]) -> typing.Iterable[str]:
  9. formats = [x.lower().lstrip(".") for x in formats]
  10. if "png" not in formats:
  11. formats.append("png")
  12. return formats
  13. class EmptyPatch(object):
  14. def __init__(self):
  15. super().__init__()
  16. self.image_relative_path = "Excluded"
  17. self.text_below = ""
  18. self.text_right_bottom = ""
  19. self.text_right_top = ""
  20. self.animal = "Invalid"
  21. self.flag_changes = "Invalid"
  22. self.movie_file = None
  23. class Patch(EmptyPatch):
  24. def __init__(self, overview: np.ndarray, data_limits: typing.Iterable[float],
  25. measurement_row: pd.Series, animal: str, measu: int, flag_changes: dict,
  26. ):
  27. super().__init__()
  28. self.overview = overview
  29. self.pil_image = Image.fromarray(overview)
  30. self.data_limits = data_limits
  31. self.text_right_bottom, self.text_right_top = [f"{x:.3g}" for x in data_limits]
  32. self.measurement_row = measurement_row
  33. self.text_below = "uninitialized"
  34. self.image_relative_path = "uninitialized"
  35. self.animal = animal
  36. self.measu = measu
  37. self.flag_changes = pprint.pformat(flag_changes).replace("\n", "<br>")
  38. def initialize_texts(self, tapestry_config: TapestryConfig):
  39. self.text_below = tapestry_config.text_below_func(self.measurement_row)
  40. if tapestry_config.text_right_top_func is not None:
  41. self.text_right_top = tapestry_config.text_right_top_func(self.measurement_row)
  42. if tapestry_config.text_right_bottom_func is not None:
  43. self.text_right_bottom = tapestry_config.text_right_bottom_func(self.measurement_row)
  44. def write_overview_movie_files(self, extra_formats: typing.Iterable[str], op_folder_path: pl.Path, row_string: str):
  45. assert self.text_below != "uninitialized", "text_below has not been initialized! Please call the function" \
  46. "'initialize_texts' first and try again!"
  47. op_animal_folder_path = op_folder_path / self.animal
  48. op_animal_folder_path.mkdir(parents=True, exist_ok=True)
  49. image_op_stem = op_animal_folder_path / f"{row_string}_{self.measu}_{self.text_below}"
  50. self.image_relative_path = f"{image_op_stem.relative_to(op_folder_path.parent)}.png"
  51. for format in sanitize_formats(extra_formats):
  52. measu_op_file = f"{image_op_stem}.{format}"
  53. self.pil_image.save(measu_op_file)
  54. return image_op_stem
  55. class PatchWithMovie(Patch):
  56. def __init__(self, overview: np.ndarray, data_limits: typing.Iterable[float],
  57. measurement_row: pd.Series, animal: str, measu: int, flag_changes: dict,
  58. op_movie_file: str):
  59. super().__init__(overview, data_limits, measurement_row, animal, measu, flag_changes)
  60. self.movie_file = op_movie_file
  61. def write_overview_movie_files(self, extra_formats: typing.Iterable[str], op_folder_path: pl.Path, row_string: str):
  62. image_op_stem = super().write_overview_movie_files(extra_formats, op_folder_path, row_string)
  63. # move movie next to the created overview files
  64. temp_movie_path = pl.Path(self.movie_file)
  65. movie_op_file_path = f"{image_op_stem}_movie{temp_movie_path.suffix}"
  66. temp_movie_path.replace(movie_op_file_path)
  67. self.movie_file = movie_op_file_path
  68. def get_nonempty_patch(overview, data_limits, measurement_row, animal, measu, flag_changes, op_movie_file):
  69. if op_movie_file is None:
  70. return Patch(overview, data_limits, measurement_row, animal, measu, flag_changes)
  71. else:
  72. return PatchWithMovie(overview, data_limits, measurement_row, animal, measu, flag_changes, op_movie_file)