wow, that's looking really good - not just referring to the screenshot, but also to the code you've written, really clean and compact !
for the vsd part, you can probably simplify the code by introducing a PropertyPlotter helper that maps the property/value vector to the polyline vector, and a terrain/altitude plotter - the common requirement for the Graph class would be to have setter/update methods that accept a func which returns the values to be updated/added.
Besides, since terrain sampling in Nasal is generally known to be a potential performance bottleneck, I would also suggest to make the property sampler routine itself configurable by passing a func that does the sampling - e.g. something like .setTerrainSampler() - that way, different methods can be used/tested more easily.
One thing that you might want to consider is reusing the same graph to show different plots (same axis alignment) - i.e. you would set up one group per polyline (plot), and then render those to the same x/y graph - basically, your graph class would use a vector (or maybe a hash) to store a list a of values that are to be rendered.
Regarding your io.load_nasal() approach, I mentioned a possible workaround to deal with both scenarios in a portable fashion here:
http://wiki.flightgear.org/Talk:How_to_ ... s_elementsAgain, this is really looking good - and I am sure that you can see the benefits of using such a decoupled design, because troubleshooting/benchmarking and optimizations can now be done easily at the graph.nas level, while benefiting all applications using your new API.
PS: To see if the current class/object setup works properly, you could try to instantiate multiple different graphs and add them to the same dialog, e.g. showing different properties (altitude over terrain, vs, groundspeed over time) - that should be easy to do using your existing code, i.e. a PropertySampler routine could show different property trends.