Skip to content

tdfs4ds.plotting

tdfs4ds.plotting

In-database plotting with TD_PLOT.

The chart is drawn inside Teradata by the UAF function TD_PLOT: the data never leaves the database, only the image does (a PNG of some tens of kB, whatever the number of points - 200,000 points were drawn in 0.5 s on Vantage 20).

How a plot is made (one session, nothing permanent is created):

  1. Count the points of the request (SELECT COUNT(*)): an empty request is said so, and a request above tdfs4ds.PLOT_MAX_POINTS is refused when that setting is a number (default None: TD_PLOT draws any size, and a failure comes back as its whole message).
  2. Stage them in a volatile table with three columns x / y / id (id = the series). TABLE_NAME(...) of a UAF call cannot hold a sub-query, and a volatile table needs no CREATE right (teradataml's own DataFrame.plot writes a permanent ml__ view instead).
  3. Keep the first tdfs4ds.PLOT_MAX_SERIES series (a legend of 300 entries is unreadable); the result says how many were left out.
  4. EXECUTE FUNCTION TD_PLOT(SERIES_SPEC(...), FUNC_PARAMS(...)) returns one row whose IMAGE column holds the picture.
  5. When the request is small (at most tdfs4ds.PLOT_INTERACTIVE_MAX_POINTS points) the staged rows are also read back and drawn as an interactive Plotly chart. Above that, only the image exists: the data stays in the database.
  6. The volatile tables are dropped.

Facts measured on Vantage 20 that shape the SQL below:

  • the axis is TIMECODE for a date/timestamp column (cast to TIMESTAMP(0)) and SEQUENCE for a number (a FLOAT axis is accepted);
  • dates are printed only with XFORMAT('YYYY-MM-DD') - a %Y-%m-%d format is Error 9153 "Invalid label format", and without a format the axis shows 1, 2, 3;
  • TD_PLOT cannot label a categorical axis: a bar chart by category is drawn over positions 1..k with the names in the axis label (and on the interactive version), because one series per category makes the bars unreadable;
  • IMAGE('png' | 'jpg' | 'svg'); a volatile table is a valid TABLE_NAME.

Public functions: :func:plot_in_database (any table, view or query), :func:plot_feature (a feature's stored values) and :func:plot_dataset (a dataset view). Each returns a dict (see :func:plot_in_database); :func:plot_features (several features, one panel each) and :func:plot_panels (any panels in one image: one SERIES_SPEC per panel, LAYOUT(columns, rows), CELL(column, row)). :func:plot_html turns a result into a small HTML page and :func:show_plot displays it in a notebook.

logger module-attribute

logger = getLogger(__name__)

PLOT_KINDS module-attribute

PLOT_KINDS = ('line', 'scatter', 'bar', 'hist', 'periods')

SERIES_ORDERS module-attribute

SERIES_ORDERS = ('largest', 'smallest', 'alphabetical', 'most_points')

_TIME_TYPES module-attribute

_TIME_TYPES = {'DA', 'TS', 'SZ'}

_NUMBER_TYPES module-attribute

_NUMBER_TYPES = {'I', 'I1', 'I2', 'I8', 'F', 'D', 'N'}

_TEXT_TYPES module-attribute

_TEXT_TYPES = {'CV', 'CF', 'CO'}

_PERIOD_TYPES module-attribute

_PERIOD_TYPES = {'PD', 'PS', 'PM', 'PT', 'PZ'}

_AGGREGATES module-attribute

_AGGREGATES = ('avg', 'sum', 'min', 'max', 'count')

_ID_LIKE module-attribute

_ID_LIKE = compile('(?:_id|_ID|ID|_key|_KEY)$')

TD_PLOT_TEXT_MAX module-attribute

TD_PLOT_TEXT_MAX = 127

TD_PLOT_MIN_SIZE module-attribute

TD_PLOT_MIN_SIZE = 400

LEGEND_LOCATIONS module-attribute

LEGEND_LOCATIONS = ('best', 'upper right', 'upper left', 'lower left', 'lower right', 'right', 'center left', 'center right', 'lower center', 'upper center', 'center')

TD_PLOT_MAX_SIZE module-attribute

TD_PLOT_MAX_SIZE = 2400

_LEGEND_ROW_PX module-attribute

_LEGEND_ROW_PX = 21

_LEGEND_CHAR_PX module-attribute

_LEGEND_CHAR_PX = 7

_LEGEND_FIXED_PX module-attribute

_LEGEND_FIXED_PX = 45

_MIN_DATA_PX module-attribute

_MIN_DATA_PX = 500

_TWO_ROWS module-attribute

_TWO_ROWS = '(SELECT 1 AS k FROM (SELECT 1 AS d) a UNION ALL SELECT 2 AS k FROM (SELECT 1 AS d) b) stp'

_FOUR_ROWS module-attribute

_FOUR_ROWS = '(SELECT 1 AS k FROM (SELECT 1 AS d) a UNION ALL SELECT 2 AS k FROM (SELECT 1 AS d) b UNION ALL SELECT 3 AS k FROM (SELECT 1 AS d) c UNION ALL SELECT 4 AS k FROM (SELECT 1 AS d) e) p4'

REBASE_MODES module-attribute

REBASE_MODES = ('first', 'mean', 'median')

_REBASE_WORDS module-attribute

_REBASE_WORDS = {'first': 'first value', 'mean': 'mean', 'median': 'median'}

_PAIR_TOKENS module-attribute

_PAIR_TOKENS = (('start', 'end'), ('begin', 'end'), ('start', 'stop'))

_VALID_END_OR_NOW module-attribute

_VALID_END_OR_NOW = "(CASE WHEN ValidEnd > CURRENT_TIMESTAMP(0) THEN CURRENT_TIMESTAMP(0) ELSE ValidEnd END) - INTERVAL '1' SECOND"

_LAYOUT_OVERRIDES module-attribute

_LAYOUT_OVERRIDES = ContextVar('tdfs4ds_historian_layouts', default=None)

_PERIOD_FEATURE module-attribute

_PERIOD_FEATURE = compile('(?i)^\\s*PERIOD\\b')

quote_ident

quote_ident(name, force=False)

Return name as a Teradata identifier, quoting it only if required.

Idempotent: an already-quoted name is returned unchanged rather than being wrapped a second time. Embedded quotes are escaped as "".

Parameters

name : str The raw object/database name. force : bool, default False Quote even when the name does not need it. Use only at the few sites that have always emitted unconditional quotes and whose exact output is already baked into persisted DDL (see feature_store/feature_query_retrieval.py) — elsewhere forcing would change the SQL of existing stores for no reason.

qualified

qualified(database, object_name, force=False)

Build db.obj with each part quoted only as needed.

qualified('TDB', 'FS_X') == 'TDB.FS_X' (unchanged for ordinary names); qualified('SVC@CORP', 'FS_X') == '"SVC@CORP".FS_X'. An empty/None database yields the bare object name, so unqualified callers keep working.

force=True quotes both parts unconditionally — only for the sites that have always emitted quotes and whose exact text is already persisted (dataset view DDL, returned volatile-table names).

split_qualified

split_qualified(name)

Split db.obj into (database, object), both de-quoted.

Quote-aware, so a dot inside a quoted part does not split the name: split_qualified('"DEINF.CARLOSN"."FS_X"') == ('DEINF.CARLOSN', 'FS_X'). The naive rsplit('.', 1) this replaces returns ('"DEINF.CARLOSN"', '"FS_X"') only by luck and ('"DEINF', 'CARLOSN"."FS_X"') in the split('.') variant.

An unqualified name returns ('', name).

sql_literal

sql_literal(value)

Escape value for use inside a single-quoted SQL string literal.

For the DBC probes and catalog predicates that compare a name as data (WHERE DatabaseName = '…'). The caller supplies the surrounding quotes.

_setting

_setting(name, default)

_max_points

_max_points()

tdfs4ds.PLOT_MAX_POINTS, or None (the default): no limit before TD_PLOT.

_max_series

_max_series()

_interactive_max_points

_interactive_max_points()

_max_panels

_max_panels()

_svg_max_points

_svg_max_points()

_legend_inline_max

_legend_inline_max()

_legend_max

_legend_max()

_max_corr_columns

_max_corr_columns()

legend_plan

legend_plan(n_series: int, label_chars: int, *, numeric_x: bool, x_range=None, width: int = 900, height: int = 450, layout=(1, 1)) -> dict

Where the legend of a panel goes, and the image size it needs.

Up to tdfs4ds.PLOT_LEGEND_INLINE_MAX series: LEGEND('best'), nothing changes. Above tdfs4ds.PLOT_LEGEND_MAX: no legend (it would be taller than the chart and unreadable). In between, TD_PLOT cannot put the legend outside the plot, so room is made inside it: the image grows taller until every entry fits and, on a numeric x axis, the x range is extended on the right by the legend's width, which then sits in empty space ('upper right'). A time axis takes no XRANGE (Error 3706) and no empty point (NULL payload refused), so there the legend stays 'best' in the taller image.

Returns {"legend": False | location, "width", "height", "xrange", "note"}.

_text

_text(value) -> str

A TD_PLOT string argument: quoted, apostrophes doubled, no line breaks, at most TD_PLOT_TEXT_MAX characters (cut with "...").

_plot_params

_plot_params(p: dict, cell=(1, 1), plot_id: int = 1) -> str

_series_spec

_series_spec(table: str, axis: str) -> str

td_plot_multi_sql

td_plot_multi_sql(panels: list, *, layout=(1, 1), title=None, width: int = 900, height: int = 450, image: str = 'png', dpi: int = 100) -> str

One TD_PLOT over several staged tables, one panel each.

panels: dicts with table, axis, kind, title, xlabel, ylabel, xformat, legend and cell = (column, row). One SERIES_SPEC per panel, in order; the panel's ID(i) is its position. layout is (columns, rows). Verified live: line and bar panels mix.

td_plot_sql

td_plot_sql(table: str, *, axis: str = 'timecode', kind: str = 'line', title=None, xlabel=None, ylabel=None, xformat=None, legend: bool = True, width: int = 900, height: int = 450, image: str = 'png', dpi: int = 100) -> str

The EXECUTE FUNCTION TD_PLOT statement over one staged x/y/id table.

axis is 'timecode' (date/timestamp x) or 'sequence' (numeric x). kind is a TD_PLOT type: line, scatter or bar (a histogram is a bar chart over bin centres, see :func:histogram_staging_sql).

_source_clause

_source_clause(source: str) -> str

FROM target: a query is wrapped as a derived table, a name is used as is.

A temporal qualifier does not belong in source (inside a derived table it is refused): pass it as qualifier=; it then opens the whole statement and applies to every temporal table the statement reads.

_q

_q(qualifier) -> str

_where

_where(where) -> str

staging_sql

staging_sql(name: str, source: str, x: str, y: str, series: Optional[str] = None, *, x_is_time: bool = True, where: Optional[str] = None, qualifier: Optional[str] = None, step_end: Optional[str] = None, clip=None, y_select: Optional[str] = None, x_known: bool = False) -> str

CREATE VOLATILE TABLE <name> with x / y / id from source.

x, y and series are SQL expressions over the source's columns (quote identifiers with :func:tdfs4ds.utils.identifiers.quote_ident). Rows with a NULL x or y are left out: a gap is not a point. y_select replaces y in the SELECT only (a window function, such as :func:rebased, cannot be in the WHERE). x_known: the source never gives a NULL x, so no test on it - a test on an expression of a time column is pushed into the source and costs a PTI its time-range read (measured: all-rows scan instead).

periods_staging_sql

periods_staging_sql(name: str, source: str, start: str, end: Optional[str], series: Optional[str] = None, *, where: Optional[str] = None, qualifier: Optional[str] = None, clip=None) -> str

Periods drawn as pulses: y = 1 while a period holds, 0 outside.

Each row gives four points from a four-row cross join: (start, 0), (start + 1 s, 1), (end - 1 s, 1), (end, 0). The one-second ramps are inside the period, so two adjacent periods (one ends where the next starts) meet at the same point at 0 - with ramps outside, their points had no order at one x and the line went back and forth. A missing end, or an end after now (an open period, UNTIL_CHANGED), is drawn up to now. clip (lo, hi) (SQL literals) cuts the periods at the edges of a zoom window.

rebase_mode

rebase_mode(rebase) -> Optional[str]

None (no index) or the reference of the index: 'first' (True), 'mean' or 'median' of each curve.

rebase_update_sql

rebase_update_sql(table: str, mode: str) -> list

Statements turning the staged y of every curve (id) of table into an index: 100 at the curve's mean or median, over everything staged for it (the whole extracted series).

Run on the staging table, after it is filled. Teradata has MEDIAN as an aggregate only, and not in a sub-query either (MEDIAN(...) OVER is Error 3707, MEDIAN in a derived table Error 3706, both measured), so the reference of each curve is grouped once into its own volatile table (<table>_ref, dropped by the last statement) and joined back. A curve whose reference is 0 or NULL cannot be indexed and is removed (TD_PLOT refuses a NULL value).

rebased

rebased(y: str, x: str, series: Optional[str] = None, from_x=None) -> str

y as an index: 100 at the series' first point (in the window drawn), or at its first point at or after from_x (0 = the start of an aligned period).

Series of different levels then start from the same origin and their moves compare directly. A first value of 0 gives no point.

histogram_staging_sql

histogram_staging_sql(name: str, source: str, value: str, *, bins: int = 20, where: Optional[str] = None, qualifier: Optional[str] = None) -> str

A histogram of value: x = bin centre, y = number of rows in the bin.

Bins are equal-width between the minimum and the maximum (WIDTH_BUCKET); the upper bound is nudged so the maximum falls in the last bin. A constant column yields one bin.

category_staging_sql

category_staging_sql(name: str, source: str, category: str, value: Optional[str], *, agg: str = 'avg', where: Optional[str] = None, qualifier: Optional[str] = None) -> str

One bar per category: x = position 1..k (alphabetical), y = the aggregate.

One series (id is constant: a series per category draws unreadable bars); the category name is in lbl, which TD_PLOT does not read, for the axis label and the interactive version.

count_sql

count_sql(source: str, x: Optional[str], y: Optional[str], where: Optional[str] = None, qualifier: Optional[str] = None) -> str

The number of points a request would stage (before staging anything).

cap_series_sql

cap_series_sql(name: str, max_series: int, order: str = 'alphabetical') -> str

Keep max_series series of a staged table, chosen by order.

alphabetical - the first names; largest / smallest - by the value at the series' last x (the latest value of a history); most_points - the series with the most points.

_order_words

_order_words(order: str) -> str

_execute

_execute(sql)

_drop

_drop(name)

_error_text

_error_text(exc) -> str

_plot_unavailable

_plot_unavailable(message: str) -> bool

TD_PLOT (UAF) missing on this system: an unknown function, not a bad request.

_mime

_mime(image: str) -> str

_new_result

_new_result(kind, title)

_bound

_bound(value, is_time: bool, upper: bool = False)

A SQL literal for one end of a window, or None.

Time: anything :func:tdfs4ds.serve.store_consistency.normalise_as_of reads (no offset = UTC), plus YYYY-MM (the month's first day; as an upper bound, the next month's first day, so "to 2023-06" includes June).

window_predicate

window_predicate(x: str, xlim, is_time: bool, step_end: Optional[str] = None) -> Optional[str]

Rows inside an x window (low, high); either end may be None.

A step (a value held over a period) is kept when its period overlaps the window, not only when it starts inside it.

panel

panel(source: str, x: Optional[str] = None, y: Optional[str] = None, *, series: Optional[str] = None, kind: str = 'line', x_is_time: Optional[bool] = None, agg: str = 'avg', bins: int = 20, where: Optional[str] = None, qualifier: Optional[str] = None, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, xformat: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, step_end: Optional[str] = None, xlim=None, ylim=None, rebase=False, rebase_from=None, x_known: bool = False) -> dict

One panel of a chart: what to read and how to draw it (validated, not run).

rebase: each series as an index, so curves of different levels are superimposed. True / 'first': 100 at its first point in the window (at or after rebase_from when given, :func:rebased); 'mean' / 'median': 100 at the mean / median of the whole curve drawn (:func:rebase_update_sql).

xlim (low, high) zooms on the x axis: the rows are filtered to the window in SQL (TD_PLOT refuses XRANGE on a time axis, Error 3706, and filtering gives the database more points to draw in the window); on a numeric axis XRANGE is set too. For a histogram the window is on the values. ylim (low, high) sets YRANGE.

See :func:plot_in_database for the arguments; a list of panels is drawn by :func:plot_panels.

default_layout

default_layout(n: int)

(columns, rows) for n panels: stacked up to 3, then two columns.

_time_format

_time_format(table: str, xlabel)

(XFORMAT, xlabel) for a time axis, from the span of the staged rows.

TD_PLOT accepts YYYY-MM-DD, YYYY-MM, DD/MM/YYYY and HH:MI but no date and time together (Error 9153, measured): within one day the ticks are hours and the date goes in the axis label; over about 13 months, months.

_stage_panel

_stage_panel(p: dict, name: str) -> dict

Count, stage and cap one panel; returns its drawing parameters (or an error).

plot_panels

plot_panels(panels: list, *, title: Optional[str] = None, layout=None, width: Optional[int] = None, height: Optional[int] = None, image: str = 'png', interactive='auto') -> dict

Draw several panels in one image, in the database (one TD_PLOT call).

Parameters:

Name Type Description Default
panels list

:func:panel dicts (at most tdfs4ds.PLOT_MAX_PANELS, 6).

required
title Optional[str]

the title over all panels.

None
layout

(columns, rows); default :func:default_layout.

None
width, height

pixels; default from the layout.

required
interactive

as for :func:plot_in_database, judged on all the points.

'auto'

Returns the dict of :func:plot_in_database, plus panels (one entry per panel: its title, points, series, staging SQL and error). A panel with nothing to draw is left out and named in notes; the call fails only when no panel is left.

_svg_copy

_svg_copy(sql: str, image: str, n_points: int) -> Optional[bytes]

The same chart as SVG (a vector image: sharp at any zoom), for a request of at most tdfs4ds.PLOT_SVG_MAX_POINTS points - an SVG holds every point, so a large one weighs megabytes. None when skipped or refused.

plot_in_database

plot_in_database(source: str, x: Optional[str] = None, y: Optional[str] = None, *, series: Optional[str] = None, kind: str = 'line', x_is_time: Optional[bool] = None, agg: str = 'avg', bins: int = 20, where: Optional[str] = None, qualifier: Optional[str] = None, title: Optional[str] = None, xlabel: Optional[str] = None, ylabel: Optional[str] = None, xformat: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, xlim=None, ylim=None, width: int = 900, height: int = 450, image: str = 'png', interactive='auto') -> dict

Draw a chart in the database with TD_PLOT.

Parameters:

Name Type Description Default
source str

a qualified table or view name, or a SELECT (it becomes a derived table). A temporal qualifier goes in qualifier, never in the query.

required
x Optional[str]

SQL expression of the x axis. kind='hist' ignores it; for kind='bar' it is the category column (text) or a numeric/time axis.

None
y Optional[str]

SQL expression of the value (for hist: the value to bin).

None
series Optional[str]

SQL expression of the series (one line/colour each), or None.

None
kind str

line | scatter | bar | hist.

'line'
x_is_time Optional[bool]

True = date/timestamp axis, False = numeric. Must be given for a line/scatter/numeric bar.

None
agg str

for a categorical bar: avg | sum | min | max | count.

'avg'
bins int

for hist.

20
where Optional[str]

an extra predicate on the source.

None
qualifier Optional[str]

a temporal qualifier opening every statement (CURRENT VALIDTIME, VALIDTIME AS OF TIMESTAMP '...', NONSEQUENCED VALIDTIME) when source is a temporal table.

None
series_order Optional[str]

which series are kept when there are more than max_series: largest (default: largest latest value), smallest, alphabetical, most_points.

None
max_series Optional[int]

how many series to draw (default tdfs4ds.PLOT_MAX_SERIES).

None
xlim

zoom on x, (low, high) (dates/timestamps or numbers; either end may be None): the rows are filtered to the window in SQL.

None
ylim

(low, high) of the y axis.

None
interactive

'auto' (an interactive version when the request has at most tdfs4ds.PLOT_INTERACTIVE_MAX_POINTS points), True or False.

'auto'

Returns:

Type Description
dict

dict with ok, image (bytes), mime, n_points, n_series,

dict

n_series_total, series_capped, labels (categorical bar),

dict

interactive_html (or None), td_plot_sql, staging_sql, notes,

dict

panels and error (the whole database message). Never raises for a

dict

database error; raises ValueError for an invalid request.

_add_traces

_add_traces(fig, s, rows, row=None, col=None)

_plotly_panels_html

_plotly_panels_html(staged, data_rows, cells, layout, *, title=None) -> str

_plotlyjs_mode

_plotlyjs_mode()

tdfs4ds.PLOT_PLOTLYJS: 'cdn' (default) or 'inline'.

Inline, plotly.js makes each page ~4.8 MB, and a chat answer travels in the conversation memory: the interactive version loads it from its CDN instead. Without network the TD_PLOT image is still there; 'inline' for offline use.

image_data_uri

image_data_uri(result: dict) -> Optional[str]

plot_html

plot_html(result: dict) -> str

A self-contained HTML page: the TD_PLOT image, and the interactive version behind a toggle when there is one. No external request.

_file_stem

_file_stem(result: dict) -> str

_toolbar

_toolbar(result: dict) -> str

Download PNG / SVG and an actual-size toggle. The chat frame is sandboxed with allow-downloads; the files are built from the page itself.

save_plot

save_plot(result: dict, path: str) -> str

Write a plot result to path: .png / .jpg (the TD_PLOT image), .svg (the SVG copy, made for requests of at most tdfs4ds.PLOT_SVG_MAX_POINTS points) or .html (the page shown in the chat). Returns the path.

_inline_plotly

_inline_plotly(full_html: str) -> str

The body of a Plotly page (its scripts included), to embed in another page.

chart_payload

chart_payload(result: dict) -> Optional[dict]

{"title", "html", "height"} for the chat (the shape MCP charts use).

show_plot

show_plot(result: dict)

Display a plot result in a notebook (the image, else the interactive chart).

column_types

column_types(database: str, obj: str) -> dict

{column: type code} from HELP COLUMN (works for views, unlike DBC.ColumnsV).

_is_time

_is_time(code)

_is_number

_is_number(code)

_is_text

_is_text(code)

_find_column

_find_column(columns: dict, name: str) -> Optional[str]

_series_expr

_series_expr(cols) -> Optional[str]

_values_list

_values_list(values) -> list

values_filter

values_filter(columns, values) -> Optional[str]

A predicate keeping the rows whose entity matches one of values.

A value matches the whole key (a | b for a composite entity) or any one of its columns - "Travel" selects every series of the Travel category.

_matching_values

_matching_values(source: str, columns, candidates, *, where=None, qualifier=None, limit: int = 60, case_insensitive: bool = False) -> list

Which candidates are values of columns in source (one query per column).

case_insensitive: "nvda" finds the stored "NVDA", and the stored spelling is returned (the filter that follows compares exact values).

dataset_columns

dataset_columns(database: str, obj: str)

(entity columns, feature columns) of a registered dataset, from its catalog.

([], []) when the view is not registered or the catalog cannot be read: the caller then falls back on the column types alone.

_ts0_text

_ts0_text(expr: str, with_tz: bool) -> str

A timestamp of any precision as TIMESTAMP(0), through its text.

CAST(<TIMESTAMP(6)> AS TIMESTAMP(0)) is refused (Error 7454, precision reduction, seen with DELTA_T periods); the text keeps the seconds. A value with a time zone is read in UTC first.

period_bounds

period_bounds(column: str, type_code: str) -> Optional[tuple]

(start, end) SQL expressions (TIMESTAMP(0)) of a PERIOD column, or None for a PERIOD of times of day (no date: not a time axis).

start_end_pairs

start_end_pairs(columns: dict) -> list

[(start column, end column)]: two date/timestamp columns named as the bounds of one period (X_START / X_END, ValidStart / ValidEnd, BEGIN_X / END_X).

_periods_of

_periods_of(cols: dict) -> list

The periods a table or view holds: PERIOD columns, then start/end pairs. [{"label", "start", "end", "columns"}], start / end being SQL.

_end_or_now

_end_or_now(end: str) -> str

A period's end, or now when it is still open, one second early (see _VALID_END_OR_NOW): the end of a step.

describe_dataset

describe_dataset(dataset: str) -> dict

{database, view, columns: {name: type}, entity, features, periods} of a view or table.

periods lists its PERIOD columns and start/end column pairs (see :func:start_end_pairs): a value over a period is drawn as a step, and the periods themselves can be drawn (kind='periods').

_find_period

_find_period(d: dict, name: Optional[str]) -> Optional[dict]

The period a name designates: its label or its PERIOD column (not a start column alone: that one stays a plain time axis unless the default picks it).

_dataset_series

_dataset_series(d: dict, x_col, y_cols) -> list

dataset_entity_values

dataset_entity_values(dataset: str, candidates) -> list

The candidates that are entity values of the dataset (the agent passes the words of the question; only real values come back).

dataset_panels

dataset_panels(dataset: str, y=None, *, x: Optional[str] = None, series=None, kind: Optional[str] = None, agg: str = 'avg', bins: int = 20, where: Optional[str] = None, entity_values=None, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, xlim=None, ylim=None)

The panels :func:plot_dataset draws, and a description of what they read.

_periods_panels

_periods_panels(d, period, series, where, entity_values, title, series_order, max_series, xlim)

One kind='periods' panel over a view's period (see :func:dataset_panels).

plot_dataset

plot_dataset(dataset: str, y=None, *, x: Optional[str] = None, series=None, kind: Optional[str] = None, agg: str = 'avg', bins: int = 20, where: Optional[str] = None, entity_values=None, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, layout=None, xlim=None, ylim=None, **kwargs) -> dict

Plot columns of a dataset view in the database.

Parameters:

Name Type Description Default
dataset str

'db.view' or a bare name (read in tdfs4ds.view_schema()).

required
y

the value column (a feature), or a list of columns: one panel each (same x, series and kind). Default: the first numeric feature of the dataset (from its catalog), else the first numeric non-entity column.

None
x Optional[str]

the x column. Default: the first date/timestamp column (ValidStart for a historical dataset).

None
series

a column or a list of columns (one line each). Default: the dataset's entity columns that are not dates (else its text columns).

None
kind Optional[str]

line (time x), scatter (numeric x), bar (text x: aggregated with agg; time or numeric x: one bar per point) or hist (distribution of y). Default: line for a time x, scatter for a numeric x, bar for a text x, hist without x.

None
entity_values

keep only these entity values (a value matches the whole key or any one of its columns).

None
series_order, max_series

which series are drawn (see :func:plot_in_database).

required
layout

(columns, rows) for several panels.

None
xlim, ylim

zoom, see :func:plot_in_database.

required

_feature_rows

_feature_rows(feature: str, entity=None, data_domain=None)

Current feature-catalog rows for a name (all domains unless one is given).

resolve_feature

resolve_feature(feature: str, entity=None, data_domain=None) -> dict

The one feature a name designates, or ValueError naming the candidates.

_feature_storage

_feature_storage(f: dict, process_id=None)

(table, entity columns, column types, feature id, version, notes).

feature_entity_values

feature_entity_values(feature: str, candidates, *, entity=None, data_domain=None) -> list

The candidates that are entity values of the feature's stored rows.

feature_panel

feature_panel(feature: str, *, kind: str = 'distribution', entity=None, data_domain=None, entity_values=None, process_id: Optional[str] = None, as_of=None, bins: int = 20, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, xlim=None, ylim=None)

The panel :func:plot_feature draws, and a description of what it reads.

_history_version_notes

_history_version_notes(feature: str, process_id: str) -> list

A note when the stored history was computed by several process versions (the SQL beneath the process changed, 0.3.3.12). Fail-open: [] otherwise.

plot_feature

plot_feature(feature: str, *, kind: str = 'distribution', entity=None, data_domain=None, entity_values=None, process_id: Optional[str] = None, as_of=None, bins: int = 20, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, xlim=None, ylim=None, **kwargs) -> dict

Plot a feature's stored values in the database (its FS_T_* storage table).

Parameters:

Name Type Description Default
feature str

the feature name (with entity / data_domain when the name exists for several).

required
kind str

'distribution' - histogram of the values at the valid time (current, or as_of); 'history' - the values over time, one line per entity value. When the entity has a date column (a daily feature) that column is the time axis; otherwise the axis is the valid time (ValidStart: when each value started to hold).

'distribution'
entity_values

keep only these entity values (a value matches the whole key or any one of its columns).

None
series_order, max_series

which entity values a history shows when there are more than max_series (default: the 12 with the largest latest value; 'smallest', 'alphabetical', 'most_points').

required
process_id Optional[str]

the producing process (FEATURE_VERSION) when several processes compute the feature. Default: the one written most recently.

None
as_of

valid time for 'distribution' and a dated 'history'.

None
xlim, ylim

zoom (a time window for a history, a value range for a distribution), see :func:plot_in_database.

required

plot_features

plot_features(features, *, kind: str = 'distribution', entity=None, data_domain=None, entity_values=None, as_of=None, bins: int = 20, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, layout=None, xlim=None, ylim=None, **kwargs) -> dict

Several features in one image, one panel each (each keeps its own scale).

features is a list of names, or of dicts with feature and any argument of :func:plot_feature (kind, entity, data_domain, entity_values, process_id) to vary per panel. The other arguments apply to every panel. A feature that cannot be drawn is left out and named in notes.

using_layout

using_layout(table: str, layout: dict)

Draw table with layout inside the with block, whatever its DEEP_LAYOUT section says (or when it has none).

historian_layout

historian_layout(table: str)

(database, table, layout) of a historian (deep) table, from its documented DEEP_LAYOUT (see tdfs4ds.set_deep_table_documentation), or from :func:using_layout.

The layout names the id columns, the tag column (which signal a row holds), the payload column (its value) and the timestamp column.

historian_tags

historian_tags(table: str, limit: int = 200) -> list

The tags a historian table holds (distinct values of its tag column).

historian_panels

historian_panels(table: str, tags, *, id_values=None, xlim=None, ylim=None, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, rebase=False)

The panels :func:plot_historian draws, and a description of what they read.

One panel per tag (tags carry different units): x = the timestamp column, y = the payload, one line per id (the id columns), rows of that tag only. Tags and id values are matched case-insensitively against the table; an unknown one is a ValueError naming what exists.

plot_historian

plot_historian(table: str, tags, *, id_values=None, xlim=None, ylim=None, title: Optional[str] = None, series_order: Optional[str] = None, max_series: Optional[int] = None, extra_panels=None, layout=None, rebase=False, **kwargs) -> dict

Plot tags of a historian (deep) table as time series, in the database.

A historian table holds one row per (ids, timestamp, tag) with the value in a payload column; its documented layout says which column is which. Each tag is drawn in its own panel, one line per id value.

Parameters:

Name Type Description Default
table str

'db.table' (or a view with the same layout).

required
tags

a tag or a list of tags ('CLOSE', ['CLOSE', 'VOLUME']).

required
id_values

keep these ids ('NVDA' or a list); matched case-insensitively.

None
xlim

a time window (low, high); :func:feature_window gives one from a feature's period.

None
extra_panels

more :func:panel dicts drawn below, in the same image (e.g. :func:feature_periods_panel).

None
rebase

superimpose the series: each one as an index, 100 at its first point in the window (True / 'first'), or at the mean / median of the whole series drawn ('mean' / 'median').

False
series_order, max_series, ylim, layout

see :func:plot_dataset.

required

_counterpart

_counterpart(name: str)

The other bound of a start/end name (last_stress_start <-> last_stress_end), or None.

feature_bounds

feature_bounds(feature: str, *, entity=None, data_domain=None)

(start feature row, end feature row or None) for a period feature or either bound of a start/end pair of time features; ValueError otherwise.

_stored

_stored(f: dict, process_id=None)

_as_text

_as_text(v) -> Optional[str]

feature_window

feature_window(feature: str, entity_values=None, *, entity=None, data_domain=None, as_of=None) -> dict

The time window a feature's stored period gives, for one entity value.

feature is a PERIOD feature, or either bound of a pair of date/timestamp features (last_stress_start / last_stress_end: either name works). The value is read at the current valid time, or at as_of. A missing end means the period is still open (up to now).

Returns {"xlim": (start, end or None), "entity_value", "features", "as_of"}; ValueError when the feature holds a value for several entity values and none was named; LookupError when nothing is stored.

feature_periods_panel

feature_periods_panel(feature: str, entity_values=None, *, entity=None, data_domain=None, xlim=None, title: Optional[str] = None, max_series: Optional[int] = None) -> tuple

Every period a feature has held over its history, drawn as pulses.

A feature that holds a period (last_stress_start / last_stress_end, or a PERIOD feature) changes as its process runs over business dates: its history keeps each distinct period (every stress episode). Returns (panel, source); draw it with :func:plot_panels or as an extra_panels of :func:plot_historian.

_feature_periods_inner

_feature_periods_inner(feature: str, entity_values=None, *, entity=None, data_domain=None)

(sql, entity key columns, matched entity values, start row, end row): every distinct period a feature has held (p_start / p_end, with the entity key), read NONSEQUENCED VALIDTIME. The SQL is meant to sit inside a derived table.

feature_periods

feature_periods(inner: str, key=(), values=None) -> list

[(start, end)] (text, oldest first): the distinct periods of :func:_feature_periods_inner, an open end read as now. One small read, so the series query can carry each period as literals.

aligned_source_sql

aligned_source_sql(source: str, layout: dict, tag: str, periods, *, margin_days: int = 0, id_values=None) -> str

The rows of one tag, around each period, with the days from its start.

One UNION ALL branch per period, each with literal time bounds: a historian table is often a PTI or partitioned on time, and it reads a time range only for literal bounds (bounds from a join or a sub-query read the whole table - measured). The tag and ids are compared without TRIM so their predicates stay usable by an index. A row near two periods belongs to both curves.

aligned_periods_panels

aligned_periods_panels(table: str, tags, period_feature: str, *, period_values=None, id_values=None, margin_days: int = 0, rebase=True, title: Optional[str] = None, max_series: Optional[int] = None, per_id: bool = False)

The panels :func:plot_aligned_periods draws, and what they read.

plot_aligned_periods

plot_aligned_periods(table: str, tags, period_feature: str, *, period_values=None, id_values=None, margin_days: int = 0, rebase=True, title: Optional[str] = None, max_series: Optional[int] = None, per_id: bool = False, layout=None, **kwargs) -> dict

Superimpose the periods a feature has held, on a historian series.

Each period (every distinct one in the feature's history, e.g. every stress episode) becomes one curve; the x axis is the number of days from the period's start, so periods months apart overlay; with rebase (default) the values are an index, 100 at the start. Every id and every period share ONE chart per tag (a curve = an id and a period); per_id=True draws one panel per id instead.

Parameters:

Name Type Description Default
table str

the historian table (its documented layout gives the columns).

required
tags

the tag(s) drawn.

required
period_feature str

a PERIOD feature or either bound of a start / end pair.

required
period_values

the feature's entity values whose periods are used.

None
id_values

the historian ids drawn (default: all).

None
margin_days int

days kept before the start and after the end of each period.

0
rebase

values as an index: True / 'first' = 100 at the period's start; 'mean' / 'median' = 100 at the mean / median of the whole curve drawn (margin included); False keeps the values.

True
per_id bool

one panel per id value instead of one chart holding them all.

False

correlation_staging_sql

correlation_staging_sql(name: str, source: str, columns: list, *, where: Optional[str] = None) -> tuple

Two statements: every CORR(a, b) in ONE pass over source (a one-row table), then the k x k matrix x / y / v built from that row. NULL correlations (a constant column) are left out.

td_plot_mesh_sql

td_plot_mesh_sql(table: str, *, title=None, xlabel=None, ylabel=None, width: int = 760, height: int = 640, image: str = 'png', vmin: float = -1.0, vmax: float = 1.0, cmap: str = 'RdBu') -> str

TD_PLOT of a matrix (MATRIX_SPEC) as a mesh heatmap with a colour bar.

plot_correlation

plot_correlation(dataset: str, columns=None, *, where: Optional[str] = None, title: Optional[str] = None, image: str = 'png', interactive='auto', width: int = 760, height: int = 640) -> dict

The correlation matrix of a dataset's numeric columns, drawn in the database.

Every Pearson correlation is computed in ONE pass (CORR) and the matrix is drawn by TD_PLOT as a heatmap (mesh, colour bar from -1 to 1). The matrix itself (k x k aggregates, not rows) is returned in matrix and drawn interactively with the column names on both axes.

Parameters:

Name Type Description Default
dataset str

'db.view' or a bare name.

required
columns

the columns (at least 2, at most tdfs4ds.PLOT_MAX_CORR_COLUMNS, 16). Default: the dataset's numeric features.

None
where Optional[str]

a predicate on the rows used.

None

_plotly_heatmap_html

_plotly_heatmap_html(names, matrix, title) -> str