Perspectives

A perspective is a saved view of a file: which items to list, what to show about each of them, and what is nested under what. Arspec comes with a few, and you can make your own in the app without writing anything by hand.

What a perspective decides

Most tools decide in advance how an ontology looks. In Arspec that decision is yours, and it is saved as a small document that can be changed on the spot, kept with the file, and handed to someone else. A perspective decides:

How the result is laid out and drawn is a separate matter, handled by styles. The built-in styles give every perspective a sensible look, so most people never need to touch them.

How you work with what is shown is a third matter, and it is the app’s: what a right-click or a long press offers, how a value is edited, where the actions are offered, how a long list is paged, how a record opens. It is the same in every perspective. A perspective chooses among what the app offers — whether a list takes new rows, whether its rows can be deleted, what a click on a part does — and neither it nor a style invents behaviour of its own. That is what lets you use a view you have never seen before.

The built-in perspectives

Attributes lists each subject with its properties beneath it, and when you open a subject it offers other angles on the same item beside them, what points at it for one. Plain lists every statement flat. Prefixes shows and edits the file's namespaces, and Styles shows the styles a file carries. Getting started has the details. Some are off by default; the perspectives screen, behind the gear at the end of the tab strip, has a switch for each.

The perspectives screen: views from this file, from this topic, and the built-in ones, each with a tick box.
The perspectives screen, behind the gear at the end of the tab strip.

Making your own

On the perspectives screen, press Create one…, or, with an existing tab open, press Configure — the sliders at the top right — to open its editor and see how it is built. The editor is a form, and the view updates as you change it. Turn on the help hints (the question mark beside Save) and every part of the form explains itself in place.

The perspective editor open on a view called People: When reads subject has type Person, Display ticks which parts of a statement are shown, and a nested list called props stands under Subordinates.
The editor on a view that lists every person. The view itself is drawn under the form and follows each change.

A perspective is built from lists. There is one top-level list, whose rows are the records you see on screen. Under it you can nest more lists, and each nested list runs once for every row of the list above it, so its rows appear inside that row. That is how the People view on the front page is made: a top list of people, and one nested list under it that finds every statement about the person above.

Each list in the editor has four parts:

PartWhat it decides
WhenWhich statements the list takes. Each condition compares one part of a statement, its subject, relation or value, with a fixed term or with a part of the row above. Conditions can be combined with all and any, and negated with not. A list with no conditions takes every statement.
DisplayWhich parts of each statement are shown, and whether each one is read-only, editable on request, or always open for editing. Behind each part's gear: what a click on it does once its row is selected (Enter does the same for the row’s first part), how the part reads — as the term itself, or as its rdfs:label or ars:label where the file or anything it imports states one — which terms its editor offers, as a query (Choices: the members of a class, the constants of a vocabulary, the things of whatever the row is about), and whether it takes anything else — and, for the value, what kind of thing it holds. Under the parts, Expand record when selected ties a record's expansion to its selection, two things otherwise done independently: the record is expanded as the cursor lands on it, on the first click or by the keys, and collapsed as the cursor leaves it. Unticked, a record is expanded from its menu, on Enter, or by a click on a part whose click action expands, and stays as it was put.
ActionsWhat may be done to the list’s rows. Add / Insert, Copy & Paste and Delete, and in a list sorted in numeric order Move up / down, are each a card: whether the action is offered at all, whether it stands in the action bar or waits on the menu, its place among the others, and the face it wears. Add / Insert also says what a new row starts as and what else one press makes; Delete how far a deletion reaches. Add action, at the foot, makes an action of your own, built from steps. What each action does, on a record and on a list, and how actions of your own are put together is on the Actions page.
ConfigurationSettings you set once: the list's ID, which files it reads (this one, the ones it imports, the app's own definitions, your profile), the fewest and most rows it may have, sorting, and Distinct by, which shows one row per subject when the file has many statements about it. Enable if is the list's second condition: When picks its rows, and this says whether the list is there at all under a given row. It reads the row above as ↑subj, ↑pred and ↑obj, and a condition that names subj, pred or obj looks for a statement, the way an Order query does: “subj is ↑obj” keeps the list to rows whose object has something said about it. Where the condition fails the list leaves nothing behind, not even a heading. On the top-level list it speaks for the whole perspective: where it fails, the perspective's tab is not offered, in an opened record or among the file's tabs. A view of what points at a term can repeat its own When there, and then has a tab only where something does. Sorting by numeric order opens an Order query: a condition that says which statement holds each row's number, “subject is ↑subj and predicate is av:order” for instance. Rows sorted that way can be moved: Move up / down joins the list's actions, on the menu and in the bar, and adding on a row inserts above it. Extra types is a hook for styles; Form is the one that comes built in.
SubordinatesThe lists nested under this one. Invoke perspective nests a whole other perspective instead, run about the current row: this is how a view can show, under each item, whatever another view says about it. Its Enable if says under which rows it runs at all, in the same words as When, reading the row above it as ↑subj, ↑pred and ↑obj; where the condition fails, nothing of it stands under that row. A perspective it runs may carry an Enable if of its own, on its top-level list, and then answers for its own tab.

