Skip to content
Snippets Groups Projects
Commit 685a3136 authored by Andi Gerken's avatar Andi Gerken
Browse files

Adapted ipynb example

Added test for ipynb example
Added testbook dependency
parent 8b5dc634
No related branches found
No related tags found
No related merge requests found
Pipeline #35804 failed
...@@ -24,6 +24,7 @@ stages: ...@@ -24,6 +24,7 @@ stages:
artifacts: artifacts:
paths: paths:
- report.xml - report.xml
- htmlcov
expire_in: 1 day expire_in: 1 day
script: script:
- ./ci/test.py - ./ci/test.py
......
...@@ -34,7 +34,7 @@ if __name__ == "__main__": ...@@ -34,7 +34,7 @@ if __name__ == "__main__":
"--prompt", "--prompt",
"ci", "ci",
".venv", ".venv",
], ]
) )
check_call( check_call(
...@@ -44,9 +44,16 @@ if __name__ == "__main__": ...@@ -44,9 +44,16 @@ if __name__ == "__main__":
"pip", "pip",
"install", "install",
str(sorted(Path("dist").glob("*.whl"))[-1].resolve()), str(sorted(Path("dist").glob("*.whl"))[-1].resolve()),
], ]
) )
check_call( check_call(
[python_venv_executable(), "-m", "pytest", "--junitxml=report.xml"], [
python_venv_executable(),
"-m",
"pytest",
"--junitxml=report.xml",
"--cov=src",
"--cov-report=html",
]
) )
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
#! /usr/bin/env python3
import robofish.io import robofish.io
import numpy as np import numpy as np
from pathlib import Path
import os
# Helper function to enable relative paths from this file
def full_path(path):
return (Path(os.path.abspath("__file__")).parent / path).resolve()
if __name__ == "__main__": def create_example_file(path):
# Create a new io file object with a 100x100cm world # Create a new io file object with a 100x100cm world
sf = robofish.io.File(world_size=[100, 100]) sf = robofish.io.File(world_size_cm=[100, 100], frequency_hz=25.0)
# create a simple obstacle, fixed in place, fixed outline # create a simple obstacle, fixed in place, fixed outline
obstacle_pose = [[50, 50, 0, 0]]
obstacle_outline = [[[-10, -10], [-10, 0], [0, 0], [0, -10]]] obstacle_outline = [[[-10, -10], [-10, 0], [0, 0], [0, -10]]]
obstacle_name = sf.create_entity( obstacle_name = sf.create_entity(
"obstacle", poses=obstacle_pose, outlines=obstacle_outline "obstacle", positions=[[50, 50]], orientations=[[0]], outlines=obstacle_outline
) )
# create a robofish with 100 timesteps and 40ms between the timesteps. If we would not give a name, the name would be generated to be robot_1. # create a robofish with 1000 timesteps. If we would not give a name, the name would be generated to be robot_1.
robofish_timesteps = 4 robofish_timesteps = 1000
robofish_poses = np.zeros((robofish_timesteps, 4)) robofish_poses = np.ones((robofish_timesteps, 4)) * 50
sf.create_entity("robot", robofish_poses, name="robot", monotonic_step=40) robot = sf.create_entity("robot", robofish_poses, name="robot")
# create multiple fishes with timestamps. Since we don't specify names, but only the type "fish" the fishes will be named ["fish_1", "fish_2", "fish_3"] # create multiple fishes with timestamps. Since we don't specify names, but only the type "fish" the fishes will be named ["fish_1", "fish_2", "fish_3"]
agents = 3 agents = 3
timesteps = 5 timesteps = 1000
timestamps = np.linspace(0, timesteps + 1, timesteps) # timestamps = np.linspace(0, timesteps + 1, timesteps)
agent_poses = np.random.random((agents, timesteps, 4)) agent_poses = np.random.random((agents, timesteps, 4))
fish_names = sf.create_multiple_entities( fishes = sf.create_multiple_entities("fish", agent_poses)
"fish", agent_poses, monotonic_points=timestamps
)
# This would throw an exception if the file was invalid # This would throw an exception if the file was invalid
sf.validate() sf.validate()
# Save file validates aswell # Save file validates aswell
example_file = full_path("example.hdf5")
sf.save(example_file) sf.save_as(path)
# Closing and opening files (just for demonstration) # Closing and opening files (just for demonstration)
sf.close() sf.close()
sf = robofish.io.File(path=example_file) sf = robofish.io.File(path=path)
print("\nEntity Names") print("\nEntity Names")
print(sf.entity_names) print(sf.entity_names)
# Get an array with all poses. As the length of poses varies per agent, it # Get an array with all poses. As the length of poses varies per agent, it is filled up with nans.
# is filled up with nans. The result is not interpolated and the time scales
# per agent are different. It is planned to create a warning in the case of
# different time scales and have another function, which generates an
# interpolated array.
print("\nAll poses") print("\nAll poses")
print(sf.select_poses()) print(sf.entity_poses)
print("\nFish poses") print("\nFish poses")
print(sf.select_poses(lambda e: e.category == "fish")) print(sf.select_entity_poses(lambda e: e.category == "fish"))
print("\nFile structure") print("\nFile structure")
print(sf) print(sf)
if __name__ == "__main__":
create_example_file("example.hdf5")
``` ```
%% Output %% Output
Entity Names Entity Names
['fish_1', 'fish_2', 'fish_3', 'obstacle_1', 'robot'] ['fish_1', 'fish_2', 'fish_3', 'obstacle_1', 'robot']
All poses All poses
[[[8.86584103e-01 2.35670820e-01 5.41754842e-01 4.49850202e-01] [[[5.56598067e-01 2.42021829e-01 2.45265663e-01 2.95294344e-01]
[8.15511882e-01 4.78223324e-01 6.29803419e-01 1.12592392e-01] [9.83367860e-01 4.36241180e-01 5.68063319e-01 8.96367550e-01]
[1.53732300e-01 7.24954247e-01 9.38574493e-01 4.65665817e-01] [8.71030211e-01 9.32705551e-02 8.51928890e-01 9.48658109e-01]
[9.10354614e-01 4.47880208e-01 3.81429136e-01 9.67544317e-01] ...
[6.07822955e-01 5.20158827e-01 8.17965686e-01 8.42760384e-01]] [6.94550753e-01 6.52826130e-01 6.08456850e-01 4.88614887e-01]
[4.84500438e-01 1.14949882e-01 6.08556986e-01 7.93362781e-02]
[[2.29353935e-01 8.80753636e-01 7.94585168e-01 2.22074524e-01] [9.54909027e-01 3.18913072e-01 4.58294243e-01 7.45387852e-01]]
[6.13970399e-01 1.33511815e-02 2.89155185e-01 2.65219092e-01]
[6.62197351e-01 6.47982001e-01 9.46004018e-02 6.59599364e-01] [[7.51943365e-02 9.95502114e-01 5.04003823e-01 8.36720586e-01]
[4.86104101e-01 4.23153102e-01 1.39821902e-01 3.11809748e-01] [8.18848014e-01 4.04324770e-01 5.49858093e-01 3.51742476e-01]
[8.03322852e-01 9.52799857e-01 3.89638603e-01 6.43237352e-01]] [1.66903093e-01 1.78061739e-01 2.81622916e-01 8.88221264e-01]
...
[[9.70978260e-01 6.75936878e-01 6.23196602e-01 8.42264950e-01] [7.69020915e-01 6.33118331e-01 4.15713340e-01 4.24170971e-01]
[4.07079160e-01 8.46290290e-01 5.64092159e-01 3.56871307e-01] [7.64205098e-01 7.78579533e-01 7.44598091e-01 3.30398619e-01]
[4.84096229e-01 8.60232174e-01 1.39015794e-01 7.82253265e-01] [4.45223182e-01 9.25011218e-01 2.36187894e-02 7.62242600e-02]]
[1.24170482e-01 2.21511930e-01 8.88282284e-02 4.53450561e-01]
[1.28404438e-01 2.87771430e-02 4.57022637e-01 9.80571806e-01]] [[7.73669600e-01 3.54849041e-01 4.21867281e-01 9.16552365e-01]
[4.73650604e-01 1.79305673e-01 8.38760436e-01 3.96051705e-01]
[2.01547332e-02 8.12301695e-01 2.78097481e-01 8.67732406e-01]
...
[8.12627971e-01 6.28660858e-01 2.13196307e-01 6.49513781e-01]
[5.58035910e-01 4.63277161e-01 8.21570277e-01 6.79726541e-01]
[7.10023165e-01 5.45146585e-01 8.51007760e-01 9.56029415e-01]]
[[5.00000000e+01 5.00000000e+01 0.00000000e+00 0.00000000e+00] [[5.00000000e+01 5.00000000e+01 1.00000000e+00 0.00000000e+00]
[ nan nan nan nan]
[ nan nan nan nan] [ nan nan nan nan]
...
[ nan nan nan nan] [ nan nan nan nan]
[ nan nan nan nan] [ nan nan nan nan]
[ nan nan nan nan]] [ nan nan nan nan]]
[[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [[5.00000000e+01 5.00000000e+01 5.00000000e+01 5.00000000e+01]
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [5.00000000e+01 5.00000000e+01 5.00000000e+01 5.00000000e+01]
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] [5.00000000e+01 5.00000000e+01 5.00000000e+01 5.00000000e+01]
[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] ...
[ nan nan nan nan]]] [5.00000000e+01 5.00000000e+01 5.00000000e+01 5.00000000e+01]
[5.00000000e+01 5.00000000e+01 5.00000000e+01 5.00000000e+01]
[5.00000000e+01 5.00000000e+01 5.00000000e+01 5.00000000e+01]]]
Fish poses Fish poses
[[[0.8865841 0.23567082 0.54175484 0.4498502 ] [[[0.55659807 0.24202183 0.24526566 0.29529434]
[0.81551188 0.47822332 0.62980342 0.11259239] [0.98336786 0.43624118 0.56806332 0.89636755]
[0.1537323 0.72495425 0.93857449 0.46566582] [0.87103021 0.09327056 0.85192889 0.94865811]
[0.91035461 0.44788021 0.38142914 0.96754432] ...
[0.60782295 0.52015883 0.81796569 0.84276038]] [0.69455075 0.65282613 0.60845685 0.48861489]
[0.48450044 0.11494988 0.60855699 0.07933628]
[[0.22935393 0.88075364 0.79458517 0.22207452] [0.95490903 0.31891307 0.45829424 0.74538785]]
[0.6139704 0.01335118 0.28915519 0.26521909]
[0.66219735 0.647982 0.0946004 0.65959936] [[0.07519434 0.99550211 0.50400382 0.83672059]
[0.4861041 0.4231531 0.1398219 0.31180975] [0.81884801 0.40432477 0.54985809 0.35174248]
[0.80332285 0.95279986 0.3896386 0.64323735]] [0.16690309 0.17806174 0.28162292 0.88822126]
...
[[0.97097826 0.67593688 0.6231966 0.84226495] [0.76902092 0.63311833 0.41571334 0.42417097]
[0.40707916 0.84629029 0.56409216 0.35687131] [0.7642051 0.77857953 0.74459809 0.33039862]
[0.48409623 0.86023217 0.13901579 0.78225327] [0.44522318 0.92501122 0.02361879 0.07622426]]
[0.12417048 0.22151193 0.08882823 0.45345056]
[0.12840444 0.02877714 0.45702264 0.98057181]]] [[0.7736696 0.35484904 0.42186728 0.91655236]
[0.4736506 0.17930567 0.83876044 0.3960517 ]
[0.02015473 0.8123017 0.27809748 0.86773241]
...
[0.81262797 0.62866086 0.21319631 0.64951378]
[0.55803591 0.46327716 0.82157028 0.67972654]
[0.71002316 0.54514658 0.85100776 0.95602942]]]
File structure File structure
version: [1 0] format_url: https://git.imp.fu-berlin.de/bioroboticslab/robofish/track_format/-/releases/1.0
world size: [100. 100.] format_version: [1 0]
world_size_cm: [100. 100.]
| entities | entities
|---| fish_1 |---| fish_1
|---|--- type: fish |---|--- category: fish
|---|--- poses: Shape (5, 4) |---|--- orientations: Shape (1000, 2)
|---|---| time |---|--- positions: Shape (1000, 2)
|---|---|--- monotonic points: Shape (5,)
|---| fish_2 |---| fish_2
|---|--- type: fish |---|--- category: fish
|---|--- poses: Shape (5, 4) |---|--- orientations: Shape (1000, 2)
|---|---| time |---|--- positions: Shape (1000, 2)
|---|---|--- monotonic points: Shape (5,)
|---| fish_3 |---| fish_3
|---|--- type: fish |---|--- category: fish
|---|--- poses: Shape (5, 4) |---|--- orientations: Shape (1000, 2)
|---|---| time |---|--- positions: Shape (1000, 2)
|---|---|--- monotonic points: Shape (5,)
|---| obstacle_1 |---| obstacle_1
|---|--- type: obstacle |---|--- category: obstacle
|---|--- orientations: Shape (1, 2)
|---|--- outlines: Shape (1, 4, 2) |---|--- outlines: Shape (1, 4, 2)
|---|--- poses: Shape (1, 4) |---|--- positions: Shape (1, 2)
|---|---| time
|---| robot |---| robot
|---|--- type: robot |---|--- category: robot
|---|--- poses: Shape (4, 4) |---|--- orientations: Shape (1000, 2)
|---|---| time |---|--- positions: Shape (1000, 2)
|---|---|--- monotonic step: 40 | samplings
|--- default: 25 hz
|---| 25 hz
|---|--- frequency_hz: 25.0
......
#! /usr/bin/env python3 #! /usr/bin/env python3
import robofish.io import robofish.io
from robofish.io import utils
import numpy as np import numpy as np
......
...@@ -14,9 +14,15 @@ entry_points = { ...@@ -14,9 +14,15 @@ entry_points = {
] ]
} }
def source_version(): def source_version():
version_parts = ( version_parts = (
run(["git", "describe", "--tags", "--dirty"], check=True, stdout=PIPE, encoding="utf-8") run(
["git", "describe", "--tags", "--dirty"],
check=True,
stdout=PIPE,
encoding="utf-8",
)
.stdout.strip() .stdout.strip()
.split("-") .split("-")
) )
...@@ -36,12 +42,20 @@ def source_version(): ...@@ -36,12 +42,20 @@ def source_version():
return version return version
setup( setup(
name="robofish-io", name="robofish-io",
version=source_version(), version=source_version(),
author="", author="",
author_email="", author_email="",
install_requires=["h5py>=3", "numpy", "seaborn", "pandas", "deprecation"], install_requires=[
"h5py>=3",
"numpy",
"seaborn",
"pandas",
"deprecation",
"testbook",
],
classifiers=[ classifiers=[
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Intended Audience :: Science/Research", "Intended Audience :: Science/Research",
......
...@@ -98,7 +98,7 @@ class Entity(h5py.Group): ...@@ -98,7 +98,7 @@ class Entity(h5py.Group):
else: else:
if poses is not None: if poses is not None:
assert poses.shape[1] == 3 or poses.shape[1] == 4 assert poses.shape[1] in [3, 4]
positions = poses[:, :2] positions = poses[:, :2]
orientations = poses[:, 2:] orientations = poses[:, 2:]
if orientations is not None and orientations.shape[1] == 1: if orientations is not None and orientations.shape[1] == 1:
......
...@@ -22,7 +22,7 @@ def test_app_validate(): ...@@ -22,7 +22,7 @@ def test_app_validate():
self.names = None self.names = None
self.save_path = graphics_out self.save_path = graphics_out
# TODO: Get rid of deprecated get_poses function # TODO: Get rid of deprecation
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
app.evaluate(DummyArgs("speed")) app.evaluate(DummyArgs("speed"))
graphics_out.unlink() graphics_out.unlink()
import robofish.io import robofish.io
from robofish.io import utils from robofish.io import utils
from pathlib import Path from pathlib import Path
from testbook import testbook
import sys import sys
sys.path.append(str(utils.full_path(__file__, "../../../examples/"))) sys.path.append(str(utils.full_path(__file__, "../../../examples/")))
ipynb_path = utils.full_path(__file__, "../../../examples/example_basic.ipynb")
path = utils.full_path(__file__, "../../../examples/tmp_example.hdf5") path = utils.full_path(__file__, "../../../examples/tmp_example.hdf5")
if path.exists(): if path.exists():
path.unlink() path.unlink()
...@@ -24,3 +25,9 @@ def test_example_basic(): ...@@ -24,3 +25,9 @@ def test_example_basic():
example_basic.create_example_file(path) example_basic.create_example_file(path)
path.unlink() path.unlink()
def test_example_basic_ipynb():
# Executing the notebook should not lead to an exception
with testbook(str(ipynb_path), execute=True) as tb:
pass
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment