Axon Usage

Str ExamplesDate/Time ExamplesDate SpansUri ExamplesList ExamplesDict ExamplesGrid ExamplesRegex ExamplesRead ExamplesHis ExamplesDef ExamplesPivot ExamplesEnergy Examples

Str Examples

Common functions for working with strings: capitalize(), contains(), decapitalize(), endsWith(), get(), index(), indexr(), isEmpty(), isTagName(), lower(), replace(), size(), startsWith(), toTagName(), trim(), trimStart(), trimEnd(), upper().

123.toStr                      >>  "123"    // convert any object to string
"num=" + 3                     >>  "num=3"  // use '+' for concat
"hi world".isEmpty             >>  false
"hi world".size                >>  8
"hi world"[5]                  >>  114      // unicode char for 'w'
"hi world"[3..-2]              >>  "worl"   // get with range is slice
"root toot".index("oo")        >>  1
"root toot".indexr("oo")       >>  6
"hi world".contains("hi")      >>  true
"Abc".upper                    >>  "ABC"
"Abc".lower                    >>  "abc"
"a,b,c".split(",")             >>  ["a", "b", "c"]
"fooBar".capitalize            >>  "FooBar"
"FooBar".decapitalize          >>  "fooBar"
" xyz ".trim                   >>  "xyz"
"abcd".startsWith("ab")        >>  true
"abcd".endsWith("cd")          >>  true
"foo bar".isTagName            >>  false
"foo bar".toTagName            >>  "fooBar"
"root toot".replace("oo", "a") >> "rat tat"

Date/Time Examples

Common functions for working with Dates, Times, and DateTimes: date(), dateTime(), day(), dayOfYear(), dst(), firstOfMonth(), fromJavaMillis(), hour(), isLeapYear(), isWeekday(), isWeekend(), lastOfMonth(), minute(), month(), now(), nowTicks(), numDaysInMonth(), second(), startOfWeek(), time(), toJavaMillis(), toTimeZone(), today(), tz(), weekOfYear(), weekday(), year(), yesterday().

now()                                   >>  current DateTime in local timezone
today()                                 >>  today's Date in local timezone
yesterday()                             >>  yesterday's Date in local timezone
today() + 1day                          >>  tomorrow
today() + 7day                          >>  next week
now() + 1hr                             >>  one hour from now
dateTime(2023-03-14, 0:00, "New_York")  >>  create DateTime from Date, Time, and timezone
now().date                              >>  Date portion of DateTime
now().time                              >>  Time portion of DateTime
now().tz                                >>  timezone string name of DateTime
today().year                            >>  four digit year
today().month                           >>  month as number between 1 and 12
today().day                             >>  day of month as number between 1 and 31
now().hour                              >>  hour as number between 0 and 23
now().minute                            >>  minutes as number between 0 and 59
now().second                            >>  seconds as number between 0 and 59
today().weekday                         >>  day of week as number between 0 and 6
today().isWeekend                       >>  true if Sunday/Saturday
today().isWeekday                       >>  true if Monday - Friday
today().firstOfMonth                    >>  first Date of the month
today().lastOfMonth                     >>  last Date of the month
now().toTimeZone("UTC")                 >>  convert DateTime to different timezone
today().numDaysInMonth                  >>  number of days in Date's month
isLeapYear(2024)                        >>  is a leap year
now().dst                               >>  is DateTime in daylight saving time
today().dayOfYear                       >>  number 1 to 366
today().weekOfYear                      >>  number 1 to 53
startOfWeek()                           >>  0 for Sun or 1 for Mon based on locale
now().toJavaMillis                      >>  milliseconds since Unix epoch of 1970
now().toJavaMillis.fromJavaMillis       >>  convert back to DateTime

Date Spans

Common functions for working with Spans and DateSpans: eachDay(), eachMonth(), end(), lastMonth(), lastQuarter(), lastWeek(), lastYear(), numDays(), pastMonth(), pastWeek(), pastYear(), start(), thisMonth(), thisQuarter(), thisWeek(), thisYear(), toDateSpan(), toSpan(), today(), yesterday().