In the editor, the top list is always open. A nested list that has lists of its own starts open too, so the shape of the tree is visible at once, and so does every Invoke perspective. A nested list with nothing under it starts folded to its title; the arrow beside the title opens it.

Above the lists, Offered says where the perspective is offered: as a tab above the file, in the lens list of an opened record, and on every term's Open term with…. Any mix, and none: a perspective offered nowhere still runs wherever another view invokes it.

A nested list usually refers to the row above

A nested list nearly always has one condition tying it to its parent row, such as subject equals the subject above. Without it, the nested list would repeat the same rows under every parent. In the condition editor, the parts of the row above are offered as ↑subj, ↑pred and ↑obj.

What an added row starts as

Adding a row — Add to list on a list’s menu, Insert on a row’s, or the action bar’s Add — creates a row the list's own conditions accept. Inserted at a row of a list that keeps an order of its own, it goes above that row; in a list the file orders, it joins the list. A condition that pins a part, such as relation is rdfs:label or subject is the subject above, decides that part of the new row. A part the conditions leave open takes the default set on the Add / Insert card under Actions, or — left on auto — the app's own: a fresh name in the file's namespace for a subject, rdf:type for a relation, and an empty value of the kind the field holds. A row is seldom one statement, so the block opens into a tree: Add triple under it adds a triple the same press makes, and under any of those another, each made after the one it hangs off — so ↑subj and kin in one of them read that triple, an n-th ancestor counts up the tree and on into the rows above, and auto starts at the node the triple above just made: its blank node, or the thing it spoke of. The card's After insert then says whether the nested lists' rows are made along with it, as many as each one's Min asks for, or the row is left bare.

Lenses: a view about one item

A lens is a perspective that is run about a single item rather than over the whole file. Where a view invokes another view under its items, as Attributes does under every subject, expanding an item shows its lenses as tabs inside the record, each showing what the file says about that item from a different angle: in Attributes, the subject's own properties on one tab and everything that points at it on another.

The record for ada expanded under the Attributes view, showing a lens tab called Attributes+ and a gear beside it.
An expanded record under Attributes. Attributes+ is a lens: a view run about this one item.

Any perspective can be a lens. The only difference is that its top-level list is given the item to start from, the same way a nested list is given the row above it. Which tabs an opened record shows is the invoking view's to say: Invoke perspective takes a list of perspectives, in the order their tabs stand, and opens on the first that has something to show unless told to open on the first regardless. The gear beside the tabs lists every perspective offered in the lens list, to tick for that one record.

In the editor, pressing an invocation's Perspectives field opens a picker: every perspective offered as a lens, with a box to tick each, in sections by where they come from, and a search box to shorten the list. The view's own family comes first, its service perspectives among them whether or not they are offered anywhere else. A service perspective is listed with its owner's name before its own, Styles - Selector Attributes say. Tick what the record's tabs should be; the ticked ones are listed above the search box in tab order, and the handle beside each drags it to another place. Press OK, and the tags stand in that order; dragging one tag onto another reorders them too.

