Did you ever miss a certain feature in your ILNumerics scene graph? You probably did. But did you know, that most of the missing “features” mean nothing more than a missing “property”? Often enough, there is only a convenient access to a certain scene graph object needed in order to finalize a required configuration.
Recently, a user asked how to turn the background of a legend object in ILNumerics plots transparent. There doesn’t seem to be a straight forward way to that. One might expect code like the following to work:
var legend = new ILLegend("Line 1", "Line 2"); legend.Background.Color = Color.FromArgb(200, Color.White);
Unfortunately, it does not. Legend objects do not implement a ‘Background’ property which would give convenient access to the background object. However, the background object obviously exists. And ILLegend – likewise most of the more complex scene graph / plotting objects in ILNumerics – is derived from ILGroup! Group nodes represent the common way to store and manage any number of child objects. At the same time, group nodes gives the user flexible access to their children.
In case of ILLegend we can utilize one of the access methods of ILGroup in order to access the scene graph node which implements the background of the legend. Once we have the background object, we can go out and manipulate it freely. In order to do that, let’s first investigate, which nodes exist inside a legend object!
Stepping into living Scene Graphs
ILNumerics and Visual Studio make it very easy to investigate even complex scenes. Let’s create a simple line plot application first! We start with a fresh new C# Windows Forms Application and add a Plotting Form Template to it. A detailed instruction is given on the getting started page, at “Creating Visualizations with ILNumerics“.
Double click on the auto-generated Program.cs file and change the last line to read:
Application.Run(new Plotting_Form1());
Starting the project via F5 brings up the newly generated example plot. We make one more addition. Double click the Plotting_Form1.cs to show the form in the designer. Now, double click on the white panel1 background to go to the code implementing the scene setup. At the end of the code creating the new plot cube and adding the line plot we add another line which adds a new legend object:
// Initial plot setup, modify this as needed private void ilPanel1_Load(object sender, EventArgs e) { // create some test data, using our private computation module as inner class ILArray<float> Pos = Computation.CreateData(4, 300); // setup the plot (modify as needed) ilPanel1.Scene.Add(new ILPlotCube(twoDMode: false) { new ILLinePlot(Pos, tag: "mylineplot") { Line = { Width = 2, Color = Color.Red, Antialiasing = true, DashStyle = DashStyle.Dotted } }, new ILLegend("MyLineItem") }); // register event handler for allowing updates on right mouse click: ilPanel1.Scene.First<ILLinePlot>().MouseClick += (_s, _a) => { if (_a.Button == MouseButtons.Right) Update(ILMath.rand(3, 30)); }; }
Starting via F5 should give a form similar like this:
Now, let’s start the fun! Investigating living objects works best when the objects are alive, right? So let’s set a breakpoint in Visual Studio right after the legend has been created:
As you know, Visual Studio allows for a nice feature ‘Edit and Continue’. Let’s add a variable as reference to our legend right in Debug mode! This is not really necessary, but eases the inspection. Note, it does not matter, where to add the code line, as long as we step over it in the debugger:
var leg = ilPanel1.Scene.First<ILLegend>();
Scene graph nodes are clever enough to give reasonable insights into their state and content at runtime. Just hover over the newly created variable ‘leg’ with the mouse and Visual Studio will display helpful debugger visualizers. Expand any node to show its content:
Inspecting the legend object that way makes it immediately clear, which object legends are made out of: a triangle shape realizes the background, a line strip shape the border. A common group holds the individual legend items and will be filled dynamically at rendering time.
Configuration Flexibility at its Extreme
Having access to every single child item in the scene graph obviously brings an extreme flexibility for configurations. Now it is easy to change the color of the background object to make the legend transparent:
var leg = ilPanel1.Scene.First<ILLegend>(); leg.First<ILTriangles>("ScreenObjectBackground").Color = Color.FromArgb(200, Color.White);
Which gives us our transparent legend:
Do not stop here!
This is the message to take away: any object in any visualization and any plot in ILNumerics is composed out of individual smaller objects. You can access them and manipulate them freely without limits! Most ‘convenience’ properties like “colorbar.Background” barely do more than we have done here: they give easy access to inner children (and add Intellisense support, of course). But if you need access – you can easily gain it yourself by inspecting the scene graph and its objects by the methods described here.