StackableChartLayer (class)
public abstract StackableChartLayer {inherits ChartLayer}
Package: CURL.GUI.CHARTS
Direct Known Subclasses: AreaLayer, LineLayer, BarLayer, BaseScatterLayer

An abstract ChartLayer subclass that defines some of the functionality required to implement stacked plots.

Description

This class is a superclass of every ChartLayer subclass that supports ChartStackingMode. You should never need to interact with this class directly.

Constructors
default:Initialize a new StackableChartLayer.
constructor protected {StackableChartLayer.default
    x-axis-data:#ChartDataSeries = null,
    stacking-mode:ChartStackingMode = ChartStackingMode.none,
    ...
}
Properties
generate-y-axes?:Determine whether or not to consider generating Y axes for this ChartLayer.
accessor public StackableChartLayer.generate-y-axes?:bool
stacking-mode:The ChartStackingMode for this ChartLayer.
accessor public StackableChartLayer.stacking-mode:ChartStackingMode
setter public StackableChartLayer.stacking-mode:ChartStackingMode
Properties inherited from ChartLayer: chart, color-associations, legend-enabled?, legend-entry-factory, style-element, x-axis-data, y-axis-data
Properties inherited from Shape: as-Shape, border-color, color, draw-operation, option-parent, selection-context, shape-parent, shape-selectable, stroke-thickness, transformation, visible?
Properties inherited from ShapeContainerBase: as-ShapeRoot, shape-children
Properties inherited from Visual: _style-element, clonable-class?, completely-clonable-children?, cursor, data-source, display-context, dragee, font-size, input-method-enabled?, input-method-keyboard-mode, name, options, options-present-here, style-class, style-manager, style-options, test-description, test-name, test-parent?, test-type-name, test-visible?, tooltip, user-data
Properties inherited from DataBindingTarget: data-binding-context, data-bindings
Properties inherited from EventTarget: event-handlers
Properties inherited from OptionListInterface: option-register-proc, registered-option-keys
Methods
append-data-series:Add a ChartDataSeries to ChartLayer.y-axis-data to be plotted.
public {StackableChartLayer.append-data-series
    data:ChartDataSeries
}:void
compute-data-min-max:Determine the minimum and maximum values associated with data.
public {StackableChartLayer.compute-data-min-max
    data:ChartDataSeries
}:(min:any, max:any)
get-data-mapping:Get a ChartDataMapping object corresponding to one of the ChartDataSeries of this ChartLayer.
public {StackableChartLayer.get-data-mapping
    y-data:ChartDataSeries
}:ChartDataMapping
get-inverse-data-mapping:Get a ChartInverseDataMapping object corresponding to one of the ChartDataSeries of this ChartLayer.
public final {StackableChartLayer.get-inverse-data-mapping
    y-data:ChartDataSeries,
    error-if-no-axes?:bool = true
}:#ChartInverseDataMapping
Methods inherited from ChartLayer: append-color-association, create-legend-entries, detach, draw, get-data-series-from-shape, get-data-series-visibility, get-fill-pattern-for-data-series, get-nearest-record-in-data, get-own-bounds, get-record-at-point, get-record-count, handle-observer-message, maybe-create-x-axis, maybe-create-y-axis-for-series, non-keyword-init-arg, note-color-associations-changed, note-y-axis-data-array-changed, remove-color-association, remove-data-series, self-contains-point?, self-intersects-polygon?, set-data-series-visibility, update-layout
Methods inherited from Shape: apply-rotation, apply-scale, apply-transformation, apply-translation, apply-translation-in-parent, constrain-own-layout-bounds, constrain-shape-layout-bounds, contains-point?, find-graphical-ancestor, fire-crossing-event, fire-in-child, get-display-context, get-down-orientation-in-shape-parent, get-graphical-root, get-local-device-pixel-size, get-origin-in-graphical-ancestor, get-origin-in-root, get-origin-in-shape-parent, get-origin-in-shape-root, get-own-bounds-in-shape-root, get-own-layout-bounds, get-right-orientation-in-shape-parent, get-shape-bounds, get-shape-bounds-in-shape-root, get-shape-layout-bounds, get-top-left-in-ancestor, get-transformation-to-shape-root, keyword-init-arg, option-change-notify, overdraw-for-selection, quantize-line-thickness, request-draw, request-draw-self, reset-transformation, set-rotation, set-scale, set-transformation, set-translation-in-parent, to-Graphic, transform-from-display-coordinates, transform-from-graphical-root-coordinates, transform-point-from-shape-root, transform-point-to-shape-root, transform-to-display-coordinates, transform-to-graphical-root-coordinates, transform-vector-from-shape-root, transform-vector-to-shape-root, transformation-changed, transformation-changing
Methods inherited from Observer: observe, stop-observing
Methods inherited from ShapeContainerBase: add, clear, draw-shape-child, draw-shape-children, get-all-children-at-point, get-child-at-point, get-leaf-at-point, get-shape-root, note-attached, note-detaching, notify-option-children, on-drag-enter, on-pointer-enter, on-pointer-envelope-event, register-options, remove, set-shape-index, set-shape-index-after, set-shape-index-before, shape-container-fire-inferior-crossing-event, shape-container-handle-crossing, shape-container-pick-child, shape-container-pointer-enter-occurred, shape-container-pointer-leave-occurred
Methods inherited from Visual: add-from-init-args, add-option, add-style-option, animate, change-cursor, clonable-appearance?, clone-appearance, clone-appearance-helper, find-test-children, get-focus-manager, get-layout-context, get-test-parent, get-test-property, get-text, get-view, maybe-fire-attach-event, maybe-fire-detach-event, note-caret-position, on-drag-leave, on-pointer-leave, pop-cursor, prepare-test-object, prepare-test-parent, push-cursor, quantize-width, release-key-focus, remove-option, remove-style-option, request-key-focus, scroll-to-include, test-record, test-run, xy-offset-to
Methods inherited from GraphicOptions: any-to-Distance
Methods inherited from GuiEventTarget: handle-event, on-action, on-cancel-mode, on-command-changed, on-commit, on-composition-change-event, on-composition-result-event, on-context-menu-event, on-current-record-change-request, on-current-record-changed, on-destroy-notify, on-destroy-requested, on-drag-over, on-drag-pointer, on-drag-started, on-drop, on-end-composition-event, on-focus-event, on-focus-in, on-focus-out, on-grab-release, on-gui-event, on-input-method-event, on-inspection, on-key-event, on-key-press, on-pointer-button, on-pointer-crossing, on-pointer-event, on-pointer-motion, on-pointer-press, on-pointer-release, on-pointer-scroll, on-raw-key-event, on-raw-key-press, on-raw-key-release, on-reset, on-selectable-added, on-selectable-removed, on-selection-changed, on-selection-context-activated, on-selection-context-deactivated, on-selection-event, on-start-composition-event, on-start-event, on-stop-event, on-view-activate, on-view-deactivate, on-window-close, remove-event-handlers-for-event-class
Methods inherited from DataBindingTarget: add-data-binding, get-data-binding, refresh-data-binding, remove-data-binding, unset-property, update-data-binding, validate-data-binding
Methods inherited from EventTarget: accepts-event-class?, add-event-handler, event-handler-present?, remove-event-handler, verify-event
Methods inherited from OptionListInterface: change-option-parent-notify, clone-options, get-option, get-option-by-name, local-add-notify, local-remove-notify, name-to-option-key, new-option-item, option-changed, option-lookup, option-lookup-here, option-propagate-notify, option-set?, propagate-option-change, remove-styles, set-option-by-name, set-style-option-by-name, unset-option-by-name, unset-style-option-by-name
Methods inherited from BasicEventTarget: enqueue-event
Methods inherited from InitRestArgParser: process-rest-args
Methods inherited from Object: object-describe, object-describe-for-debugging, object-serialize

