diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..68107df --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: Test viewer + +on: + push: + branches: [ main, development, test* ] + pull_request: + branches: [ main, development, test* ] + +jobs: + build: + + runs-on: ${{ matrix.runs-on }} + strategy: + fail-fast: false + matrix: + runs-on: [ubuntu-latest] + python-version: [ "3.10", "3.12" ] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install ffmpeg -y + pip install numpy matplotlib ruff + + - name: Test WCONViewer + run: | + ./test_all.sh + + + - name: Print info on files + run: | + ls -alt diff --git a/.gitignore b/.gitignore index 225fc6f..6cd32ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /__pycache__ +/.DS_Store diff --git a/Player.py b/Player.py index 5dc9a1c..94ac666 100644 --- a/Player.py +++ b/Player.py @@ -19,6 +19,8 @@ def __init__( mini=0, maxi=100, pos=(0.125, 0.92), + times=None, + t_units="", **kwargs, ): self.i = 0 @@ -39,6 +41,8 @@ def __init__( save_count=save_count, **kwargs, ) + self.times = times + self.t_units = t_units def play(self): while self.runs: @@ -82,6 +86,7 @@ def onestep(self): self.i -= 1 self.func(self.i) self.slider.set_val(self.i) + self.fig.canvas.draw_idle() def setup(self, pos): @@ -105,14 +110,32 @@ def setup(self, pos): self.slider = matplotlib.widgets.Slider( sliderax, "", self.min, self.max, valinit=self.i ) + self.slider.valtext.set_visible(False) self.slider.on_changed(self.set_pos) + self.slider.label.set_horizontalalignment("left") + label_position = self.slider.label.get_position() # Get the current position + self.slider.label.set_position( + (label_position[0] + 1.1, label_position[1]) + ) # Adjust x-coordinate + + # self.text_box = matplotlib.widgets.TextBox(textax, label="", initial="0 ms") def set_pos(self, i): self.i = int(self.slider.val) self.func(self.i) + self.set_time_text(self.i) + + def set_time_text(self, i): + time_text = str(i) + if self.times is not None: + time_text = "%s%s" % (self.times[i], self.t_units) + + # self.text_box.set_val(time_text) + self.slider.label.set_text(time_text) def update(self, i): self.slider.set_val(i) + self.set_time_text(i) if __name__ == "__main__": diff --git a/WormView.py b/WormView.py index d85e7f1..1263564 100644 --- a/WormView.py +++ b/WormView.py @@ -127,12 +127,22 @@ def main(): ax.set_ylim([-1.5, 1.5]) - t = np.array(wcon["data"][0]["t"]) + t_units = "" + x_units = "" + y_units = "" + + if "units" in wcon: + t_units = wcon["units"].get("t") + x_units = wcon["units"].get("x") + y_units = wcon["units"].get("y") + print(f"Time units: {t_units}, x units: {x_units}, y units: {y_units}") + + times = np.array(wcon["data"][0]["t"]) x = np.array(wcon["data"][0]["x"]).T y = np.array(wcon["data"][0]["y"]).T print( - f"Range of time: {t[0]}->{t[0]}; x range: {x.max()}->{x.min()}; y range: {y.max()}->{y.min()}" + f"Range of time: {times[0]}{t_units}->{times[-1]}{t_units}; x range: {x.max()}{x_units}->{x.min()}{x_units}; y range: {y.max()}{y_units}->{y.min()}{y_units}" ) factor = 0.05 if abs(x.max() - x.min()) > abs(y.max() - y.min()): @@ -146,7 +156,7 @@ def main(): mid = (x.max() + x.min()) / 2 ax.set_xlim([mid - side * (0.5 + factor), mid + side * (0.5 + factor)]) - num_steps = t.size + num_steps = times.size if "px" in wcon["data"][0] and "py" in wcon["data"][0]: if args.ignore_wcon_perimeter: @@ -170,13 +180,14 @@ def main(): def update(ti): global midline_plot, perimeter_plot f = ti / num_steps + t = times[ti] color = "#%02x%02x00" % (int(0xFF * (f)), int(0xFF * (1 - f) * 0.8)) - print("Time step: %s, fract: %f, color: %s" % (ti, f, color)) + print("Time %s%s, step: %s, fract: %f, color: %s" % (t, t_units, ti, f, color)) if midline_plot is None: (midline_plot,) = ax.plot( - x[:, ti], y[:, ti], color="g", label="t=%sms" % t[ti], linewidth=0.5 + x[:, ti], y[:, ti], color="g", label="t=%sms" % times[ti], linewidth=0.5 ) else: midline_plot.set_data(x[:, ti], y[:, ti]) @@ -189,7 +200,9 @@ def update(ti): else: perimeter_plot.set_data(px[:, ti], py[:, ti]) - anim = Player(fig, update, maxi=num_steps - 1) + anim = Player( + fig, update, maxi=num_steps - 1, times=[t for t in times], t_units=t_units + ) # TODO WormViewCSV and WormViewWCON - should WormViewCSV just be the original WormView? That's what it initially did. # TODO Could take out Player and WormViewWCON into separate repo - Taking out Player could be ugly. It is quite coupled with WormView due to the update function.