The Navigation functionality (veneer.navigation
) lets you query and modify the current Source model using normal Python object notation. For example:
scenario.Network.Nodes[0].Name = 'Renamed node'
This notebook introduces the navigation functionality, including how it ties into the existing functionality in v.model
as well as current limitations.
In [4]:
import veneer
v = veneer.Veneer(19876)
In [2]:
v.status()
Out[2]:
In [5]:
from veneer.navigate import Queryable
In [6]:
scenario = Queryable(v)
In [7]:
scenario.Name
Out[7]:
In [11]:
scenario.Network.nodes.Count
Out[11]:
... However this won't work after indexing into a list or dictionary:
You can still access the properties of the list item, if you know what they're called:
In [12]:
scenario.Network.nodes[0].Name
Out[12]:
... But if you want tab completion, create a variable and run the cell that creates it. Then tab into the new variable:
In [20]:
node = scenario.Network.nodes[0]
# node.<tab> WON'T WORK YET. You need to run this cell first
In [21]:
# Now tab completion should work should work
node.Name
Out[21]:
The above examples start from the scenario - which works, but is tedious when you need a particular node or link (or all water users, etc).
Here, the existing functionality under v.model
is has been expanded to return Queryable objects that can be used for object navigation.
All of the relevant v.model
areas (link, node, catchment, etc) now have a nav_first
method, which accepts the same query parameters as the other operations. For example, v.model.node.nav_first
accepts the nodes
and node_types
query parameters, in the same way as v.model.node.get_param_values
.
As always, the query parameters are available in the help, one level up:
In [52]:
v.model.node?
... So we can get a particular node, for navigation as follows.
In [53]:
callide = v.model.node.nav_first(nodes='Callide Dam')
Note: The function is called nav_first
to emphasise that you will receive the first match for the query. So, if you query node_types='WaterUser'
, you'll get the first Water User matched.
It's likely that we'll add a more generic nav
method at some point that allows you to get a Queryable capable of bulk operations.
From the examples above, it looks like, you can work with the Queryable
object as a normal Python object. In some cases you can, but not always.
For changing values in the object (ie changing the relevant property in the Source model), you can indeed set the value directly:
In [23]:
callide.Name
Out[23]:
In [26]:
callide.fullSupplyLevel
Out[26]:
In [27]:
callide.fullSupplyVolume
Out[27]:
In [28]:
callide.fullSupplyVolume = 136300000
In [29]:
callide.fullSupplyVolume
Out[29]:
Note: Changing one thing may have a side effect, impacting another property:
In [31]:
callide.fullSupplyLevel
Out[31]:
If a property can't be set this way, it should tell you:
In [36]:
# CAUSES EXCEPTION
#callide.fullSupplyLevel = 216
In [38]:
# Would be nice, but doesn't work...
#callide.fullSupplyVolume = 1.1 * callide.fullSupplyVolume
The reason is, callide.fullSupplyVolume
is, itself, a Queryable
object:
In [39]:
callide.fullSupplyVolume.__class__
Out[39]:
So, although it prints out as a number, it is in fact a reference to the value within the model.
If you want to actually use the value in an expression (eg to set another property), you'll need to use the `
In [41]:
callide.fullSupplyVolume = 1.1 * callide.fullSupplyVolume._eval_()
In [42]:
callide.fullSupplyVolume
Out[42]:
In [43]:
callide.fullSupplyVolume = callide.fullSupplyVolume._eval_() / 1.1
In [44]:
callide.fullSupplyVolume
Out[44]:
It's not ideal to need to call ._eval_()
and we plan to improve this over time.
Also, the _eval_()
workaround only works for simple types - numbers, strings, booleans, etc. It doesn't work for complex objects, such as Nodes, Links and model instances.
For example you CANNOT do this at the moment:
storage = v.model.node.nav_first(nodes='my storage')
link = v.model.link.nav_first(links='some link')
# Try to set the outlet link for the storage...
storage.OutletPaths[0] = link # WILL NOT WORK!
When you use the model configuration functionality under v.model
every operation is a bulk operation by default - you use query parameters to limit the application:
For example, the following would retrieve Easting and Northing (really, just the node coordinates) for every node:
eastings = v.model.node.get_param_values('Node.location.E')
northings = v.model.node.get_param_values('Node.location.N')
while the following would do the same for only storages, by using query parameters:
eastings = v.model.node.get_param_values('Node.location.E',node_types='Storage')
northings = v.model.node.get_param_values('Node.location.N',node_types='Storage')
When using Queryable
, everything is, currently, an operation on a single object (eg a single node):
In [50]:
callide.Node.location.E
Out[50]:
However... one of the big benefits of the navigable functionality is the ability to discover the parameter name (often nested) that you need to use in a bulk operation.
When stuck for a parameter name, use a Queryable to discover it, through tab-completion and then plug the resulting path back into the v.model.X.get_param_values()
call
The Queryable approach is new and will expand.
Things on the list are:
Other related functionality that would be nice:
node.Inflow = 0
, see the data source that is connected.