Constructor Details
default (constructor)
protected {StackableChartLayer.default
    x-axis-data:#ChartDataSeries = null,
    stacking-mode:ChartStackingMode = ChartStackingMode.none,
    ...
}

Initialize a new StackableChartLayer.

x-axis-data: See ChartLayer.default.
stacking-mode: The initial ChartStackingMode of this chart. Note that stacking modes other than ChartStackingMode.none impose restrictions on the type of data accepted. See StackableChartLayer.stacking-mode for more information.
...: See ChartLayer.default.


Property Details
generate-y-axes? (accessor)
accessor public StackableChartLayer.generate-y-axes?:bool

Determine whether or not to consider generating Y axes for this ChartLayer.

Description

This method is called internally by the automatic axis generation process. By default, it returns true, but some layers override it. For example, in layers that support stacking (for instance, see LineLayer.stacking-mode), when the stacking mode is ChartStackingMode.percent, there is no need for a Y axis for that layer because the plot does not depend on an axis for Y positions at all.


stacking-mode (accessor)
accessor public StackableChartLayer.stacking-mode:ChartStackingMode
setter public StackableChartLayer.stacking-mode:ChartStackingMode

The ChartStackingMode for this ChartLayer.

Description

This property defines how members of StackableChartLayer.y-axis-data are interpreted relative to one another, in the following way:

Notes

For any value other than StackableChartLayer.none, the data contained in this ChartLayer must conform to a few restrictions. All elements of StackableChartLayer.y-axis-data must use the same Domain. (That is, ChartDataSeries.field.domain must be the same.) This implies that they will all have the same data type. Also, that data type must be a numeric type. This includes types such as int, double, and types with units such as Time or Distance as well.