Opening a term

Right-click any term (long-press on a phone or tablet) and Open term with… lists the perspectives that say they open terms. Pick one and it opens on a page of its own about that term, given the term as the subject to start from and nothing else, so it fits a perspective whose top-level list refers to the row above. Subject's Attributes, Attributes+ and References to the Subject come built in; a view of your own joins the list by ticking to open a term with under Offered.

Service perspectives: the lenses a view brings along

A lens that only makes sense inside one particular view has no place on the perspectives screen, where it would sit beside the views of the file with nothing to say about the file. So a perspective can own service perspectives: views that exist to be run inside it, under Invoke perspective or as the tabs of an opened record, and nowhere else. They are not listed for switching on and off, and other views do not offer them.

The built-in Attributes is made this way. Its own list is only the subjects of the file; under each one it invokes two service perspectives, which are the two tabs of an opened subject: Attributes+, finding every statement about that subject and, under any value that is an anonymous node, that node's own statements, as far down as the anonymous nodes go; and References to the Subject, finding what points at it. The second says in its Enable if what its When says, so its tab appears only on a subject something points at. Two more wait in the lens list for whoever wants them: Subject's Attributes, the same statements one level deep, and Object's Attributes, the statements about what a row points at.

Service perspectives are edited through the view that owns them. Open that view's editor and its heading reads Main Perspective Configuration, with a button beside it counting the services, +2 say. Press it to switch the editor to one of them, or to start another with New service perspective. A service is saved wherever its owner is saved, and deleting one takes it out of its owner.

Where views are kept

A new perspective starts as an unsaved preview. Its first Save asks where to keep it:

Kept inWho sees it
The ontology file itselfAnyone who opens the file. The view ships with the data.
The topic's .arspec fileAnyone you hand the topic to. The ontology files stay untouched.
Your profileYou, in every file, on every machine your profile follows you to. Managed from Preferences → Profile → Your perspectives and styles.

A perspective is a small text document, so sharing one means copying a file. A view written for one ontology works on any other that uses the same terms, which is what makes a view worth sharing with everyone who works with the same vocabulary.

How a perspective is stored

This section is for the curious and for those who want to write views by hand or have an AI draft them. You can skip it.

A perspective is written in RDF, in the same language as the data, using the ars: vocabulary. Here is the “People” view from the front page as the app saves it: a top list of every subject of type :Person, once each, and one nested list showing the relation and value of every statement about that person.

@prefix ars: <https://arspec.org/ars/spec/1/schema#> .
@prefix p:   <http://ex/team/perspec/people#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

p:perspec a ars:Perspective ;
    ars:title "People" ;
    ars:rootDataSource p:people .

p:people a ars:DataSource ;
    ars:subjectVisible true ;
    ars:distinctBy rdf:subject ;
    ars:adding [ a ars:RowAction ; ars:inActionBar false ] ;
    ars:filter [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
        ars:op ars:typeIs ;
        ars:value [ a ars:IriValue ;
            ars:nsUri "http://ex/team#" ; ars:localName "Person" ] ] ;
    ars:child p:props .

p:props a ars:DataSource ;
    ars:label "Attributes" ;
    ars:order 0 ;
    ars:predicateVisible true ;
    ars:objectVisible true ;
    ars:deletion [ a ars:RowAction ; ars:order 0 ] ;
    ars:filter [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
        ars:op ars:eq ;
        ars:value [ a ars:TermValue ;
            ars:role rdf:subject ; ars:bindingDistance 1 ] ] .

A few things to know when reading or writing one:

The full vocabulary ships inside the app; Preferences → Profile → Your perspectives and styles can open it. The AI assistant can read the vocabulary too, which is how it drafts a view that loads.

See one being edited: open the demo, pick a tab, press Configure, and turn on the help hints.