today()                             >>  any Date value may be used span
thisWeek()                          >>  DateSpan for current week (locale based start of week)
thisMonth()                         >>  DateSpan for current month
thisQuarter()                       >>  DateSpan for current quarter
thisYear()                          >>  DateSpan for current year
pastWeek()                          >>  DateSpan for previous 7 days
pastMonth()                         >>  DateSpan for previous 30 days
pastYear()                          >>  DateSpan for previous 365 days
lastWeek()                          >>  DateSpan for last week (locale based start of week)
lastMonth()                         >>  DateSpan for last month
lastQuarter()                       >>  DateSpan for last quarter
lastYear()                          >>  DateSpan for last year
toDateSpan(2023-01-01..2023-02-28)  >>  DateSpan with two explicit dates
toDateSpan(2023-02-14)              >>  DateSpan for a day
toDateSpan(2023-02)                 >>  DateSpan for a month
toDateSpan(2023)                    >>  DateSpan for a year
toDateSpan(2023-02).toSpan          >>  Convert DateSpan to Span
toDateSpan(2024-02).start           >>  First day of DateSpan
toDateSpan(2024-02).end             >>  Last day of DateSpan
toDateSpan(2024-02).numDays         >>  Number of days in DateSpan
eachDay(2024-02) (d) => echo(d)     >>  Iterate the Dates in a DateSpans
eachMonth(2024) (d) => echo(d)      >>  Iterate the months in a DateSpan

Uri Examples

Common functions for working with URIs: uriBasename(), uriDecode(), uriEncode(), uriExt(), uriHost(), uriIsDir(), uriName(), uriPath(), uriPathStr(), uriPort(), uriScheme()

`/a/b/file.txt`.uriName                   >>  "file.txt"
`/a/b/file.txt`.uriBasename               >>  "file"
`/a/b/file.txt`.uriExt                    >>  "txt"
`http://host:81/a/b/file.txt`.uriScheme   >>  "http"
`http://host:81/a/b/file.txt`.uriHost     >>  "host"
`http://host:81/a/b/file.txt`.uriPort     >>  81
`http://host:81/a/b/file.txt`.uriPathStr  >>  "/a/b/file.txt"
`http://host:81/a/b/file.txt`.uriPath     >>  ["a", "b", "file.txt"]
`/a/b`.uriIsDir                           >>  false
`/a/b/`.uriIsDir                          >>  true
`file name.html`.uriEncode                >>  "file%20name.html"
"file%20name.html".uriDecode              >>  `file name.html`

List Examples

Common functions for working with lists: add(), addAll(), all(), any(), concat(), contains(), get(), each(), find(), findAll(), first(), flatMap(), fold(), index(), indexr(), insert(), insertAll(), isEmpty(), last(), map(), moveTo(), remove(), set(), size(), sort(), sortr(), unique().

x: [10, 20, 30]
y: ["chat", "apple", "bee"]
x.isEmpty          >>  false
x.size             >>  3
x[2]               >>  30
x[1..-1]           >>  [20, 30]  // get with range is slice
x.first            >>  10
x.index(30)        >>  2
x.index(40)        >>  null
x.contains(20)     >>  true
x.fold(sum)        >>  60
x.any v => v < 20  >>  true
x.all v => v < 20  >>  false
x.concat(";")      >>  "10;20;30"

Functions which modify a list always return a new list (the original is immutable):

x.add(40)                      >>  [10, 20, 30, 40]
x.addAll([40, 50])             >>  [10, 20, 30, 40, 50]
x.set(2, 99)                   >>  [10, 20, 99]
x.insert(0, 99)                >>  [99, 10, 20, 30]
x.insertAll(0, [88,99])        >>  [88, 99, 10, 20, 30]
x.remove(1)                    >>  [10, 30]
y.sort                         >>  ["apple", "bee", "chart"]
y.sortr                        >>  ["chart", "bee", "apple"]
y.sort((a,b)=>a.size<=>b.size) >>  ["bee", "chat", "apple"]
y.each s => echo(s)            >>  iterator s => s.size              >>  [4, 5, 3]
y.flatMap s => [s, s.size]     >>  ["chat", 4, "apple", 5, "bee", 3]
y.find s => s.size == 3        >>  "bee"
y.findAll s => s.size <= 4     >>  ["chat", "bee"]
y.moveTo("chat", -1)           >>  ["apple", "bee", "chat"]
[1,1,1,2].unique               >>  [1,2]

Dict Examples

Common functions for working with dicts: all(), any(), get(), each(), find(), findAll(), has(), isEmpty(), map(), missing(), names(), remove(), set(), dis(), trap(), vals().

