diff --git a/examples/example_basic.py b/examples/example_basic.py index 70c39b6b862543abba085657a339d4588b8cb67c..359e4d01983bbf67b125ffd34f1d7a97f11e5c05 100755 --- a/examples/example_basic.py +++ b/examples/example_basic.py @@ -5,48 +5,53 @@ from robofish.io import utils import numpy as np -# Create a new io file object with a 100x100cm world -sf = robofish.io.File(world_size_cm=[100, 100], frequency_hz=25.0) +def create_example_file(path): + # Create a new io file object with a 100x100cm world + sf = robofish.io.File(world_size_cm=[100, 100], frequency_hz=25.0) -# create a simple obstacle, fixed in place, fixed outline -obstacle_outline = [[[-10, -10], [-10, 0], [0, 0], [0, -10]]] -obstacle_name = sf.create_entity( - "obstacle", positions=[[50, 50]], orientations=[[0]], outlines=obstacle_outline -) + # create a simple obstacle, fixed in place, fixed outline + obstacle_outline = [[[-10, -10], [-10, 0], [0, 0], [0, -10]]] + obstacle_name = sf.create_entity( + "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. -robofish_timesteps = 1000 -robofish_poses = np.ones((robofish_timesteps, 4)) * 50 -robot = sf.create_entity("robot", robofish_poses, name="robot") + # create a robofish with 1000 timesteps. If we would not give a name, the name would be generated to be robot_1. + robofish_timesteps = 1000 + robofish_poses = np.ones((robofish_timesteps, 4)) * 50 + 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"] -agents = 3 -timesteps = 1000 -# timestamps = np.linspace(0, timesteps + 1, timesteps) -agent_poses = np.random.random((agents, timesteps, 4)) + # 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 + timesteps = 1000 + # timestamps = np.linspace(0, timesteps + 1, timesteps) + agent_poses = np.random.random((agents, timesteps, 4)) -fishes = sf.create_multiple_entities("fish", agent_poses) + fishes = sf.create_multiple_entities("fish", agent_poses) -# This would throw an exception if the file was invalid -sf.validate() + # This would throw an exception if the file was invalid + sf.validate() -# Save file validates aswell -example_file = utils.full_path(__file__, "example.hdf5") -sf.save_as(example_file) + # Save file validates aswell -# Closing and opening files (just for demonstration) -sf.close() -sf = robofish.io.File(path=example_file) + sf.save_as(path) -print("\nEntity Names") -print(sf.entity_names) + # Closing and opening files (just for demonstration) + sf.close() + sf = robofish.io.File(path=path) -# Get an array with all poses. As the length of poses varies per agent, it is filled up with nans. -print("\nAll poses") -print(sf.poses) + print("\nEntity Names") + print(sf.entity_names) -print("\nFish poses") -print(sf.select_poses(lambda e: e.category == "fish")) + # Get an array with all poses. As the length of poses varies per agent, it is filled up with nans. + print("\nAll poses") + print(sf.poses) -print("\nFile structure") -print(sf) + print("\nFish poses") + print(sf.select_poses(lambda e: e.category == "fish")) + + print("\nFile structure") + print(sf) + + +if __name__ == "__main__": + create_example_file("example.hdf5") diff --git a/examples/example_readme.py b/examples/example_readme.py index 71442e29faac159ffc739a10340ea65ecc64e005..cec24cf35dfe83115e16cfd317f01d4a9078ef9a 100644 --- a/examples/example_readme.py +++ b/examples/example_readme.py @@ -2,34 +2,35 @@ import robofish.io import numpy as np from pathlib import Path -path = Path("example.hdf5") -if path.exists(): - path.unlink() +def create_example_file(path): + # By using the context, the file will be automatically validated + with robofish.io.File(path, "w", world_size_cm=[100, 100], frequency_hz=25.0) as f: + f.attrs["experiment_setup"] = "This is a simple example with made up data." -# By using the context, the file will be automatically validated -with robofish.io.File(path, "w", world_size_cm=[100, 100], frequency_hz=25.0) as f: - f.attrs["experiment_setup"] = "This is a simple example with made up data." + # Create a single robot with 30 timesteps + # positions are passed separately + # orientations are passed as with two columns -> orientation_x and orientation_y + f.create_entity( + category="robot", + name="robot", + positions=np.zeros((100, 2)), + orientations=np.ones((100, 2)) * [0, 1], + ) - # Create a single robot with 30 timesteps - # positions are passed separately - # orientations are passed as with two columns -> orientation_x and orientation_y - f.create_entity( - category="robot", - name="robot", - positions=np.zeros((100, 2)), - orientations=np.ones((100, 2)) * [0, 1], - ) + # Create fishes with 30 poses (x, y, orientation_rad) + poses = np.zeros((100, 3)) + poses[:, 0] = np.arange(-50, 50) + poses[:, 1] = np.arange(-50, 50) + poses[:, 2] = np.arange(0, 2 * np.pi, step=2 * np.pi / 100) + fish = f.create_entity("fish", poses=poses) + fish.attrs["species"] = "My rotating spaghetti fish" + fish.attrs["fish_standard_length_cm"] = 10 - # Create fishes with 30 poses (x, y, orientation_rad) - poses = np.zeros((100, 3)) - poses[:, 0] = np.arange(-50, 50) - poses[:, 1] = np.arange(-50, 50) - poses[:, 2] = np.arange(0, 2 * np.pi, step=2 * np.pi / 100) - fish = f.create_entity("fish", poses=poses) - fish.attrs["species"] = "My rotating spaghetti fish" - fish.attrs["fish_standard_length_cm"] = 10 + # Show and save the file + print(f) + print("Poses Shape: ", f.poses.shape) - # Show and save the file - print(f) - print("Poses Shape: ", f.poses.shape) + +if __name__ == "__main__": + path = create_example_file("example.hdf5") diff --git a/src/robofish/io/file.py b/src/robofish/io/file.py index 2a9392743892c72cd3b4e72c3c45774681e5e553..3e3b0121794a968d3d84bee488200f817f6127bb 100644 --- a/src/robofish/io/file.py +++ b/src/robofish/io/file.py @@ -129,8 +129,10 @@ class File(h5py.File): return self def __exit__(self, type, value, traceback): - self.validate() - self.close() + # Check if the context was left under normal circumstances + if (type, value, traceback) is (None, None, None): + self.validate() + self.close() def save_as(self, path: Union[str, Path], strict_validate: bool = True): """ Save a copy of the file diff --git a/tests/robofish/io/test_examples.py b/tests/robofish/io/test_examples.py index 94b60155e311d41dd87fc650a6863f496d7cdc59..1d0379fb1b06448e5f733c3690ff48a4f623592c 100644 --- a/tests/robofish/io/test_examples.py +++ b/tests/robofish/io/test_examples.py @@ -7,9 +7,20 @@ import sys sys.path.append(str(utils.full_path(__file__, "../../../examples/"))) +path = utils.full_path(__file__, "../../../examples/tmp_example.hdf5") +if path.exists(): + path.unlink() + + def test_example_readme(): import example_readme + example_readme.create_example_file(path) + path.unlink() + def test_example_basic(): import example_basic + + example_basic.create_example_file(path) + path.unlink()