The results monitor

A long simulation, a parameter variation that runs overnight, a genetic optimization on a cluster: all of them write their results to a file while they run. The results monitor shows that file as it grows — it re-reads what has been appended since the last update and redraws the curves, until the window is closed.

It reads the four kinds of file Exudyn writes: a sensor file, a coordinates solution file, and the resultsFile of ParameterVariation and GeneticOptimization. Which one it is does not have to be said; the header of the file tells it.

Three ways to call it

python -m exudyn monitor --last                 #the newest results file that is found
python -m exudyn monitor solution/genetic.txt   #a given file
python -m exudyn.misc.resultsMonitor f.txt      #the module directly, same options

and from a script or from the Spyder console:

from exudyn.misc.resultsMonitor import MonitorResults
MonitorResults('solution/genetic.txt', logY=True, updatePeriod=0.5)

MonitorResults(...) is the function; the command line is a thin layer over it. Everything the options do is available as an argument, and help(MonitorResults) describes them.

MonitorResults(...) blocks until its window is closed, which is what is wanted in a console and not what is wanted in a script that still has to run the simulation. For that there is

from exudyn.misc.resultsMonitor import StartResultsMonitor
StartResultsMonitor('solution/sensorPos.txt', updatePeriod=0.5)
mbs.SolveDynamic(simulationSettings)     #the plot follows the file while this runs

StartResultsMonitor(...) starts the monitor as a second process - python -m exudyn monitor with the options it was given - and returns at once. The two processes share nothing but the file, which is the protocol they already had, so there is no plotting inside the solver and no question of threads. The file does not have to exist yet: the monitor waits for it to appear and for its first row, and says which file it is waiting for.

The process is not stopped when the script ends, so the plot is still there when a short simulation is over; the returned subprocess.Popen is the handle for a script that wants it gone. Nothing is started when windows are suppressed (EXUDYN_SUPPRESS_UI_WINDOW_OPEN, exudyn.special.userInterface.suppressPlots), so a test that runs such a script neither opens a window nor leaves a process behind. 3SpringsDistance.py watches the coordinates solution this way.

Finding the file

Typing a path is the part that used to make the monitor awkward, so there are three ways around it:

  • --last takes the most recently written results file it finds.

  • no file name at all opens a file dialog; without tkinter, a numbered list in the terminal.

  • --list-files prints the results files that were found and their type, and exits.

It looks in exudyn.config.outputDirectory, in solution/ and in the current directory; --dir DIR adds another place and may be given repeatedly.

Choosing what is drawn

By default a sensor or solution file is drawn over time, with every column except time; an optimization file is drawn over its varied parameters.

python -m exudyn monitor f.txt --list-columns       #which column is which, with indices
python -m exudyn monitor f.txt -y 2,3 --log-y       #only these columns, logarithmic

--list-columns exists because guessing a column index from a file is the second thing that used to make the monitor awkward. For a parameter variation, --color-variations draws the first parameter only and gives every variation of the remaining parameters its own colour.

The control panel

Next to the plot there is a small window (tkinter, part of the standard library — no extra dependency) which changes what you are looking at without restarting the run:

  • pause and resume the updates, and change the update period;

  • logarithmic x / y, autoscale on or off;

  • one checkbox per curve, up to 16 curves;

  • save figure… and save data… (the plotted data as CSV);

  • open file…, which points the monitor at another results file.

--no-panel leaves it out. If tkinter is missing, or windows are suppressed, the monitor says so in one line and draws the plot without the panel.

Settings that survive

What you set in the panel is stored in ~/.exudyn/config.json, under resultsMonitor — update period, log scales, autoscale, window size, whether the panel is shown, and the directory last used. It is the one file Exudyn remembers anything in (User settings that persist between runs). The next monitor starts the way the last one ended. --no-settings neither reads nor writes it, which is what a reproducible script or a test wants.

An option given on the command line always wins over the stored setting.

The monitor does not take the keyboard focus and does not come to the front while it updates. It did until 1.12.104, because the update used matplotlib.pyplot.pause, which raises and focuses the window every time it is called - once per update period - so the control panel beside the plot could not be typed into. If you want the window above the others, --always-on-top (or alwaysOnTop=True) does that, and it still leaves the keyboard where it was.

In a script, in a test, on a server

python -m exudyn monitor f.txt --once --save results.png

--once draws the file as it is, writes --save if given, and returns instead of entering the update loop. That is what makes the monitor usable where nobody can close a window — a CI job, a batch script, a machine reached over SSH — and it is how the monitor itself is tested (python/TestModels/resultsMonitorTest.py).

The same happens automatically when window opening is suppressed (EXUDYN_SUPPRESS_UI_WINDOW_OPEN, exudyn.special.userInterface.suppressPlots): the monitor draws once and returns rather than waiting for a human who is not there.

Every option

python -m exudyn monitor --help

The options are grouped there — what to plot, appearance, updating — and that list is generated from the program itself, so it cannot go out of date the way a list printed in a manual can.