d: {dis:"Bob", bday:1980-06-01}
d.isEmpty            >>  false
d["bday"]            >>  1980-06-01
d["foo"]             >>  null
d->dis               >>  "Bob"
d->foo               >>  UnknownNameErr exception
d.has("bday")        >>  true
d.missing("bday")    >>  false
d.names              >>  ["dis", "bday"]
d.vals               >>  ["Bob", 1980-06-01]
d.dis                >>  "Bob"
d.dis("bday")        >>  "1-Jun-1980"
d.any v => v.isDate  >>  true
d.all(isDate)        >>  false

// iterate keys, vals
d.each((v, k) => echo(k + ": " + v))

For a detailed discussion on using [] versus -> see Axon Language.

Functions which modify a dict always return a new dict (the original is immutable):

d.set("person", marker())  >>  {dis:"Bob", bday:1980-06-01, person}
d.remove("bday")           >>  {dis:"Bob"} v => v + "!"         >>  {dis:"Bob!", bday:"1980-06-01!"}
d.find v => v.isDate       >>  1980-06-01
d.findAll v => v.isDate    >>  {bday:1980-06-01}

Grid Examples

Common functions for working with grids: addCol(), addColMeta(), addMeta(), addRow(), addRows(), all(), any(), col(), cols(), colNames(), colToList(), each(), find(), findAll(), first(), flatMap(), foldCol(), foldCols(), get(), gridRowsToDict(), gridColsToDict(), has(), isEmpty(), join(), joinAll(), keepCols(), last(), map(), meta(), missing(), removeCol(), removeCols(), renameCol(), reorderCols(), rowToList(), size(), sort(), sortr(), toGrid(), unique().

// create grid from list of dicts
g: [{dis:"Site-A", area:2300ft²},
    {dis:"Site-B", area:3100ft²},
    {dis:"Site-C", area:1950ft²}].toGrid

g.isEmpty                     >>  false
g.size                        >>  3
g.has("area")                 >>  true
g.missing("foo")              >>  true
g.meta                        >>  grid level meta data
g.cols                        >>  [ Col("dis"), Col("area") }
g.colNames                    >>  ["dis", "area"]
g.col("dis").name             >>  "dis"
g.col("dis").meta             >>  meta data for column "dis"
g.col("foo")                  >>  throws UnknownNameErr
g.col("foo", false)           >>  null
g.colToList("area")           >>  [2300ft², 3100ft², 1950ft²]
g.first                       >>  {dis:"Site-A", area:2300ft²}
g.last                        >>  {dis:"Site-C", area:1950ft²}
g[1]                          >>  {dis:"Site-B", area:3100²}
g[-2]                         >>  {dis:"Site-B", area:3100²}
g[0..1]                       >>  slice to new grid of Site-A, Site-B
g.each(row=>...)              >>  iterate each row as a dict
g.foldCol("area", sum)        >>  7350ft²
g.any r => r->area > 2000ft²  >>  true
g.all r => r->area > 2000ft²  >>  false

Functions which modify a grid always return a new grid (the original is immutable):

g.sort("area")                             >> sort by area column
g.sortr("area")                            >> reverse sort by area column
g.sort((a,b)=>...)                         >> sort with function r => r.set("area", r->²))  >> area ft² -> m²
g.find r => r->dis == "Site-A"             >> find row where dis == "Site-A"
g.findAll r => r->area < 2000              >> grid with rows where area < 2000
rowToName: (r) => r->dis[-1..-1].lower     >> func to map "Site-A" -> "a"
g.gridRowsToDict(rowToName, r=>r->area)    >> {a:2300ft², b:3100², c: 1950ft²}
g.gridColsToDict(c=>,c=> >> {dis:3, area:4}
g.addMeta({title:"Sites"})                 >> adds grid level meta data
g.addColMeta("area", {dis:"Sq Footage"})   >> add column level meta data
g.addCol("areaM2") r => r->²)    >> add new column which is area in m²
g.renameCol("area", "sqFt")                >> rename column area -> sqFt
g.reorderCols(["dis", "area"])             >> force specific column ordering
g.removeCol("area")                        >> remove a column
g.removeCols(["area"])                     >> remove a list of columns
g.keepCols(["dis"])                        >> remove all cols except given list
g.addRow({dis:"Site-D", area: 4000ft²})    >> add new row to end of grid
g.addRows([{dis:"Site-D"},{dis:"Site-E"}]) >> add list of new rows to grid
g.unique("dis")                            >> grid with rows with unique values in dis col

