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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/old
/build
/*.egg-info
/wconviewer/__pycache__
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Saving animations with `-nogui` requires the `ffmpeg` binary to be installed on
## Usage

```
wconviewer -f examples/simdata.wcon
wconviewer examples/simdata.wcon
```

Run `wconviewer -h` for all options (e.g. `-nogui` to save an `.mp4` instead of showing a window).
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "WCONViewer"
version = "0.1.0"
version = "0.2.0"
description = "Viewer for WCON (Worm tracker Commons Object Notation) files in 2D"
readme = "README.md"
license = { file = "LICENSE" }
Expand Down
8 changes: 4 additions & 4 deletions test_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ ruff check wconviewer app.py

pip install .

wconviewer -f examples/simdata.wcon -nogui -z # Test reloading WCON in Player
wconviewer -f examples/worm_motion_log.wcon -nogui -g
wconviewer -f examples/output_W2D.wcon -nogui -g -z
wconviewer examples/simdata.wcon -nogui -z # Test reloading WCON in Player
wconviewer examples/worm_motion_log.wcon -nogui -g
wconviewer examples/output_W2D.wcon -nogui -g -z

#wconviewer -f examples/N2\ on\ food\ L_2009_09_15__11_01_01___8___1.wcon.zip -nogui
#wconviewer examples/N2\ on\ food\ L_2009_09_15__11_01_01___8___1.wcon.zip -nogui
10 changes: 10 additions & 0 deletions wconviewer/Player.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(
zoom_state=False,
on_toggle_grid=None,
on_toggle_zoom=None,
start_play=True,
**kwargs,
):
self.i = 0
Expand Down Expand Up @@ -53,6 +54,15 @@ def __init__(
self.times = times
self.t_units = t_units

if not start_play:
# The animation timer is started by matplotlib on the first draw, so
# pause it from a draw callback registered after matplotlib's own.
def pause_after_first_draw(event):
self.fig.canvas.mpl_disconnect(cid)
self.stop()

cid = self.fig.canvas.mpl_connect("draw_event", pause_after_first_draw)

def play(self):
while self.runs:
self.i = self.i + self.step * (1 if self.forwards else -1)
Expand Down
65 changes: 49 additions & 16 deletions wconviewer/WormView.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,21 @@ def set_show_grid(self, value):
self.ax.grid(False, which="major")
self.ax.grid(False, which="minor")

def get_plot(self, args):
def get_plot(
self,
wcon_file,
ignore_wcon_perimeter=False,
suppress_automatic_generation=False,
minor_radius=40e-3,
):
# global times, t_units, x, y, px, py, ax

self.fig, self.ax = plt.subplots()

plt.get_current_fig_manager().set_window_title("WCON replay")
self.ax.set_aspect("equal")

self.wcon = SimpleWCON(args.wcon_file)
self.wcon = SimpleWCON(wcon_file)

self.ax.set_xlabel("x (%s)" % self.wcon.x_units_used)
self.ax.set_ylabel("y (%s)" % self.wcon.y_units_used)
Expand Down Expand Up @@ -181,20 +187,20 @@ def get_plot(self, args):
print("No objects found")

if self.wcon.px is not None and self.wcon.py is not None:
if args.ignore_wcon_perimeter:
if ignore_wcon_perimeter:
print(
"Ignoring (px, py) values in WCON file and computing perimeter from midline."
)
self.px, self.py = self.get_perimeter(self.x, self.y, args.minor_radius)
self.px, self.py = self.get_perimeter(self.x, self.y, minor_radius)
else:
print("Using (px, py) from WCON file")
self.px = np.array(self.wcon.px).T
self.py = np.array(self.wcon.py).T
else:
if not args.suppress_automatic_generation and self.wcon.x.shape[0] >= 2:
if not suppress_automatic_generation and self.wcon.x.shape[0] >= 2:
print("Computing perimeter from midline")
self.px, self.py = self.get_perimeter(
self.wcon.x, self.wcon.y, args.minor_radius
self.wcon.x, self.wcon.y, minor_radius
)
else:
print("Not computing perimeter from midline")
Expand Down Expand Up @@ -273,11 +279,10 @@ def parse_args():
description="Open a player for the worm behaviour."
)
parser.add_argument(
"-f",
"--wcon_file",
"wcon_file",
type=validate_file,
metavar="WCON_FILE",
help="WCON file path",
required=True,
)
parser.add_argument(
"-nogui", action="store_true", help="Just load file, don't show GUI"
Expand Down Expand Up @@ -333,13 +338,39 @@ def main():

print(" - Arguments parsed: %s" % args)

show_worm_view(
args.wcon_file,
args.show_head,
args.zoom_to_worm,
args.show_grid,
args.nogui,
args.ignore_wcon_perimeter,
args.suppress_automatic_generation,
args.minor_radius,
)


def show_worm_view(
wcon_file: str,
show_head: bool = False,
zoom_to_worm: bool = False,
show_grid: bool = False,
nogui: bool = False,
ignore_wcon_perimeter: bool = False,
suppress_automatic_generation: bool = False,
minor_radius: float = 40e-3,
start_play: bool = True,
):

wv = WormView(
show_head=args.show_head,
zoom_to_worm=args.zoom_to_worm,
show_grid=args.show_grid,
show_head=show_head,
zoom_to_worm=zoom_to_worm,
show_grid=show_grid,
)

fig, ax = wv.get_plot(args)
fig, ax = wv.get_plot(
wcon_file, ignore_wcon_perimeter, suppress_automatic_generation, minor_radius
)

def update(ti):
print(" ------ Animating the plot for time index: %d" % ti)
Expand All @@ -355,22 +386,24 @@ def update(ti):
zoom_state=wv.zoom_to_worm,
on_toggle_grid=wv.set_show_grid,
on_toggle_zoom=wv.set_zoom_to_worm,
# When saving a movie (nogui) the animation always runs through
start_play=start_play or nogui,
)

if args.nogui:
if nogui:
# Checkboxes are only useful for interactive control; don't bake them
# into the frames used for the saved movie.
anim.check_buttons.ax.set_visible(False)

if not args.nogui:
if not nogui:
plt.show()
else:
print("GUI suppressed, exiting without showing %s." % anim)

from matplotlib.animation import FFMpegWriter

FFwriter = FFMpegWriter(fps=10)
mp4_file = args.wcon_file.replace(".wcon.zip", ".wcon").replace(".wcon", ".mp4")
mp4_file = wcon_file.replace(".wcon.zip", ".wcon").replace(".wcon", ".mp4")
print(f"Saving animation to: {mp4_file}")
anim.save(mp4_file, writer=FFwriter)

Expand Down
Loading