If the data does not conform to these restrictions, an error will be thrown whenever the data changes or the stacking mode changes.

When this property is set to StackableChartLayer.percent, the resulting plots are independent of any Y axis because they are based upon percentage. StackableChartLayer overrides ChartLayer.generate-y-axes? to inhibit Y axis creation in this situation.

Example


Example: Changing StackableChartLayer.stacking-mode
{import * from CURL.GUI.CHARTS}
{import * from CHARTS-DOC,
    location = "../docstring-support/gui/charts-doc.scurl"
}

{let chart:LayeredChart =
    {LayeredChart
        width = 17cm,
        height = 10cm,
        left-axis-parent =
            {ShapeGroup
                axis-label = "Sales",
                tick-label-factory =
                    {proc {axis:ChartAxis, tick:ChartTick, tick-rotation:Angle}:any
                        let constant val:double = tick.value asa double
                        {return
                            {if val >= 1e9 then
                                {format "%gB", val / 1e9}
                             elseif val >= 1e6 then
                                {format "%gM", val / 1e6}
                             else
                                {format "%g", val}
                            }
                        }
                    }
            },
        {BarLayer
            sample-sales-records,
            "north-america-sales",
            "europe-sales",
            "asia-sales",
            "service-revenue",
            x-axis-data = {ChartDataSeries sample-sales-records, "period"}
        }
    }
}

{value chart}

{RadioFrame
    {HBox
        spacing = 4pt,
        {RadioButton radio-value = ChartStackingMode.none, value = true},
        {RadioButton radio-value = ChartStackingMode.stacked},
        {RadioButton radio-value = ChartStackingMode.percent}
    },
    {on ValueFinished at rf:RadioFrame do
        let constant layer:BarLayer = chart.layers[0] asa BarLayer
        set layer.stacking-mode = rf.value asa ChartStackingMode
    }
}


Method Details
append-data-series (method)
public {StackableChartLayer.append-data-series
    data:ChartDataSeries
}:void

Add a ChartDataSeries to ChartLayer.y-axis-data to be plotted.

data: The ChartDataSeries to be added.

Description

See ChartLayer.y-axis-data for more information.


compute-data-min-max (method)
public {StackableChartLayer.compute-data-min-max
    data:ChartDataSeries
}:(min:any, max:any)

Determine the minimum and maximum values associated with data.

data: The ChartDataSeries to examine. This must be a member of ChartLayer.y-axis-data.

Returns

The minimum and maximum values. Note that these values will both be null if no non-null values are present in the data. Otherwise, neither will be null.

Description

This method ordinarily is implemented to simply call ChartDataSeries.compute-min-max. However, it may extend the computation to take plotting into account. For example, when dealing with a stacked line chart, the actual stacked data values will be taken into account. This is the reason for calling this method, rather than ChartDataSeries.compute-min-max.


get-data-mapping (method)
public {StackableChartLayer.get-data-mapping
    y-data:ChartDataSeries
}:ChartDataMapping

Get a ChartDataMapping object corresponding to one of the ChartDataSeries of this ChartLayer.

y-data: The ChartDataSeries for which the mapping is valid. This object must be a member of ChartLayer.y-axis-data.

Returns

A ChartDataMapping object for this layer and the specified data series.

Description

ChartDataMapping allows you to easily determine the spatial location of a given record using ChartDataMapping.get-position. It is commonly used by ChartLayer implementations when positioning Shape objects as part of their plots.

Note that the position returned is in coordinates relative to the plot area. In the example below, the coordinates are used as-is to add Shapes to the ChartLayer itself. This works because all ChartLayers have the plot area's origin as their own origin.

If you wanted the coordinates relative to the Chart, you could use LayeredChart.plot-area.transformation.transform to accomplish this.

See also ChartLayer.get-inverse-data-mapping.

Notes

This method will cause some amount of chart layout to occur immediately, if layout is pending. It will always result in a call to LayeredChart.ensure-axes-valid, since a data mapping cannot be determined without valid axes.

Note that any subsequent operations that change the axes in the chart or the data series in this layer (including such operations as changing the stacking mode) will invalidate the ChartDataMapping object. Using the object will produce meaningless results. It is best not to retain these objects, but rather to obtain them using this method whenever they are needed.

Example


Example: Using ChartDataMapping to add Shapes to a chart
{import * from CURL.GUI.CHARTS}
{import * from CHARTS-DOC,
    location = "../docstring-support/gui/charts-doc.scurl"
}