Joins between two grids may be done by column name using join() or joinAll():

// create another grid
h: [{dis:"Site-A", tz:"Chicago"},
    {dis:"Site-B", tz:"Denver"},
    {dis:"Site-C", tz:"New_York"}].toGrid

// join g and h by the dis column
g.join(h, "dis")

// resulting join grid
dis     area      tz
------  --------  --------
Site-A  2,300ft²  Chicago
Site-B  3100ft²   Denver
Site-C  1,950ft²  New_York

Regex Examples

Regular expressions can be used via the reMatches(), reFind(), reFindAll(), and reGroups() functions. Typically you will want to use raw string literals r"" to avoid escaping the backslash:

// check match for entire string
reMatches(r"AHU-(\d+)", "AHU")     // false
reMatches(r"AHU-(\d+)", "AHU-10")  // true

// find substring in a regex
reFind(r"AHU-(\d+)",  "Store-2")        // null
reFind(r"AHU-(\d+)",  "Store-2 AHU-3")  // "AHU-3"

// find all substring groups in a regex
reGroups(r"(Clg|Hgt)-(\d+)", "foo")     // null
reGroups(r"(Clg|Hgt)-(\d+)", "Hgt-7")   // ["Hgt-7", "Hgt", "7"]
reGroups(r"(Clg|Hgt)-(\d+)", "<Hgt-7>") // ["Hgt-7", "Hgt", "7"]

Note that reGroups() returns a list of strings for each group defined by (). The first item in the list is always the entire match.

Axon uses the Java regular expression engine - see java.util.regex.Pattern for full specification.

Read Examples

You can do simple queries to slice and dice your data:

site                          // find everything with site tag
site and geoCity=="Richmond"  // find all the sites in Richmond
equip and siteRef==xxxx       // find all the equip within a site with rec id xxx
equip and siteRef->dis=="Foo" // find all the equip within a site with dis tag "Foo"
ahu and siteRef==xxxx         // find all the AHUs within a site
point and equipRef==xxx       // find all the points within a piece of equipment

The above queries are shorthand for readAll(filter). In general most queries will start will some filter to select a set of recs from the database.

His Examples

To perform time-series analysis you'll typically pipe one or more records to the hisRead() function (SkySpark only):

// get history data for the points within a given piece of equipment
readAll(point and equipRef==xxx).hisRead(2009-10-03) // for a single day
readAll(point and equipRef==xxx).hisRead(2009-10)    // for a month
readAll(point and equipRef==xxx).hisRead(2009)       // for an entire year
readAll(point and equipRef==xxx).hisRead(pastWeek)   // for last 7 days
readAll(point and equipRef==xxx).hisRead(today)      // for today
readAll(point and equipRef==xxx).hisRead(2009-10-01..2009-10-07)

Any of the time range functions can be used with hisRead() including today(), yesterday(), thisWeek(), pastWeek(), thisMonth(), pastMonth().

In general once you get above a days worth of data, you will need to use a rollup to condense the data into a more manageable volume. Rollups are easy:

// find daily max of electrical demand for month of March 2010
readAll(kw).hisRead(2010-03).hisRollup(max, 1day)

As you start to perform time-series analysis, you'll start to to use functions to map, filter, and fold your data:

// find all the days where daily max exceeded 200 KW
readAll(kw).hisRead(2010-03).hisRollup(max, 1day).hisFindAll(v => v > 200)

// find all the periods of time where zone temp was above 75
readAll(zoneTemp).hisRead(pastMonth).hisFindPeriods(v => v > 75)

As you start to write functions that mine the data for certain patterns, you'll want to start combining them. A common technique is to use hisFindPeriods to find different conditions, then compute the intersection:

(ahu, dates) => do

  // find periods in cooling mode for this AHU
  coolPeriods: read(cool and equipRef==ahu->id)
       .hisRead(dates).hisFindPeriods(v => v)

  // find periods in heating mode for this AHU
  heatPeriods: read(heat and equipRef==ahu->id)
        .hisRead(dates).hisFindPeriods(v => v)

  // compute when AHU running in both heating and cooling modes
  hisPeriodIntersection([coolPeriods, heatPeriods])

Def Examples

Common functions for working with defs: conjuncts(), def(), defs(), tags(), terms():

