Molding CSV data — actions, queries and visualizations
This is Part 4 of Tutorial: molding CSV data into an explainable system. This part shows that, in addition to contextual views, there are also contextual actions and queries that can also be implemented easily as tiny tools. We also see that simple visualizations can easily be created to provide richer views of our domain.
If you are jumping into the tutorial at this point, and have some previously saved work not already in this image, you should file it in now. Otherwise, you can file in a sample snapshot reflecting the work completed at the end of the previous part:
VRTutorialExamples new fileIn10MoldingAuthors
We can easily navigate from the dataset to individual papers or authors, but how can we navigate back? We can evaluate self dataset in an inspector playground, but is there an easier way?
Instead of introducing another contextual view, what we need here is a Contextual Action, a button that performs a useful task, possibly updating a view, spawning a new view, or launching an external tool.
⇒
Evaluate self dataset in an Inspector playground of paper 128. Extract an
action
to navigate to the dataset.
Hint:
Right-click in the playground as you would to extract a method or a view, but this time select Create <gtAction> for dataset. Before accepting the generated method, change the icon from empty to up, and change the tooltip text to Spawn dataset.
⇒
Refresh the view to see the new action associated with an “up” button.
Hint:
You can refresh the Inspector views by clicking the ▾ menu icon at the top right, and selecting “↻ Update pane tool.”
VRDatasetExamples new paper128
Take a closer look at the newly defined action. It looks like this:
It's quite similar to a view method, except that its argument is anAction instead of aView, and the pragma is <gtAction> instead of <gtView>.
This action is currently defined only for papers. Let's make it work for authors as well.
⇒
Push the gtDatasetFor: method up to its superclass, VRDomainEntity.
Now the action is also available for authors!
It would be nice to access the actual papers referred to in the dataset. We don't have the URLs or DOIs of these publications, but we can ask Google Scholar to find them for us, like this:
paper := VRDatasetExamples new paper128. query := paper title copyReplaceAll: String space with: '+'. gsUrl := 'https://scholar.google.com/scholar?hl=en&q=' , query. WebBrowser openOn: gsUrl
⇒
Create an action for papers that will open a web browser on the Google Scholar query for that paper.
Hint:
You can use the BrGlamorousVectorIcons>>#web
icon for the button.
Here are the changes:
"protocol: #actions" VRDomainEntity >> gtDatasetFor: anAction <gtAction> ^ anAction button icon: BrGlamorousVectorIcons up; tooltip: 'Spawn dataset'; action: [ :button | button phlow spawnObject: self dataset ] "protocol: #views" VRPaper >> gtGoogleScholarFor: anAction <gtAction> ^ anAction button icon: BrGlamorousVectorIcons web; priority: 10; tooltip: 'Look up in Google Scholar'; action: [ :button | WebBrowser openOn: 'https://scholar.google.com/scholar?hl=en&q=' , (self title copyReplaceAll: String space with: '+') ]
To sync to this point in the tutorial (throwing away any other changes) evaluate:
VRTutorialExamples new fileIn11Actions
To find papers related to a particular topic, we need a way to query the list of papers of a dataset. A contextual view cannot do this on its own, nor can an action. We need a Contextual Search. Like views and actions, they are defined as methods of the objects to search, with a dedicated pragma, namely <gtSearch>.
Have a look at the following
search
method for datasets. It searches through the list of papers of the dataset, using the filterBySubstring criterion. We search papers by
title
(itemName: #title), and the result (sendCategory:) is a new paper group built from the query result (aCategory items contents):
⇒
Add this method to the VRDataset class. You should now see a 🔍 search icon at the top right.
⇒
Which papers have “Mondrian” in the title?
⇒
Add further searches by paper type and author name. Set the priorities so that paper titles are searched before paper types, and then author names.
VRDatasetExamples new vrDataset
As usual, here are the changes:
"protocol: #search" VRDataset >> gtSpotterForPaperTitles: aSearch <gtSearch> ^ aSearch list title: 'Paper titles'; priority: 10; items: [ self allPapers ]; itemsLimit: Float infinity; itemName: #title; sendCategory: [ :aCategory :aStep :thisSearch | VRPaperGroup withAll: aCategory items contents ]; filterBySubstring "protocol: #search" VRDataset >> gtSpotterForPaperTypes: aSearch <gtSearch> ^ aSearch list title: 'Paper titles'; priority: 20; items: [ self allPapers ]; itemsLimit: Float infinity; itemName: #type; sendCategory: [ :aCategory :aStep :thisSearch | VRPaperGroup withAll: aCategory items contents ]; filterBySubstring "protocol: #search" VRDataset >> gtSpotterForAuthorNames: aSearch <gtSearch> ^ aSearch list title: 'Author name'; priority: 30; items: [ self authors ]; itemsLimit: Float infinity; itemName: #name; sendCategory: [ :aCategory :aStep :thisSearch | VRAuthorGroup withAll: aCategory items contents ]; filterBySubstring
To sync to this point in the tutorial (throwing away any other changes) evaluate:
VRTutorialExamples new fileIn12Searches
Here is an example of a somewhat more complex analysis. We would like to understand whether coauthors independently submit papers or not. Here we display a graph starting from a given author, and linking to that authors papers, the other co-authors, and their further publications, if any:
aMondrian := GtMondrian new.
anAuthor := VRDatasetExamples new authorLanza.
theAuthors := {anAuthor} asOrderedCollection , anAuthor coauthors.
thePapers := (theAuthors flatCollect: #papers) copyWithoutDuplicates.
nodes := theAuthors , thePapers.
aMondrian nodes
shape: [ :node | node mondrianNodeElementHighlighting: self ];
with: nodes.
aMondrian edges connectToAll: #mondrianChildren.
aMondrian layout
custom: (GtGraphForceBasedLayout new
charge: -2000;
length: 200).
aMondrian
We have to implement a few helper methods first, such as mondrianChildren and so on.
⇒
Accept the following changes to enable the mondrian graph.
"protocol: #mondrian" VRPaper >> mondrianNodeElementHighlighting: aNode ^ BlElement new size: 10 @ 10; border: (self mondrianBorderHighlighting:aNode); background: self mondrianNodeColor; aptitude: (BrGlamorousWithExplicitTooltipAptitude text: self printString) "protocol: #mondrian" VRAuthor >> mondrianNodeElementHighlighting: aNode ^ BlTextElement new text: self initials asRopedText; padding: (BlInsets all: 12); border: (self mondrianBorderHighlighting:aNode); background: self mondrianNodeColor; aptitude: (BrGlamorousWithExplicitTooltipAptitude text: self name); geometry: BlCircleGeometry new; yourself "protocol: #mondrian" VRDomainEntity >> mondrianNodeElementHighlighting: aNode self subclassResponsibility "protocol: #mondrian" VRAuthor >> mondrianNodeColor ^ Color paleRed "protocol: #mondrian" VRPaper >> mondrianNodeColor ^ Color paleBlue "protocol: #mondrian" VRDomainEntity >> mondrianNodeColor self subclassResponsibility "protocol: #mondrian" VRDomainEntity >> mondrianChildren self subclassResponsibility "protocol: #mondrian" VRPaper >> mondrianChildren ^ self authors "protocol: #mondrian" VRAuthor >> mondrianChildren ^ self papers "protocol: #mondrian" VRDomainEntity >> mondrianBorderHighlighting: aNode ^ BlBorder paint: Color black width: 1 "protocol: #mondrian" VRAuthor >> initials ^ '' join: (self name substrings collect: #first)
Here we can see clearly which co-authors are also active in other papers, and which are not. The diagram is also clickable, so we can dive into specific authors and papers.
Now we would like to turn this into a dedicated view for authors.
⇒
Extract a method coauthorMondrian: from this snippet, parameterized by the mondrian instance.
Hint:
copy this code to an inspector playground of an author, replacing anAuthor by self.
⇒
Introduce a mondrian view that uses this helper method.
Hint:
To do this, you need to send the mondrian factory message to the view, like this:
VRDatasetExamples new authorLanza
Note how you can now navigate between Co-author graph views by clicking on authors in the graph.
Here are the remaining changes:
"protocol: #views"
VRAuthor >> gtCoauthorGraphFor: aView
<gtView>
^ aView mondrian
title: 'Co-author graph';
priority: 40;
painting: [ :aMondrian | self coauthorMondrian: aMondrian ];
actionUpdateButton
"protocol: #mondrian"
VRAuthor >> coauthorMondrian: aMondrian
| thePapers nodes theAuthors |
theAuthors := {self} asOrderedCollection , self coauthors.
thePapers := (theAuthors flatCollect: #papers) copyWithoutDuplicates.
nodes := theAuthors , thePapers.
aMondrian nodes
shape: [ :node | node mondrianNodeElementHighlighting: self ];
with: nodes.
aMondrian edges connectToAll: #mondrianChildren.
aMondrian layout
custom: (GtGraphForceBasedLayout new
charge: -2000;
length: 200).
^ aMondrian
To sync to this point in the tutorial (throwing away any other changes) evaluate:
VRTutorialExamples new fileIn13Mondrian
NB: This page links to Pages containing missing references - allowed failures to allow references to missing classes and methods in this page. Next: Part 5. Molding CSV data — continuing the exploration