-
Notifications
You must be signed in to change notification settings - Fork 7
Semantic Filtering API
The semantic filtering API allows for the definition of diagram specific tags and filtering rules that can be used for later filtering and identifying graph elements based on their semantic characteristics. This allows the creation of richer interaction techniques on the client-side rather than relying on purely structural attributes of the different graph elements. Example use cases are filtering of proxy nodes and providing semantic context for structural diagram editing.
SemanticFilterTag
s can be added to a graph element with the property de.cau.cs.kieler.klighd.semanticFilter.tags
. They contain a string that serves to convey semantic information. A tag also acts as an atomic SemanticFilterRule
that evaluates to true for an element if that element contains a tag with the same string.
A graph element can contain a list of SemanticFilterRule
s. Depending on the intended use case it may make sense to attach different rules to different graph elements, but in the use cases we consider here, rules would apply to the entire graph. Therefore, rules are only attached to the root node. It is up to the client feature (e.g. proxy-view) to look for and apply rules on a graph.
A SemanticFilterTag
, TrueConnective
and FalseConnective
are atomic rules. Rules can be constructed using connectives and other rules. The following logical connectives are defined:
- IdentityConnective
- NegationConnective
- AndConnective
- OrConnective
- IfThenConnective
- IfThenElseConnective
A SemanticFilterTag
can also have a number in addition to a string and there are special numerical connectives that take a SemanticFilterTag
as an operand and evaluate to true or false according to the number saved in that tag. The following numeric connectives are defined:
- NumericEqualConnective
- NumericNotEqualConnective
- GreaterThanConnective
- GreaterEqualsConnective
- LessThanConnective
- LessEqualsConnective
The following rules take numeric inputs and output a numeric value themselves. They can be used to construct more complex expressions such as "states" where the sum of "declarations" and "childCount" is larger than some value.
- NumericPlusConnective
- NumericMinusConnective
- NumericTimesConnective
- NumericDividesConnective
In the following we declare some simple tags and a numeric tag.
/** Tag giving semantic meaning that the element is a state. */
public static final SemanticFilterTag STATE = new SemanticFilterTag("state");
/** Tag giving semantic meaning that the element is final. */
public static final SemanticFilterTag FINAL = new SemanticFilterTag("final");
/** Returns a tag giving semantic meaning how many declarations an element has. */
public static SemanticFilterTag DECLARATIONS(Double num) {
return new SemanticFilterTag("numDeclarations", num);
}
/** Returns a tag giving semantic meaning how many declarations an element has without a value.
* Used for constructing rules involving the tag.
* /
public static SemanticFilterTag DECLARATIONS = new SemanticFilterTag("numDeclarations);
We can then assign these tags during the synthesis.
node.getProperty(KlighdProperties.SEMANTIC_FILTER_TAGS).add(SCChartsSemanticFilterTags.STATE)
...
node.getProperty(KlighdProperties.SEMANTIC_FILTER_TAGS).add(SCChartsSemanticFilterTags.DECLARATIONS(filteredDeclarations.size as double))
Next, we need some rules that we can use to filter elements on the client.in
/** Rule to exclude elements that are states. */
public static final SemanticFilterRule NO_STATES = new NegationConnective(SCChartsSemanticFilterTags.STATE, "Filter States");
/** Rule to only include elements that have at least 3 declarations. */
public static final SemanticFilterRule ONLY_AT_LEAST_3_DECLARATIONS = new OrConnective(
new LessEqualsConnective(new NumericConstantConnective(3.0), SCChartsSemanticFilterTags.DECLARATIONS
"Filter Elements With Less Than 3 Declarations");
Finally we can add the rules to the graph (here we add them to the root node) [xtend].
rootNode.setProperty(KlighdProperties.SEMANTIC_FILTER_RULES, #[NO_STATES, ONLY_AT_LEAST_3_DECLARATIONS])
In addition to the programmatic method of defining rules an expression language may be used. SemanticFilterRuleParserUtil.parse(<ExpressionString>)
may be used to parse these expressions and obtain the corresponding SemanticFilterRule
.
Expressions are built up analogously to the programmatic construction. Each expression is evaluated either to a boolean or numeric value. An atomic expression is either a constant (true
, false
or a string that can be parsed as Java double) or a tag variable. A tag variable consists of a string identifier (without whitespaces) and is preceded by #
to denote a boolean value i.e. the tag is present or not or by a $
to denote a numeric value. Whitespaces are used as separators between operators and expressions. The table below gives an overview over the available operators. Brackets ((
,)
) may additionally be used to override precedence.
Operator | Syntax | Input | Output | Precedence |
---|---|---|---|---|
And | <expr> && <expr> | boolean | boolean | 4 |
Or | <expr> || <expr> | boolean | boolean | 3 |
Not | ! <expr> | boolean | boolean | 6 |
Addition | <expr> + <expr> | numeric | numeric | 9 |
Subtraction | <expr> - <expr> | numeric | numeric | 9 |
Multiplication | <expr> * <expr> | numeric | numeric | 10 |
Division | <expr> / <expr> | numeric | numeric | 10 |
GreaterEquals | <expr> >= <expr> | numeric | boolean | 8 |
GreaterThan | <expr> > <expr> | numeric | boolean | 8 |
LessEquals | <expr> <= <expr> | numeric | boolean | 8 |
LessThan | <expr> < <expr> | numeric | boolean | 8 |
Equals | <expr> = <expr> | numeric/boolean | boolean | 7 |
NotEqual | <expr> != <expr> | numeric/boolean | boolean | 7 |
-
#initial || $regions >= 3
- keeps all elements that have the taginitial
or have the tagregions
with a value of 3 or higher. -
$children + $importance > $weight
- keeps all elements where the sum of thechildren
andimportance
tags is higher than the value of theweight
tag
How exactly a feature on the client uses these tags and rules is flexible. In general the rules should be retrieved from the graph and some decision must be made on how to choose a rule based on its name. Then rules can be applied on graph elements, which allows filtering of elements.
Getting filters from the root
import { Filter, getFilters } from "../../filtering/semantic-filtering-util";
...
filters: Filter[] = getFilters(rootNode)
Filter interface
export interface Filter {
name?: string
defaultValue?: boolean
filterFun(el: SKGraphElement): boolean
}
Now using a list of graph elements we can use the filter
function to apply this Filter
to all graph elements and get a filtered list of graph elements.
KIELER is an open source software project by the RTSYS Group at Kiel University, licensed under the Eclipse Public License or Eclipse Public License 2.0 | KIELER Mailing List