def(^site)        // lookup def for site tag
def("site")       // convenience for site(^site)
defs()            // list all definitions
tags()            // list only tag definitions

Pivot Examples

The pivot() and xqPivot() functions are used to transform a grid or list of dicts into a pivot table. Pivot tables are used to summarize data based on grouping and rolling up of cell values. These functions are only available in SkySpark.

We use a dict called the shape to define how the generate the pivot table:

  • rows: selection to use for row grouping
  • cols: selection to use for column grouping
  • cells: selection and folding function to use for rollups

Selection is a dotted path of tag names with special handling for marker/ref tags. For example "" will select the site id of any target type. If the target has the site marker tag, then its the target id itself, otherwise its the value of siteRef.

All the shape tags (rows, cols, cells) may be a single Dict or a list of Dicts. The dicts must have the select tag with the selector.

Row and col groupings are used to group the rollups by their unique combinations. For example the group [geoState, geoCity] would create a grouping for every unique combination of the geoState and geoCity tags. Any input row missing one of the group's selectors is implicitly skipped in the result.

Row grouping is used to define the summarized rows in the resulting grid. At least one row group tag must be defined. Column grouping is used to create a column in the result for each unique column group.

Cells define which tag to rollup for a given grouping. A default folding function is used based on the selected tag's name. An explicit folding function may be specified with the fold tag. The following folding names are supported:

  • sum: Numbers
  • min: Numbers
  • max: Numbers
  • avg: Numbers
  • count: Anything
  • periodUnion: Str base64 periods, must also have date column

Our examples all use this input grid:

geoState, geoCity,     dur,  cost
"VA",     "Richmond",  10h,   40$
"VA",     "Richmond",   4h,   12$
"VA",     "Richmond",   2h,    6$
"VA",     "Norfolk",    8h,    8$
"VA",     "Norfolk",   11h,    7$
"CA",     "Richmond",   3h,    5$
"CA",     "Richmond",   4h,    4$

A simple pivot which rolls up dur and cost by geoState:

pivot(input, {
  rows: {select:"geoState"},
  cells: [{select:"cost"}, {select:"dur"}]

geoState, cost,  dur
"CA",       9$,   7h
"VA",      73$,  35h

A pivot which folds cost by avg, min, and max:

pivot(input, {
  rows: {select:"geoState"},
  cells: [{select:"cost", fold:"avg"}, {select:"cost", fold:"max"}, {select:"cost", fold:"min"}]

geoState, cost_avg,  cost_max, cost_min
"CA",         4.5$,       5$,       4$
"VA",        14.6$,      40$,       6$

Pivot using two tags for row grouping:

pivot(input, {
  rows: [{select:"geoState"}, {select:"geoCity"}],
  cells: {select:"dur"}

geoState,  geoCity,     dur
"CA",      "Richmond",   7h
"VA",      "Norfolk",   19h
"VA",      "Richmond",  16h

Pivot using a column grouping:

pivot(input, {
  rows: {select:"geoState"},
  cols: {select:"geoCity"},
  cells: {select:"dur"}

geoState, Norfolk dur,  Richmond dur
"CA",         null,        7hr
"VA",         19hr,       16hr

The dicts used for row, col, and cells are passed thru into the column meta of the resulting grid.

Energy Examples

Most energy queries start life using a read/readAll piped to the hisRead function:

// daily consumption data for all sites in Mar 2011
readAll(energy and siteMeter).hisRead(2011-03).hisRollup(sum, 1day)

// monthly consumption data for all sites in 2010
readAll(energy and siteMeter).hisRead(2010).hisRollup(sum, 1mo)

// raw demand data for all sites on 1 Apr 2011
readAll(power and siteMeter).hisRead(2011-04-01)

// demand data normalized by area (square footage/meters)
readAll(power and siteMeter).hisRead(2011-04-01)

// demand data normalized by degree-day
readAll(power and siteMeter).hisRead(2011-04-01)

// demand data normalized by area and degree-day
readAll(power and siteMeter).hisRead(2011-04-01)

// table of site dis and total kWh consumption for March sorted by kWh
readAll(energy and siteMeter).hisRead(2011-03)
  .hisRollup(sum, 1mo)
  .hisFlatten((kw,ts,his) => { dis:his->siteRef->dis, kw:kw })

// average daily profile of hourly demand peak across last month
readAll(power and siteMeter).hisRead(lastMonth)
  .hisRollup(max, 1hr)