As you might be aware, I've been working lately on implementing NetLogo's plotting functionality in Tortoise. We're interested in allowing our users to plug in any plotting library they might like to use, rather than locking them in to one particular library with Tortoise. We're looking for a library that supports nice-looking, performant, real-time plotting and accommodates all of NetLogo's plotting functionality. (The "performant, real-time plotting" part is the toughest one to come by.) Thus far, I've only found one library that meets those criteria: Highcharts. The next-closest was Lab Grapher, but it has some shortcomings that prevent it from fulfilling our needs. I currently intend to ship Tortoise with Highcharts by default, but, if you guys are interested in making Lab Grapher a viable option for use with NetLogo's plotting functionality, I detail below the things that could be done to make it more usable on our end.
I've created a repository where I converted a Tortoise standalone model to incorporate a graph from Lab Grapher and a graph from Highcharts. It's a bit annoying and noisy that Lab Grapher requires you to supply the CSS and library files, yourself, but the actual important changes are in the 'wolfsheep.html' file. Other minor annoyances include having to manually size the `div` here, and having to prepend the `div`'s ID with a '#' here, but, again, that stuff really is pretty minor. The fundamental thing that I was looking at here involved how an adapter is constructed for a given plotting library. Namely, the important stuff resides in the `resize`, `reset`, `registerPen`, `resetPen`, `addPoint`, and `updatePenMode` functions declared in each adapter's constructor, so I'll go over those functions a bit here.
- Purpose: Adjust the max/min of the graph's axes through the passed-in arguments (`xMin`, `xMax`, `yMin`, `yMax`)
- Called when: the plot is initialized/cleared, bounds are explicitly expanded via NetLogo code, bounds are implicitly expanded via adding a data point while NetLogo's "autoplotting" is enabled, or when bounds are forced to remain the same via a point being added that would implicitly expand the bounds if not for the fact that "autoplotting" is disabled for this plot. Suffice it to say that this is called very often by the Tortoise plotting functionality to manage plot bounds. I've made the conscious decision to not leave autoscaling up the plotting library, because some libraries (e.g. Highcharts) don't seem to allow a way to disable autoscaling, and some libraries (e.g. Highcharts) don't give you any way to tell it how much to resize the axis when autoscaling, and that leads to poor performance when some libraries (e.g. Highcharts) resize the plot everytime a new point is added.
- Pain points: Nothing, really
- Purpose: Restore the plot visualization to its default, point-free state
- Called when: the plot is initialized, or when the `clear-plot` or `clear-all` (or related) prims are called in NetLogo code
- Pain points: Not much; it works how I want it to, but it would be nice to see some documentation regarding which arguments are mandatory and which aren't, and what those arguments do. In general, documentation would really be helpful in many other areas of Lab Grapher, as well.
- Purpose: Add a pen to the graphical plot, such that it shows up in the legend and is initialized correctly for further plotting
- Called when: the plot is initialized/cleared, or when a pen is added to a plot mid-run via the `create-temporary-plot-pen` primitive
- Pain points: This is an area where there's some major pain. First and foremost, it's not apparent to me that Lab Grapher even supports multiple pens on the same plot. If it doesn't/won't, that's a major show-stopper for Tortoise; it's something that we fundamentally need. Also, it's not clear to me how I can set the color of a pen, nor how I can enable the legend. The Lab Grapher source file makes mention of a legend and suggests that it can be enabled by setting `legendVisible: true` in the options, but that doesn't appear to have any effect for me. Since I don't know for certain what is and isn't supported by Lab Grapher, it's entirely possible that all of my complaints here (and about Lab Grapher in general) could just be solved by documentation.
- Purpose: Set a pen into its initial state (generally, this just entails deleting all existing points for the pen)
- Called when: a pen/plot is initialized/cleared, or when the `reset-pen` primitive is called
- Pain points: Nothing, really, but, should Lab Grapher ever support multiple pens, it would be nice for the Lab Grapher pen objects to have a pleasant `resetPoints` method like the plot object currently has
- Purpose: Plot a new point
- Called when: a point is added to a pen
- Pain points: Lab Grapher seems to lack the ability to set the color of the new point. Ideally, I would be able to specify this through a CSS RGB string (e.g. "rgb(255, 255, 255)") and include it as an argument of some sort to Lab Grapher's `addPoint` function. Personally, I don't like that this is one of NetLogo plotting's many quirky features (in good company with other abominations like being able to add a point at a lesser 'x' value than the last 'x' value plotted, essentially plotting backwards), but changing plot pen colors mid-run is something Tortoise needs to support for the time being for full backwards compatibility with NetLogo.
- Purpose: Change the display mode of the current pen (e.g. change a line graph into bar graph)
- Called when: when a pen is initialized/cleared, or when the `set-plot-pen-mode` primitive is called
- Pain points: Alongside `registerPen`, this is the other major pain point. NetLogo currently supports three types of plots: line plots, bar plots, and scatterpoint plots. As far as I can tell, Lab Grapher only supports line plots, so this is another show-stopper for us. It would be great if these other two plot types were supported. Tortoise needs a bit more than just having basic support for those plotting types, though; it also needs to be able to change an existing pen's display mode mid-run.
That's my overview of the points of possible improvement for Lab Grapher. None of this stuff is holding us up in any way; I plan to ship Tortoise plotting with Highcharts, which meets all of our needs (as far as I can tell), but, if you guys have an interest in Lab Grapher one day being a pluggable plotting solution in Tortoise (or even if you just want to make it better for use by the public at large), it would be great to see this stuff addressed. Of course, let me know if you have any questions about any of this.