Converting Legacy scripts to Core+ Scripts Cheat Sheet
See the User Guide in the Core docs and Core+ docs for comprehensive documentation on the new APIs.
Data access methods
| Deephaven method in Legacy | Python method in Core+ | Groovy method in Core+ |
|---|---|---|
db.i | db.live_table | db.liveTable |
db.t | db.historical_table | db.historicalTable |
Empty .where() clauses
In a Legacy worker, a .where() method applied to an uncoalesced table (e.g., the return from db.t before filtering
by a partitioning column) would coalesce the table. Alternatively, the table could explicitly be realized with the
.coalesce() method. In Core+, you must use the .coalesce() method instead of .where().
Snapshots
In a Legacy worker, trigger.snapshot(source, ...)
snapshots table source according to table trigger. In Core+,
the method is called snapshotWhen and the positions of the tables
are inverted in the call: the trigger is the argument and the source
is the table on which the operation is applied:
source.snapshotWhen(trigger, ...).
In Legacy, the second argument to the snapshot call is a boolean
specifying if an initial snapshot should be made. In Core+, the
equivalent is to pass SnapshotWhenOptions.Flag.INITIAL in the
optional list of flags.
Parameterized queries
Parameterized queries allow on-demand query execution with user-provided parameters through a UI panel. This is a Legacy-only feature and is not available in Core+ workers.
In Core+, parameterized queries are replaced by deephaven.ui, which provides a richer and more flexible set of interactive capabilities.
Key differences
| Legacy | Core+ |
|---|---|
ParameterizedQuery with Parameter definitions | deephaven.ui components |
| UI-based parameter control panel | Reactive UI components with Python/JavaScript |
| Limited parameter types (String, Long, Double, DateTime, Boolean, Table) | Full range of UI components (text inputs, sliders, dropdowns, date pickers, etc.) |
Fixed parameter validation with Constraint objects | Custom validation logic in Python |
Results displayed via scope.setResult() | Direct table and plot rendering in UI |
Migration approach
To migrate a Legacy parameterized query to Core+:
- Replace the
ParameterizedQuerystructure with adeephaven.uiapplication. - Convert
Parameterdefinitions to appropriate UI input components (e.g.,ui.text_input,ui.slider,ui.date_input). - Replace the query function's parameter retrieval logic with reactive UI state.
- Remove
scope.setResult()calls and directly return tables and visualizations.
For detailed information on Legacy parameterized queries, refer to the parameterized queries documentation in earlier versions of the documentation (Legacy only). For Core+ UI development, see the deephaven.ui documentation.
Migrating Persistent Queries
Persistent Queries (PQs) are queries that run regularly to perform data ingestion, analysis, and dashboard creation. Both Legacy and Core+ support PQs, but there are important differences in how they are created and managed.
Worker types
- Legacy workers: Use the Legacy API and syntax.
- Core+ workers: Use the modern Core+ API and syntax (Python snake_case, updated imports, etc.).
Migration steps
To migrate a PQ from a Legacy worker to a Core+ worker:
- Update the query script: Convert all Legacy syntax to Core+ syntax using this cheat sheet.
- Change the worker type: In the PQ configuration, switch from a Legacy worker to a Core+ worker.
- Test thoroughly: Validate that the migrated query produces the same results.
- Update dependencies: Ensure any custom libraries or plugins are compatible with Core+.
Creating and managing PQs
Both Legacy and Core+ PQs are created and managed through:
- The Query Monitor UI.
- Programmatic APIs (Python and Groovy).
The PQ management APIs are largely the same between Legacy and Core+, but the query scripts themselves must use the appropriate syntax for the worker type.
For more information on PQs, see:
Time handling
The Deephaven Core+ time library is very different from the Legacy Library, having been thoroughly modernized as described in these blog posts:
In particular, Legacy queries that used currentDateNy() must use today(), business calendars are entirely re-written, and the syntax of periods as input to time_table have changed.
To get the current date, you must use the today() function, which takes an optional time zone. You can use a full time zone name like America/New_York or the shortcut ET for Eastern time. The equivalent function to currentDateNy() is either today(timeZone(`America/New_York`)) or today('ET'), as in the following example:
quotes = db.liveTable("Market", "EqQuote").where("Date=today('ET')")
quotes = db.live_table("Market", "EqQuote").where("Date=today('ET')")
When the time zone is omitted, the today() function uses the value of the user.timezone property.
The common Legacy idiom lastBusinessDateNy() to get the previous business day's data has been replaced by functions on the BusinessCalendar class. First, you must retrieve the calendar with the calendar() function, which on a default Core+ installation returns the USNYSE business calendar. To verify your default business calendar, you can run the following command:
println(io.deephaven.time.calendar.Calendars.calendar().name())
import deephaven.calendar
print(deephaven.calendar.calendar().name())
You can specify an alternative business calendar name as an argument to the calendar() function. For filtering Date partitions, you may either use the minusBusinessDays method and pass today() as a String argument or use the pastBusinessDate method and convert the resulting java.time.LocalDate to a String.
As a shortcut, you can elide calendar() for the default calendar.
The following examples all retrieve the previous business day's data:
quotes = db.historicalTable("Market", "EqQuote").where("Date=minusBusinessDays(today(), 1)")
quotes2 = db.historicalTable("Market", "EqQuote").where("Date=pastBusinessDate(1).toString()")
quotes3 = db.historicalTable("Market", "EqQuote").where("Date=calendar().minusBusinessDays(today(), 1)")
quotes4 = db.historicalTable("Market", "EqQuote").where("Date=calendar().pastBusinessDate(1).toString()")
quotes5 = db.historicalTable("Market", "EqQuote").where("Date=calendar(`USNYSE`).minusBusinessDays(today(), 1)")
quotes6 = db.historicalTable("Market", "EqQuote").where("Date=calendar(`USNYSE`).pastBusinessDate(1).toString()")
quotes7 = db.historical_table("Market", "EqQuote").where("Date=formatDate(calendar(`USNYSE`).pastBusinessDate(1))")
quotes = db.historical_table("Market", "EqQuote").where(
"Date=minusBusinessDays(today(), 1)"
)
quotes2 = db.historical_table("Market", "EqQuote").where(
"Date=pastBusinessDate(1).toString()"
)
quotes3 = db.historical_table("Market", "EqQuote").where(
"Date=calendar().minusBusinessDays(today(), 1)"
)
quotes4 = db.historical_table("Market", "EqQuote").where(
"Date=calendar().pastBusinessDate(1).toString()"
)
quotes5 = db.historical_table("Market", "EqQuote").where(
"Date=calendar(`USNYSE`).minusBusinessDays(today(), 1)"
)
quotes6 = db.historical_table("Market", "EqQuote").where(
"Date=calendar(`USNYSE`).pastBusinessDate(1).toString()"
)
quotes7 = db.historical_table("Market", "EqQuote").where(
"Date=formatDate(calendar(`USNYSE`).pastBusinessDate(1))"
)
Caution
If you use the pastBusinessDate function, then you must convert the result from a LocalDate to a String. If you compare a LocalDate to your partitioning column, a match is impossible and the result is an empty table.
If you actually want yesterday's data instead of the previous business day's data, you can use minusDays in the clause, which will include non-business days (such as weekends) in the result. For example:
quotes = db.historicalTable("Market", "EqQuote").where("Date=calendar().minusDays(today(), 1)")
import deephaven.calendar
quotes = db.historical_table("Market", "EqQuote").where(
"Date=calendar().minusDays(today(), 1)"
)
For time tables, you must use the new Period syntax. For example:
fiveSeconds = timeTable("PT5s")
oneHour = timeTable("PT1h")
from deephaven import time_table
five_seconds = time_table("PT5s")
one_hour = time_table("PT1h")
Python
Python-only summary of changes
-
Method names are now
snake_case. For example,lastBybecomeslast_by. -
Aggregation names (previously
ComboAggregateFactory) have changed, as detailed below. For example,AggLastbecomesagg.last. -
In instances of more than one parameter, arguments may take array lists instead of multiple strings; e.g.,
t.update(["Update Statement 1", "Update Statement 2", ...]). These are marked in the "Python method renames" table below. For comparison:-
In a Legacy script,
AggTypeswill be comma-separated:source.by(AggCombo(AggType("Col1"), AggType("Col2 = NewCol1")), "Key1" , "Key2"). -
In Core, this becomes an
agg_listwithin arrays:agg_list=[ agg.first(["Col1 = NewCol1"]), agg.last(["Col2 = NewCol2"]), ] source.agg_by(agg_list, by=["GroupingColumns..."])
-
Important
This is not a comprehensive listing of all Python commands -- only those where the syntax has changed.
Core+ Python import equivalents
| Legacy Python import | Core+ Python import |
|---|---|
import com.illumon.iris.db.Plot.* | from deephaven.plot import * |
import com.illumon.iris.db.Plot.colors.* | from deephaven.plot.color import * |
jpy.get_type("com.illumon.iris.db.v2.by.ComboAggregateFactory").* | from deephaven import agg |
import deephaven.Calendars | import deephaven.calendar |
import deephaven.Plot | import deephaven.plot |
from deephaven.Calendars import | from deephaven.calendar import |
from deephaven import Plot | from deephaven import plot |
from deephaven import TableTools |
|
from deephaven.Plot import | from deephaven.plot import |
from deephaven.TableTools import emptyTable | from deephaven import empty_table |
Python method renames
Table constructors
| Legacy | Core+ | Syntax |
|---|---|---|
db.timeTable | time_table | time_table("PT1S") Note: requires from deephaven import time_table |
ttools.emptyTable | empty_table | empty_table(N) Note: requires from deephaven import empty_table |
Aggregation
| Legacy | Core+ | Syntax |
|---|---|---|
AggArray | agg.group | .agg_by([agg.group(cols=["Y"])], by=["X"]) |
AggCombo(<original params>) | agg_list | agg_list = [<original params>] |
AggCount | agg.count_ | .agg_by([agg.count_(col="Number")] |
AggFirst | agg.first | .agg_by([agg.first(cols=["Y"])], by=["X"]) |
AggLast | agg.last | .agg_by([agg.last(cols=["Y"])], by=["X"]) |
AggMax | agg.max_ | .agg_by([agg.max_(cols=["Y"])], by=["X"]) |
AggMed | agg.median | .agg_by([agg.median(cols=["Number"])], by=["X"]) |
AggMin | agg.min_ | .agg_by([agg.min_(cols=["Y"])], by=["X"]) |
AggPct | agg.pct | .agg_by([agg.pct(percentile=0.68, cols=["PctNumber = Number"])], by=["X"]) |
AggStd | agg.std | .agg_by([agg.std(cols=["Number"])], by=["X"]) |
AggSum | agg.sum_ | .agg_by([agg.sum_(cols=["Number"])], by=["X"]) |
AggVar | agg.var | .agg_by([agg.var(cols=["Number"])], by=["X"]) |
avgBy | avg_by | .avg_by() , .avg_by(by=["X"]) |
countBy | count_by | .count_by("Count") |
lastBy | last_by | .last_by |
firstBy | first_by | .first_by |
headBy | head_by | .head_by(2, by=["X"] |
maxBy | max_by | .max_by() |
medianBy | median_by | .median_by() |
minBy | min_by | .min_by() |
stdBy | std_by | .std_by() |
sumBy | sum_by | .sum_by() |
tailBy | tail_by | .tail_by(2, by=["X"]) |
varBy | var_by | .var_by() |
by | group_by | .group_by() |
Filter
| Legacy | Core+ | Syntax |
|---|---|---|
headPct | head_pct | .head_pct(pct=0.40) |
tailPct | tail_pct | .tail_pct(pct=0.40) |
where | where | .where(filters=["Number > 3"]) |
whereIn | where_in | .where_in(filter_table=filter, cols=["X = Values"]) |
whereNotIn | where_not_in | .where_not_in(filter_table=filter, cols=["X = Values"]) |
Sort
| Legacy | Core+ | Syntax |
|---|---|---|
sortDescending | sort_descending | .sort_descending(order_by=["X"]) |
Select
| Legacy | Core+ | Syntax |
|---|---|---|
dropColumns | drop_columns | .drop_columns(cols=["B", "D"]) |
moveColumns | move_columns | .move_columns(idx=1, cols=["C"]) |
moveUpColumns | move_columns_up | .move_columns_up(cols=["B"]) |
renameColumns | rename_columns | .rename_columns(cols=["Fruit = A", "Type = C"]) |
select | select | .select(formulas=["B"]) |
updateView | update_view | .update_view(formulas=["X = B", "Y = sqrt(C)"]) |
update | update | .update(formulas=["A", "X = B", "Y = sqrt(C)"]) |
view | view | .view(formulas=["B"]) |
Join
| Legacy | Core+ | Syntax |
|---|---|---|
exactJoin | exact_join | left.exact_join(table=right, on=["X"]) |
leftJoin | left_outer_join | left_outer_join(l_table=left, r_table=right, on=["I"]) |
naturalJoin | natural_join | left.natural_join(table=right, on=["DeptID"]) |
merge | merge | merge([source1, source2]) |
Format
| Legacy | Core+ | Syntax |
|---|---|---|
formatColumnWhere | format_column_where | .format_column_where(col="X", cond="X > 2", formula="RED") |
formatColumns | format_columns | .format_columns(["A = B > 2 ? BLUE : NO_FORMATTING", "C = Decimal(`0.00%`)"]) |
formatRowWhere | format_row_where | .format_row_where(cond="X > 2 && X < 4", formula="RED") |
Metadata
| Legacy | Core+ | Syntax |
|---|---|---|
getMeta() | meta_table | .meta_table |
size() | size | size |
Plot
| Legacy | Core+ | Syntax |
|---|---|---|
catHistPlot | plot_cat_hist | .plot_cat_hist(series_name="Keys count", t=source, category="Keys") |
catPlot | plot_cat | plot_cat(series_name="Cagetories Plot", t=source, category="Categories", y="Values") |
chartTitle | chart_title | chart_title(title="Name") |
figureTitle | figure_title | figure_title(title="Name") |
histPlot | plot_xy_hist | plot_xy_hist(series_name="Histogram Values", t=source, x="Values", nbins=N) |
lineStyle | LineEndStyle | LineEndStyle(ROUND) |
newChart | new_chart | new_chart(index=int, row=int, col=int) |
ohlcPlot | plot_ohlc | .plot_ohlc(series_name="Name", t=source, x="TimestampBin", open="Open", high="High", low="Low", close="Close") |
piePlot | plot_pie | .plot_pie(series_name="Name",t=source,category="category",y="y-values") |
twinX | x_twin | x_twin(name="string") |
Time
| Legacy | Core+ | Syntax |
|---|---|---|
convertDateTime | to_j_instant | to_j_instant("2022-01-01T00:00:00 ET") Note: requires from deephaven.time import to_j_instant |
Miscellaneous
| Legacy | Core+ |
|---|---|
com.fishlib.base.verify.Assert | io.deephaven.base.verify.Assert |
nullToValue | replaceIfNull |
com.illumon.iris.db.tables.databases.Database#reloadData | io.deephaven.enterprise.database.Database#clearLocationCache |