Pharo offers many powerful and extensible software development tools. One of them is the Inspector, designed to inspect any Pharo object. The Inspector is a central tool in Pharo as it allows you to see the internal representation of an object, intimately interact with an object through an evaluation panel, and define visual representations of an object.
Visualizations built with Roassal can be hooked into the Inspector. Furthermore, navigation through the graph of objects happens by simply clicking Roassal shapes, which can open a new visualization, itself showing clickable shapes. This chapter details the mechanism to embed Roassal visualizations in the Pharo Inspector.
In addition to detailing the support of Roassal by the Inspector, the chapter illustrates the use of Chart (the charting library of Roassal) and Mondrian (the graph library of Roassal).
Pharo Inspector
The Pharo Inspector can be invoked in a number of ways. You can send the inspect message to any object to open the Inspector. For example, you can open the Playground and execute the following code by pressing Cmd+D (on macOS) or Alt+D (on Linux and Windows) or by right-clicking Do It (see Figure 13-1):
c := OrderedCollection new.
c add: 10.
c add: 15.
c add: 19.
c inspect
The action of sending inspect opens a new window. Although this can be convenient in many situations, the Inspector can also be open within the Playground window. You can press Cmd+G/Alt+G to embed the Inspector in the Playground window using the following code. In such a case, the inspect message is not necessary (see Figure 13-2):
c := OrderedCollection new.
c add: 10.
c add: 15.
c add: 19.
c
Invoking the Cmd+G/Alt+G keystroke splits the Playground into two panes, with the Playground on the left and the Inspector on the right. The Inspector has three tabs—Items, Raw, and Meta. The first tab (Items) lists the items contained in the collection. The second tab (Raw) shows the internal values of the object representing the ordered collection. The third tab (Meta) shows the list of methods defined in the class of the object, OrderedCollection. The tabs that are offered by the Inspector depend on the object to be inspected. For example, inspecting a color object gives a different set of tabs.
In the following sections, you will see how to plug a Roassal visualization as a tab when inspecting an ordered collection. In particular, you will define new tabs to access visualizations.
Visualizing a Collection of Numbers
Open a system browser on the SequenceableCollection class, the superclass of OrderedCollection, and define the following method:
SequenceableCollection>>visualizeListOfNumbers
| c d |
c := RSChart new.
d := RSLinePlot new.
d y: self.
c addPlot: d.
c build.
^ c canvas
In the system browser, you should see Figure 13-3.
This visualization can be invoked in the Playground using Cmd+G/Alt+G (see Figure 13-4):
c := OrderedCollection new.
c add: 10.
c add: 15.
c add: 19.
c visualizeListOfNumbers
The Playground splits and the visualization appears on the right pane. This visualization can be improved by adding title ticks with the following method (see Figure 13-5):
SequenceableCollection>>visualizeListOfNumbers
| c d |
c := RSChart new.
d := RSLinePlot new.
d y: self.
c addPlot: d.
c title: 'Visualizing numbers'.
c addDecoration: RSVerticalTick new.
c addDecoration: RSHorizontalTick new.
c build.
^ c canvas
If you want to include the value 0, use the mustInclude0inY method, as in this new version (see Figure 13-6):
SequenceableCollection>>visualizeListOfNumbers
| c d |
(self allSatisfy: #isNumber) ifFalse: [
^ RSCanvas new add:
(RSLabel text: 'Need to contain numbers'); yourself ].
c := RSChart new.
d := RSLinePlot new.
d y: self.
c addPlot: d.
c title: 'Visualizing numbers'.
c addDecoration: RSVerticalTick new.
c addDecoration: RSHorizontalTick new.
c mustInclude0inY.
c build.
^ c canvas
This new version of visualizeListOfNumbers has a guard to prevent building a chart if the collection does not contain numbers. This small visualization easily scales up. Consider the following script (see Figure 13-7):
numberOfValues := 1000.
y := 0.
c := OrderedCollection new.
numberOfValues timesRepeat: [
c add: y.
y := y + ((-30 to: 30) atRandom) ].
c visualizeListOfNumbers
This example illustrates how a Roassal canvas can be rendered in the Pharo Inspector. It plots 1,000 values. Since the example does not use a seeded random generator, the graph you obtain may be slightly different. The visualizeListOfNumbers method is called by the script to produce the visualization. However, the integration of Roassal in the Inspector framework may produce the visualization by automatically invoking visualizeListOfNumbers. You can define the inspectorVisualization method to wrap a Roassal canvas into a SpRoassal3InspectorPresenter object:
The value 90 provided to the inspectorPresentationOrder: keyword indicates the priority of the tab in the Inspector. A low value indicates that the Visualization tab is located on the left. Since you do not need the evaluation pane, the method can be defined:
The inspectorVisualization and inspectorVisualizationContext: methods are semantically connected by having the first as the prefix of the second.
After defining inspectorVisualization and inspectorVisualizationContext:, evaluating the following script using Cmd+G/Alt+G embeds the visualization in the Inspector (see Figure 13-8):
numberOfValues := 1000.
y := 0.
c := OrderedCollection new.
numberOfValues timesRepeat: [
c add: y.
y := y + ((-30 to: 30) atRandom) ].
c
If you wanted to keep the chart without the 0 value in the two axes, you could define this method:
SequenceableCollection>>visualizeListOfNumbersNo0
| c d |
(self allSatisfy: #isNumber) ifFalse: [
^ RSCanvas new add:
(RSLabel text: 'Need to contain numbers'); yourself ].
c := RSChart new.
d := RSLinePlot new.
d y: self.
c addPlot: d.
c title: 'Visualizing numbers'.
c addDecoration: RSVerticalTick new.
c addDecoration: RSHorizontalTick new.
c build.
^ c canvas
The canvas returned by visualizeListOfNumbersNo0 has to be wrapped as follows:
Inspecting the following script highlights the differences between the two visualizations (see Figure 13-9):
c := OrderedCollection new.
-3.14 to: 3.14 by: 0.1 do: [ :x |
c add: x sin + 3 ].
c
Figure 13-9 shows that the two visualizations are accessible through a dedicated tab in the Inspector. The values kept in the c variable range from 2 to 4. In one visualization, the origin (0, 0) is part of the graph, in the other visualization, it is not. This contrived example illustrates the ability of the Pharo Inspector to render multiple visualizations.
Chaining Visualizations
A collection may contain other collections. In this section, you see how to define a visualization that enables you to navigate through nested collections. Consider this method:
SequenceableCollection>>visualizeCollections
| m |
(self allSatisfy: #isCollection) ifFalse: [
^ RSCanvas new add:
(RSLabel text: 'Need to contain collections'); yourself ].
The visualizeCollections method makes sense only if the collection contains other collections. If not, a gentle canvas indicates an error, as expressed in the first lines of the method. The Mondrian API is used to render each collection as a transparent circle. The size of a circle reflects the number of values contained in the represented collection. Circles of the same size are connected with a line.
The visualization is hooked into the Inspector using the following:
Figure 13-10 shows three panes. The middle pane is the collection that contains four other collections. Since these four collections are the same size, they are all connected to each other with a line. Clicking a node in the graph opens a new pane, which renders the visualizations you have previously seen.
In the same spirit, here is a more complex example (see Figure 13-11):
numberOfCollections := 100.
c := OrderedCollection new.
r := Random seed: 42.
numberOfCollections timesRepeat: [
t := OrderedCollection new.
y := 0.
(r nextInteger: 100) timesRepeat: [
t add: y.
y := y + ((-30 to: 30) atRandom) ].
c add: t
].
c
Figure 13-11 visualizes a larger collection, made of 100 nested collections. Clusters can be easily distinguished in the Collections visualization.
What Have You Learned in This Chapter?
Roassal greatly benefits from the programming environment offered by Pharo. The Inspector, easily accessible from the Playground, is a central tool to support incremental and live programming. The chapter explained the following:
How to add visualizations accessible from the Inspector.
How to remove the evaluation pane in the Inspector for a particular visualization.
Examples of the Chart and Mondrian Roassal components.
The chapter defined a few simple visualizations on the SequenceableCollection class; however, these very same techniques can be applied to any class from any particular domain.