{let chart:LayeredChart =
    {LayeredChart
        width = 15cm,
        height = 6cm,
        {BarLayer
            sample-records,
            "Age",
            x-axis-data = {ChartDataSeries sample-records, "Name"}
        },
        {LineLayer
            sample-records,
            "Wins"
        },
        {on ChartLayoutChanged do
            || Give big winners a gold diamond
            let constant layer:ChartLayer = chart.layers[1]
            let constant map:ChartDataMapping =
                {layer.get-data-mapping layer.y-axis-data[0]}


            let index:int = 0
            {for record in sample-records do
                {if record["Wins"] asa int >= 6 then
                    let constant (pos:Distance2d, y-was-null?:bool) =
                        {map.get-position record, index}
                    
                    {if not y-was-null? then
                        || Don't add shapes for records with null values.
                        let constant size:Distance =
                            3 * {sqrt 2} * {layer.get-display-context}.pixel-size
                        {layer.add
                            {RectangleShape
                                {GRect size, size, size, size},
                                translation = pos,
                                rotation = 45deg,
                                color = "gold",
                                tooltip =
                                    {Tooltip
                                        {format
                                            "%s got %d wins!",
                                            record["Name"],
                                            record["Wins"]
                                        }
                                    }
                            }
                        }
                    }
                }
                
                {inc index}
            }
        }
    }
}

{value chart}


get-inverse-data-mapping (method)
public final {StackableChartLayer.get-inverse-data-mapping
    y-data:ChartDataSeries,
    error-if-no-axes?:bool = true
}:#ChartInverseDataMapping

Get a ChartInverseDataMapping object corresponding to one of the ChartDataSeries of this ChartLayer.

y-data: The ChartDataSeries for which the mapping is valid. This object must be a member of ChartLayer.y-axis-data.
error-if-no-axes?: If no axes can be found that match y-data (see LayeredChart.get-best-match-x-axis and LayeredChart.get-best-match-y-axis), then no ChartInverseDataMapping object can be created.

When this happens, if error-if-no-axes? is true, then an error is thrown. If error-if-no-axes? is false, then null will be returned instead.

Returns

A ChartInverseDataMapping object for this layer and the specified data series, if one can be created. null will only be returned if no axes match y-data and error-if-no-axes? is false.

Description

ChartInverseDataMapping allows you to easily determine the X and Y values that correspond to a given spatial location. For example, this might be used to add data to or change data in a RecordSet in response to user input.

ChartInverseDataMapping.get-values expects coordinates in the coordinate space of the LayeredChart, such as you would be given if you attached an event handler to the chart itself, as the example below does.

See also ChartLayer.get-data-mapping.

Notes

This method will cause some amount of chart layout to occur immediately, if layout is pending. It will always result in a call to LayeredChart.ensure-axes-valid, since a data mapping cannot be determined without valid axes.

Note that any subsequent operations that change the axes in the chart or the data series in this layer (including such operations as changing the stacking mode) will invalidate the ChartInverseDataMapping object. Using the object will produce meaningless results. It is best not to retain these objects, but rather to obtain them using this method whenever they are needed.

Note also that not all configurations of charts can produce a complete inverse mapping. Any chart that uses stacking (either ChartStackingMode.stacked or ChartStackingMode.percent) will return an X-axis-only ChartInverseDataMapping. In this case, the Y value will be null.

Example


Example: Using ChartInverseDataMapping
{import * from CURL.GUI.CHARTS}
{import * from CHARTS-DOC,
    location = "../docstring-support/gui/charts-doc.scurl"
}

{let bar-display:TextDisplay = {TextDisplay width = 4cm}}
{let line-display:TextDisplay = {TextDisplay width = 4cm}}

{let chart:LayeredChart =
    {LayeredChart
        width = 15cm,
        height = 6cm,
        {BarLayer
            sample-records,
            "Age",
            x-axis-data = {ChartDataSeries sample-records, "Name"}
        },
        {LineLayer
            sample-records,
            "Wins"
        },
        {on e:PointerMotion do
            let layer:ChartLayer = chart.layers[0]
            let inverse-mapping:ChartInverseDataMapping =
                {non-null {layer.get-inverse-data-mapping layer.y-axis-data[0]}}
            let (x:any, y:any) = {inverse-mapping.get-values e.x, e.y}
            set bar-display.value = x & ", " & y

            set layer = chart.layers[1]
            set inverse-mapping =
                {non-null {layer.get-inverse-data-mapping layer.y-axis-data[0]}}
            set (x, y) = {inverse-mapping.get-values e.x, e.y}
            set line-display.value = x & ", " & y
        }
    }
}

{Table
    cell-border-width = 1pt,
    cell-border-color = FillPattern.silver,
    {row-prototype
        font-weight = FontWeight.bold,
        {text BarLayer (Age)},
        {text LineLayer (Wins)}
    },
    {row-prototype bar-display, line-display},
    {row-prototype
        {cell-prototype
            colspan = 2,
            chart
        }
    }
}