chartcartesian — u_pbt_chartcartesian #
← Component reference · Guide contents
Cartesian chart: columns, bars, lines, areas and scatter, on one category axis and one or two value axes. The type is set per series.
▶ See it live — Demo application, Cartesian chart tile: the preview, the code behind it and this page, side by side.
In brief #
| Userobject | u_pbt_chartcartesian |
| Item class | n_pbt_chartcartesian_series (of_item(key)) · n_pbt_chartcartesian_axis (of_axis(axis)) |
| Used for | Comparing values along an axis — months, products, regions |
| Principle | You set the categories then the series; the scales, the grid and the animation are ours |
Quick start #
// Local variables
string ls_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun"}
double ld_sales[] = {420, 510, 480, 620, 700, 660}
// The categories FIRST : they fix how many values a series carries
uo_chart.of_set_categories(/*labels*/ ls_months)
uo_chart.of_add_series(/*key*/ "sales", /*label*/ "Revenue", /*type*/ u_pbt_chartcartesian.TYPE_BAR, /*values*/ ld_sales)
The type belongs to the SERIES, not to the component #
This is the decision everything else follows from. One component per type — one for bars, one for lines — can never produce a combination: bars with a target line over them, on a second axis. Yet that is the most asked-for shape on a dashboard.
Here there is one component, and each series carries its is_type (TYPE_BAR, TYPE_LINE, TYPE_AREA, TYPE_SCATTER, TYPE_STEPLINE). Changing one series' type leaves the others alone.
ib_secondary puts a series on the second value axis. That is what lets an order count and a revenue figure live together: without it, one of the two is a flat line along the axis.
of_set_categoriescomes before the series: their number fixes how many values each series must carry.
// Local variables
double ld_target[] = {400, 500, 550, 600, 680, 720}
// Bars and a line in the SAME chart : the type belongs to the series
uo_chart.of_add_series(/*key*/ "target", /*label*/ "Target", /*type*/ u_pbt_chartcartesian.TYPE_LINE, /*values*/ ld_target)
// And its own scale, when the two do not share a unit
uo_chart.of_item(/*key*/ "target").ib_secondary = true
Properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_title | string | "" | Chart title, shown above |
ib_show_legend | boolean | true | Shows the legend. Clicking an entry hides its series — the cheapest way to compare two series out of five |
is_legend_location | string | bottom | Where the legend goes (LEGEND_* constants): above or below the plot, or beside it — START/END put it in a column on one side, and the plot gives up that room. START/END are logical: they follow the reading direction. An unknown place is the bottom, and reads back as such |
ib_show_grid | boolean | true | The rules behind the plot, at every round value. Without them only the shape stays readable, never a value |
ib_value_tooltip | boolean | true | The value panel: when the mouse passes over a category, every series and its value there, at once, and a crosshair marks the column. It is not is_tooltip (inherited), which is the tooltip of the whole component — this one follows the pointer and says what the chart is made of. Each series writes its line with its own is_label_format; a missing value has no line. The tooltip of a series (its is_tooltip) is written in this panel, under the row of the series pointed at, even at false |
is_orientation | string | vertical | Columns or bars (ORIENTATION_* constants). Turns the whole frame of reference, lines and areas included |
ib_stacked | boolean | false | Stacks the bar series instead of setting them side by side; the area series stack among themselves — never bars with areas. A line is never stacked: it says a level. The bars of the second axis make their own stack, beside the stack of the main axis |
is_stack_mode | string | value | Sum or share (STACK_* constants). In percentage every stack is brought to 100: the axis then reads shares, not totals — down to -100 when some shares are negative. Means nothing outside stacking |
ib_enabled | boolean | true | Greyed out: the component keeps showing what it shows — a chart with no data is a different thing from a chart the application has switched off — but it stops answering: no click, no key, no legend entry, and it leaves the Tab order. true by default |
ib_animated | boolean | true | The chart arrives animated: the shapes rise from the axis — the whole chart when it goes from empty to drawn and when a series is added. New values slide to their place, and a shape a live chart pushes (of_append_values) rises alone: a dashboard that refreshes itself can keep the animation. A workstation set to reduce motion does not animate, unless the application insists (PBT_SetAnimationPolicy, section 4.8) |
ii_anim_duration | integer | 450 | Duration of that arrival, in milliseconds (0 to 5000) |
is_anim_easing | string | ease-out | Curve of the arrival (EASING_* constants): linear, ease-out, back-out which overshoots and comes back, bounce-out which bounces, elastic-out which snaps. This is what gives an animation its character |
ii_anim_delay | integer | 0 | Delay between two series on arrival, in milliseconds (0 to 1000). They then come in one after another instead of appearing together, which gives the chart its reading order. 0 = all at once |
is_format | string | "" | The format of every number the chart writes — value axes, data labels and value panel — in the syntax of a DataWindow format: #,##0.00, $#,##0, #,##0 "units", sections positive;negative;zero. The separators are those of the display language. An axis may carry its own (of_axis(AXIS_VALUE2).is_format), which wins over this one. Empty (or a format that is not a numeric one) = the number as it is, to the thousandth |
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change |
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change |
il_theme_accent | long | -1 | Accent colour of this component (-1 = the theme's accent) |
is_tooltip | string | "" | Plain tooltip shown when hovering the component |
is_super_tooltip_title | string | "" | Title of the rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Text of the rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the rich tooltip |
Methods #
| Method | Role | |
|---|---|---|
of_set_categories ( string as_labels[] ) | The labels of the category axis — text: a markup tag in them is dropped, so the axis, the panel and #x# say the same thing. Call it before the series. Returns 0 once applied, -2 when the component is not created | |
of_set_value_labels ( string as_labels[] ) | Labels on the value axis. Empty — the normal case — that axis carries numbers. Filled, it carries bands like the category axis: the two-categorical frame a heat map is drawn in. Returns 0 once applied, -2 when the component is not created | |
of_get_value_labels ( ref string as_labels[] ) | Fills as_labels[] with what the value axis carries right now and returns the count. Zero = it carries numbers; a label holding ` | ` reads back whole |
of_get_categories ( ref string as_labels[] ) | Fills as_labels[] with the categories the chart carries right now — after of_append_categories dropped the oldest, after of_from_datastore read them — and returns their number | |
of_get_last_error ( ) | Why the last call was refused (a role of of_map the rows do not have, a NULL bound, a position outside a series…), or how many rows the last of_from_datastore skipped and why; else the last error of the DLL, as for every component | |
of_add_heat_series ( string as_key, string as_label, long al_x[], long al_y[], double ad_weight[] ) | A heat map: one cell per (category, value label) pair, coloured by its weight. al_x is the rank of the category and al_y the rank of the label, both from 1 — the ranks a PowerScript array is indexed by, which a double loop writes without arithmetic. Set both label lists first. A NULL weight is an empty cell: nothing is drawn, labelled or clickable there. Returns 0 once added, -5 when the key is empty, holds / or ` | , or is already held, -2` when the component is not created |
of_add_ohlc_series ( string as_key, string as_label, double ad_open[], double ad_high[], double ad_low[], double ad_close[] ) | An OHLC series: the range from low to high, a tick on the left for the open and one on the right for the close. Four numbers per point, and the axis is read against the high and the low — the other two are inside them by construction. The four arrays are truncated to the shortest. Returns 0 once added, -5 when the key is empty, holds / or ` | , or is already held, -2` when the component is not created |
of_add_candle_series ( string as_key, string as_label, double ad_open[], double ad_high[], double ad_low[], double ad_close[] ) | The same four numbers, drawn as candles: a wick from low to high and a filled body between the open and the close. A doji — open equal to close — keeps one pixel of body, so it stays a line the eye can find. Returns 0 once added, -5 when the key is empty, holds / or ` | , or is already held, -2` when the component is not created |
of_set_series_ohlc ( string as_key, double ad_open[], double ad_high[], double ad_low[], double ad_close[] ) | New quotes for a financial series already on the chart. What of_set_series_values is to a series of values. Returns 0 once applied, -5 when no series has this key or when it is not a financial series, -2 when the component is not created | |
of_get_series_ohlc ( string as_key, ref double ad_open[], ref double ad_high[], ref double ad_low[], ref double ad_close[] ) | Fills the four arrays with what the series carries right now and returns the number of points. A series that is not financial answers 0 | |
of_add_series ( string as_key, string as_label, string as_type, double ad_values[] { , long al_color } ) | Adds a series with its type — TYPE_BAR, TYPE_LINE, TYPE_AREA, TYPE_SCATTER or TYPE_STEPLINE; the overload also takes its colour (RGB()), otherwise the palette picks. A NULL value (SetNull) is a gap: nothing is drawn, labelled or clickable there, and a line is cut. A key already held is refused, never replaced: of_set_series_values and the of_item handle change a series that exists. Returns 0 once added, -5 when the type is not one of those five (a heat map and the financial series have their own method), or when the key is empty, holds / or ` | , or is already held, -2` when the component is not created |
of_set_series_values ( string as_key, double ad_values[] ) | New values for a series already drawn, everything else untouched. This is what a live dashboard calls: the series keeps its identity, so the shapes slide instead of jumping. A NULL value is a gap. Returns 0 once applied, -5 when no series has this key or when it carries points or quotes (of_set_series_points, of_set_series_ohlc replace those), -2 when the component is not created | |
of_set_point_color ( string as_key, long al_position, long al_color ) | The colour of one point — the month that passed its limit, in red. al_position counts from 1; -1 (or NULL) gives the point the colour of its series back. Bars, line markers and scatter points take it, and it slides with its point in a live chart. Returns 0 once applied, -5 when no series has this key, when the position is outside the series, or for a heat map or a financial series (their colours are their ramp and their direction), -2 when the component is not created | |
of_get_point_color ( string as_key, long al_position ) | Returns the colour (an RGB() long) that of_set_point_color — or a ROLE_COLOR column — gave the point at al_position, counted from 1, or -1 when it has none (it takes the colour of its series), and for an unknown key or position | |
of_append_values ( string as_key, double ad_values[], long al_max_points ) | A live chart: pushes new values at the end of a series and drops the oldest once it carries more than al_max_points (0 = no limit). Only the new values travel — the series is not sent again on every tick. Pair it with of_append_categories. The new shapes rise alone, the others slide. Push every series, with the same maximum as of_append_categories: a series left behind slides out of step with its categories. Returns 0 once applied, -5 when no series has this key or when it carries points or quotes, -2 when the component is not created | |
of_append_categories ( string as_labels[], long al_max_count ) | New categories at the end of the axis, the oldest dropped beyond al_max_count (0 = no limit): the labels of a live chart slide with its values. Push every series with of_append_values and the same maximum. Returns 0 once applied, -2 when the component is not created | |
of_add_point_series ( string as_key, string as_label, double ad_x[], double ad_y[] { , double ad_weight[] } ) | A series positioned by value on both axes: x says where along the category axis, y how high. That axis then stops being a category axis — it becomes a second value axis, with its own graduations. An overload takes a weight per point, which sizes the bubble. A NULL weight keeps the default size, outside the scale of the others. Do not mix such series with series of values on a chart of categories: the category labels give way to graduations. Returns 0 once added, -5 when the key is empty, holds / or ` | , or is already held, -2` when the component is not created |
of_set_series_points ( string as_key, double ad_x[], double ad_y[], double ad_weight[] ) | New points for a series that already carries some. What of_set_series_values is to a series of values. Returns 0 once applied, -5 when no series has this key or when it carries values or quotes, -2 when the component is not created | |
of_get_series_points ( string as_key, ref double ad_x[], ref double ad_y[], ref double ad_weight[] ) | Fills the three arrays with what the series carries right now and returns the number of points. A series of values answers nothing in ad_x: it has no x of its own | |
of_get_series_values ( string as_key, ref double ad_values[] ) | Fills ad_values[] with what the series carries right now and returns the count. A live read : it asks the chart, not the last push | |
of_remove_series ( string as_key ) | Removes one series; the others keep their colour — taken when they were added — and their visibility; its tooltip and item colours go with it. Its handle (of_item) is destroyed with it: a later of_item on the same key creates a fresh one. Returns 0 once removed, -5 when no series has this key, -2 when the component is not created | |
of_clear ( ) | Empties the chart — series and categories; the series handles go with them. The axes keep their settings and their sections. Returns 0 once cleared, -2 when the component is not created | |
of_from_datastore ( datastore ads ) | Feeds the chart from a DataStore (a DataWindow, a DataWindowChild: overloads), as the graph of a DataWindow does: a column of categories, a column of values and, when there is one, a column of series — a series per value found there, one series named after the value column without it. The rows sharing a category and a series are summed; the categories come in the order of the rows (sort the DataStore); a category without a row is a gap. A colour column colours its point. A column plays a role when it is named like it (category, series, value, color) or when of_map says so; regional numbers and dates are read right. Given again, the chart changes in place: a series keeps its type, colour and axis, a series added by hand is never touched; a new series is a bar. Returns 0 once loaded (rows whose series cannot be a key are skipped: of_get_last_error says how many), -5 when the DataStore is not valid or no column plays ROLE_CATEGORY or ROLE_VALUE (of_get_last_error says which), -2 when the component is not created | |
of_map ( string as_role, string as_column ) | Gives a column of the DataStore a role (ROLE_CATEGORY, ROLE_SERIES, ROLE_VALUE, ROLE_COLOR) when its name does not say it. Before of_from_datastore, or after: the rows are read again. An empty column gives the role back to the column named like it. Returns 0 once set, -5 when the role is not a ROLE_ constant or the column is not one of the last DataStore, -2 when the component is not created | |
of_reload ( ) | Reads the rows of the DataStore (or DataWindow) given to of_from_datastore again — after a Retrieve, an edit, a filter — and changes the chart in place: the shapes slide to their new values. Returns 0 once read, -5 when no DataStore was given or it is no longer valid, -2 when the component is not created | |
of_item ( string as_key ) | Returns a series handle, to change it later | |
of_axis ( string as_axis ) | Returns an axis handle (AXIS_CATEGORY, AXIS_VALUE, AXIS_VALUE2), to set it up afterwards. Any other role gives no handle (IsValid() is false) | |
of_add_axis_section ( string as_axis, string as_key, double ad_from, double ad_to, long al_color ) | A band across the plot, behind the data: "below 200 is bad". Drawn under the shapes, it never competes with them. On the category axis, ad_from and ad_to are positions counted from 1 (2 to 3 covers the second and the third category). A colour of -1 (or NULL) is a pale wash of the theme accent. Returns 0 once added, -5 when the axis is not one of AXIS_*, when a bound is NULL, or when the key is empty, holds / or ` | , or is already held on that axis, -2` when the component is not created |
of_add_axis_threshold ( string as_axis, string as_key, double ad_at, long al_color, integer ai_thickness ) | A line across the plot at one value — a target, a limit. Same registry as the bands, but drawn to be seen. A colour of -1 (or NULL) draws it in the theme accent. Returns 0 once added, -5 when the axis is not one of AXIS_*, when a bound is NULL, or when the key is empty, holds / or ` | , or is already held on that axis, -2` when the component is not created |
of_clear_axis_sections ( string as_axis ) | Removes every band and every threshold of one axis. Returns 0 once cleared, -5 when the axis is not one of AXIS_*, -2 when the component is not created | |
of_remove_axis_section ( string as_axis, string as_key ) | Removes one band or threshold of one axis: the others stay. Returns 0 once removed, -5 when the axis is not one of AXIS_* or holds no section with this key, -2 when the component is not created | |
of_reset ( ) | Empties the chart — series and axis handles included — and puts every property back to its default. Returns 0 once done, -2 when the component is not created |
Without a key (demo mode), the chart draws only its first 3 series, legend included. The others stay in the model —
of_count,of_get_series_valuesand their handles see them — and setting the key shows them without you sending anything again.
Events #
| Event | Fired when |
|---|---|
ue_point_clicked (string as_key, long al_index, double ad_value) | A bar, a point, a cell or a quote was clicked — or confirmed with Enter: the series key, the position of the point in the series, counted from 1, and its value — the point's own value whatever the shape of the series: the y of a scatter, the weight of a heat cell, the close of a quote. On the keyboard Left/Right walk the categories and Up/Down choose the series the panel underlines; a point series or a heat map, once chosen, is walked point by point. A gap has nothing to click; the point the keyboard is on is ringed, and said to a screen reader |
ue_point_rclicked (string as_key, long al_index, double ad_value, long al_x, long al_y) | A right click on a bar, a point, a cell or a quote — or the Menu key (Shift+F10) on the point the keyboard is on: the series key, the position from 1 and the value, as ue_point_clicked gives them. Open your menu there; al_x, al_y: where to open the menu, in screen pixels — the pointer, or the middle of the point's shape from the keyboard (Menu key, Shift+F10); a contextmenu opens there as they are (uo_menu.of_show(al_x, al_y)) |
ue_rclicked ( ) | A right click on the chart where no point is drawn — the axes, the empty plot, the legend. A right click on a point raises ue_point_rclicked instead, never both |
ue_series_toggled (string as_key, boolean ab_visible) | The user hid or restored a series with a click in the legend. What the chart displays is then no longer what the application sent. Setting ib_visible is a value, like ticking a check box: this event reports the user's gesture |
The animation is a way in, not a computation: the final geometry is written straight away, and only the arrival is played. A chart that is never displayed — born off screen, on a tab nobody opened — therefore shows the right bars, silently.
Item properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_label | string | "" | The name of the series, as the legend shows it |
is_type | string | bar | bar · line · area · scatter · stepline (TYPE_* constants). Changes the drawing of this series alone — that is what makes a combination chart. Only a type of the same family is taken: a series of values among bar, line, area, scatter and stepline, a financial series between ohlc and candle; any other is ignored and is_type reads back the type kept |
il_color | long | -1 | Colour of the series (RGB()). -1 while none is set: the palette picks, when the series is added, and the series keeps it: removing another series never recolours it. One point may take its own (of_set_point_color). The inherited item colours (il_accent, il_back_color, il_text_color and their hover twins) have no effect on a series: il_color decides |
ib_visible | boolean | true | false hides a series without removing it — the legend keeps the way back. Like a check box, it is a value you set: ue_series_toggled reports the user's click in the legend |
ib_secondary | boolean | false | Plots the series on the second axis. That is how a count and an amount live on the same chart |
ib_data_labels | boolean | false | Writes each point's value next to it. Off by default: on fifty points the labels cover the drawing they explain |
is_label_format | string | "" | What each label and each line of the panel says: #y# the value, #x# the category (the x of a point series, the column of a heat cell), #v# the row of a heat cell, #label# the name of the series, #open# #high# #low# #close# the quotes; the rest is written as it stands — "$#y#K". Empty = the value alone. A label written inside a stacked bar takes black or white, whichever its bar carries |
id_smoothness | double | 1 | Lines and areas only: how round the line is drawn, 0 = straight segments, 1 = fully curved, as LiveCharts draws it. A step line ignores it — it says the level HELD until the next category, and a curve would say it drifted. A curve can pass beyond its points; it is cut to the plot frame and never paints over the axis labels |
ib_fill | boolean | true | Lines and areas: the wash under the stroke, down to the axis, in the series' own colour. It is the removal that is the deliberate act — for a line laid over something else (columns, coloured axis bands) that the wash would hide |
il_fill_color | long | -1 | The colour of that wash. -1 = the colour of the line itself |
is_marker | string | "circle" | Lines, step lines and scatters: the SHAPE of the marker on each point (constants MARKER_*: none, circle, square, triangle, diamond). Not decoration — two lines that cross, printed in grey, are told apart by their markers and by nothing else |
ii_thickness | integer | 2 | Lines and areas: the thickness of the stroke, in pixels |
il_point_count | long | 0 | How many points this series carries — values, (x, y) pairs or quotes (read only). A long: a live series may keep more than 32,767 |
il_cold_color | long | -1 | Heat maps only: the COLD end of the ramp, the lightest reading. -1 = the component's own ramp, one blue, from very pale to deep |
il_mid_color | long | -1 | The MIDDLE stop. Three stops and not two: interpolating from one end to the other washes out the middle of the scale, which is where most readings sit. -1 = the component's own middle blue |
il_hot_color | long | -1 | The HOT end, the heaviest reading. It is the one the legend shows. -1 = the component's own deep blue |
il_up_color | long | -1 | Financial series only: the colour of a point that closes above its open. -1 = the component's own green |
il_down_color | long | -1 | And that of a point that closes below. Two colours because the direction is what such a chart is read for — one colour would hide it. -1 = the component's own red |
is_tooltip | string | "" | Its tooltip, written in the value panel, right under the row of the series — only when it is the series pointed at (its bar, point or line under the mouse, or the series chosen on the keyboard with Up / Down), never for the other series of the column, never as a second bubble. A column met where no shape is drawn points at no series. With ib_value_tooltip at false, the panel still opens for it, without the figures. A point series or a heat map shows it in the panel the keyboard opens on its point. Markup accepted |
is_super_tooltip_title | string | "" | The bold title of its tooltip, written in the panel under its row |
is_super_tooltip_text | string | "" | The text of its tooltip, in the panel. Markup accepted |
is_super_tooltip_image | string | "" | An image at the top of its tooltip, in the panel (bundle path, absolute path or resources.dll:name) |
Axis properties #
| Property | Type | Default | Role |
|---|---|---|---|
is_title | string | "" | Title written along the axis. Empty = no title, and no room reserved for one. The tooltip and the item colours an axis handle inherits (is_tooltip, is_super_tooltip_*, il_accent, il_back_color, il_text_color…) have no effect on an axis |
id_min | double | NULL | Imposed lower bound. It wins over the data and is not rounded: someone who writes 0 means 0. NULL (SetNull) imposes nothing: the axis follows its data again, and a free bound reads back NULL (IsNull), never 0. Free, a value axis takes zero in only when a bar or an area stands on it: quotes and lines are read on their own range |
id_max | double | NULL | Imposed upper bound, same rule. What goes past it is cut at the edge of the plot |
id_step | double | 0 | Distance between two grid lines, in values. 0 = a round step read from the range |
ii_label_rotation | integer | 0 | Rotation of this axis' labels, in degrees (-90 to 90) — category names or value graduations. Twelve month names only fit under a chart when they lean; when they still do not, the chart writes one in N, the first and the last always |
ib_separator | boolean | true | Its grid lines. A category axis rarely needs them, a value axis nearly always does |
ii_section_count | integer | 0 | How many bands and thresholds this axis carries (read only) |
ib_logarithmic | boolean | false | Value axes only: a logarithmic scale, graduated by decades (1, 10, 100…), each decade the same height — for figures that span several orders of magnitude. Zero and negative values have no place on it and are not drawn |
is_format | string | "" | The format of this axis — its graduations, and the labels and the panel of the series drawn on it — over the chart's is_format: an amount on one side, a count of orders on the other. Same syntax (#,##0, 0.0 "u"…). Empty = the chart's format |
Examples #
Setting the animation to suit the screen #
// A dashboard that refreshes every few seconds : no arrival animation
uo_chart.ib_animated = false
// Elsewhere, a slower arrival that is actually seen
uo_chart.ii_anim_duration = 1200
Opening the rows behind a point #
// Event ue_point_clicked of uo_chart : the series key, the position of the
// point (from 1) and its value - enough to open the rows behind it
// Local variables
string ls_month
// On a series of values, the position IS the rank of the category
ls_month = is_months[al_index]
wf_open_orders(/*series*/ as_key, /*month*/ ls_month, /*amount*/ ad_value)
A live dashboard #
// Timer event of the window : new values for the same series, so the bars
// SLIDE to their new height instead of replaying their arrival
// Local variables
double ld_sales[]
// Read the figures, then hand them to the series already on the chart
ld_sales = wf_read_sales()
uo_chart.of_set_series_values(/*key*/ "sales", /*values*/ ld_sales)
A live chart that slides #
// Timer event of the window, every second : ONE new reading. Only that value
// travels ; past sixty, the oldest leaves on both the axis and the series
// Local variables
string ls_time[]
double ld_cpu[]
// The time of the reading on the axis, the reading itself in the series
ls_time[1] = String(Now(), "hh:mm:ss")
ld_cpu[1] = wf_read_cpu()
uo_chart.of_append_categories(/*labels*/ ls_time, /*max_count*/ 60)
uo_chart.of_append_values(/*key*/ "cpu", /*values*/ ld_cpu, /*max_points*/ 60)
A missing reading, and the chart as a picture #
// March was not measured : a NULL value is a gap, the line is cut there
// Local variables
double ld_temp[] = {18.5, 19.2, 0, 21.4}
// The third reading is missing : NULL, not zero
SetNull(ld_temp[3])
uo_chart.of_add_series(/*key*/ "temp", /*label*/ "Temperature", /*type*/ u_pbt_chartcartesian.TYPE_LINE, /*values*/ ld_temp)
// The chart as it is on screen, title and legend included, to a PNG file
uo_chart.of_save_as_png(/*path*/ "C:\Reports\temperature.png")
A band and a target on the value axis #
// A pale red band below 200 and a target line at 600, behind the bars
uo_chart.of_add_axis_section(/*axis*/ u_pbt_chartcartesian.AXIS_VALUE, /*key*/ "low", /*from*/ 0, /*to*/ 200, /*color*/ RGB(/*red*/ 255, /*green*/ 220, /*blue*/ 220))
uo_chart.of_add_axis_threshold(/*axis*/ u_pbt_chartcartesian.AXIS_VALUE, /*key*/ "target", /*at*/ 600, /*color*/ RGB(/*red*/ 200, /*green*/ 70, /*blue*/ 70), /*thickness*/ 2)
// The value axis says what it measures
uo_chart.of_axis(/*axis*/ u_pbt_chartcartesian.AXIS_VALUE).is_title = "Sales ($K)"
A chart fed from a DataStore #
// The month on the category axis, one series per product category, the amounts
// of the rows summed by the chart - what the graph of a DataWindow does
// Local variables
datastore lds_sales
// Your DataStore and its Retrieve, sorted : the categories come in the order of the rows
lds_sales = create datastore
lds_sales.DataObject = "d_sales"
lds_sales.SetTransObject(SQLCA)
lds_sales.Retrieve()
lds_sales.SetSort("month A")
lds_sales.Sort()
// Which column plays which role, then ONE call reads every row
uo_chart.of_map(/*role*/ u_pbt_chartcartesian.ROLE_CATEGORY, /*column*/ "month")
uo_chart.of_map(/*role*/ u_pbt_chartcartesian.ROLE_SERIES, /*column*/ "category")
uo_chart.of_map(/*role*/ u_pbt_chartcartesian.ROLE_VALUE, /*column*/ "amount")
uo_chart.of_from_datastore(/*ads*/ lds_sales)
// Later, the rows changed (an edit, a new Retrieve) : read again IN PLACE, the
// bars slide and every series keeps what you set on it
lds_sales.Retrieve()
uo_chart.of_reload()
The colour of one point, a menu on another #
// May passed its limit : ONE bar of the series in red, the others keep their colour
uo_chart.of_set_point_color(/*key*/ "sales", /*position*/ 5, /*color*/ RGB(/*red*/ 200, /*green*/ 40, /*blue*/ 40))
// Event ue_point_rclicked of uo_chart : a menu about the point under the mouse
// Local variables
m_point lm_menu
// Remember which point the menu is about, then open it where the pointer is
is_menu_series = as_key
il_menu_position = al_index
lm_menu = create m_point
lm_menu.m_popup.PopMenu(w_main.PointerX(), w_main.PointerY())
destroy lm_menu
Good practice #
- Set the categories before the series. Their number says what a series must contain; the other way round cannot work.
- A second axis is justified, not endured. Two scales on one drawing mislead the eye: bring it out only when the units really differ.
- Turn the animation off on a refreshing dashboard. An arrival that restarts every five seconds never finishes, and tires instead of helping.
- Bars start at zero, and the component keeps to that: zero joins the axis as soon as a bar or an area stands on it. A truncated bar chart exaggerates every gap. Lines, scatters and quotes are read on their own range.
- The chart keeps its mathematical direction in a right-to-left application: categories from left to right, value axis on the left. Only the
START/ENDlegend follows the reading direction. - Stack to read a total, juxtapose to compare. These are not two styles, they are two different questions.
- Push every series in a live chart:
of_append_categories, thenof_append_valuesfor each one, with the same maximum — a series left behind slides under the next category. - A gap is not a zero. A NULL value is neither drawn, labelled nor clickable; a NULL weight leaves the cell of a heat map empty.
ue_point_clickedgives the rank: use it to open the exact list behind that point, not the search screen.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_count · of_keys_at · of_has | Walk what the component holds | 3.2 Items |
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |
is_accessible_name · is_accessible_description | The name and description a screen reader says | 3.4 Optional properties and events |
Two helpers are not inherited: of_icon and of_escape_markup live on n_pbt_utils. Declare one — n_pbt_utils lnv_utils, nothing to create — and call them on it.