Skip to main content
Every visual aspect of a FioriCharts chart is configurable through properties on ChartModel and a set of attributes classes. Because ChartModel is an ObservableObject, you can mutate these properties after the chart is displayed and the view updates automatically.

Series colors

ChartSeriesAttributes

ChartSeriesAttributes controls the line width, point appearance, and color palette for a single series. Pass an array to ChartModel.seriesAttributes — one element per series.
let series0 = ChartSeriesAttributes(
    palette: ChartSeriesPalette(colors: [.blue]),
    lineWidth: 2,
    point: ChartPointAttributes(isHidden: false, diameter: 8, strokeColor: .blue)
)

let series1 = ChartSeriesAttributes(
    palette: ChartSeriesPalette(colors: [.orange]),
    lineWidth: 2,
    point: ChartPointAttributes(isHidden: true)
)

let model = ChartModel(
    chartType: .line,
    data: [
        [200, 170, 165, 143, 166, 112, 110],
        [150, 120, 130, 135, 120, 138, 137]
    ],
    titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]],
    seriesAttributes: [series0, series1]
)

ChartSeriesAttributes properties

PropertyTypeDefaultDescription
paletteChartSeriesPaletteSystem colorColor palette for the series
lineWidthCGFloat1Stroke width for lines (0–100)
pointChartPointAttributesDefault pointPoint appearance
firstLineCapDiameterCGFloat0Diameter of the cap at the first data point
lastLineCapDiameterCGFloat0Diameter of the cap at the last data point

ChartSeriesPalette

ChartSeriesPalette defines the colors used to render a series.
// Single solid color
let palette = ChartSeriesPalette(colors: [.systemBlue])

// Fill color distinct from the line color
let palette = ChartSeriesPalette(colors: [.blue], fillColor: .blue.opacity(0.2))

// With explicit label, positive, and negative colors
let palette = ChartSeriesPalette(
    colors: [.blue],
    fillColor: nil,
    labelColor: .blue,
    positiveMaxColor: .green,
    positiveMinColor: .green.opacity(0.6),
    negativeMaxColor: .red.opacity(0.6),
    negativeMinColor: .red
)
PropertyDescription
colorsPrimary color(s) for the series line. Stock charts can use multiple colors.
fillColorColor for filled areas (area charts). Defaults to colors.first.
labelColorColor for data point labels.
positiveMaxColorColor for the maximum positive value marker.
positiveMinColorColor for the minimum positive value marker.
negativeMaxColorColor for the maximum negative value marker.
negativeMinColorColor for the minimum negative value marker.

Per-category color overrides

To color individual bars or segments, use colorsForCategory on ChartModel.
let model = ChartModel(
    chartType: .column,
    data: [[120, 90, 75, 140, 110]],
    titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May"]],
    colorsForCategory: [
        0: [2: .red]  // series 0, category index 2 is red
    ]
)

Shape-style gradients

Apply gradients or image fills to entire series or individual categories using view modifiers.
let gradient = LinearGradient(
    colors: [.red, .green, .blue],
    startPoint: .bottom,
    endPoint: .top
)

ChartView(model)
    .chartSeriesShapeStyle([1: AnyShapeStyle(gradient)])
    .frame(width: 360, height: 220)
For per-category styling:
ChartView(model)
    .chartCategoryShapeStyle([
        0: [
            0: AnyShapeStyle(LinearGradient(colors: [.red, .orange], startPoint: .bottom, endPoint: .top)),
            1: AnyShapeStyle(Color.yellow)
        ]
    ])
    .frame(width: 360, height: 220)

Data points

ChartPointAttributes controls the appearance of the dots drawn at each data value.
let pointAttrs = ChartPointAttributes(
    isHidden: false,
    diameter: 8,
    strokeColor: .blue,
    gap: 4
)

let seriesAttrs = ChartSeriesAttributes(
    palette: ChartSeriesPalette(colors: [.blue]),
    lineWidth: 2,
    point: pointAttrs
)
PropertyTypeDefaultDescription
isHiddenBoolfalseHides or shows the point
diameterCGFloat7Point diameter in points (0–100)
strokeColorColor.secondaryLabelOutline color of the point
gapCGFloat2Minimum gap between adjacent points before they are hidden (0–100)

Axes

Axis hierarchy

ChartAxisAttributes          (base)
  └── ChartNumericAxisAttributes   (adds: isZeroBased, explicitMin/Max, formatter …)
        └── ChartCategoryAxisAttributes  (adds: labelLayoutStyle)
All axis attributes classes share a common set of sub-objects:
PropertyTypeDescription
baselineChartBaselineAttributesThe zero-line at the base of the chart
gridlinesChartGridlineAttributesHorizontal or vertical grid rules
labelsChartLabelAttributesTick-mark labels along the axis
titleLabelChartLabelAttributesAppearance of the axis title text
titleString?Axis title string

Configuring the numeric axis

let numericAxis = ChartNumericAxisAttributes()
numericAxis.isZeroBased = true          // baseline starts at 0
numericAxis.explicitMin = -50           // override calculated minimum
numericAxis.explicitMax = 300           // override calculated maximum
numericAxis.abbreviatesLabels = true    // "1.23k" instead of "1,234"
numericAxis.isMagnitudedDisplayed = true
numericAxis.gridlines.isHidden = false
numericAxis.gridlines.color = .gray.opacity(0.3)
numericAxis.gridlines.width = 1
numericAxis.labels.isHidden = false
numericAxis.labels.fontSize = 11
numericAxis.title = "Revenue (USD)"

let model = ChartModel(
    chartType: .column,
    data: [[200, 170, 165, 143, 166]],
    titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May"]],
    numericAxis: numericAxis
)

ChartNumericAxisAttributes key properties

PropertyTypeDefaultDescription
isZeroBasedBooltrueStarts the axis at zero when all values are positive or all negative
explicitMinCGFloat?nilOverrides the calculated axis minimum
explicitMaxCGFloat?nilOverrides the calculated axis maximum
abbreviatesLabelsBoolfalseAbbreviates large values (e.g. “1.2k”)
isMagnitudedDisplayedBooltrueIncludes the magnitude suffix (“k”, “M”) in abbreviated labels
formatterNumberFormatterDecimal, 2 dpFormatter applied to axis labels

Configuring the category axis

ChartCategoryAxisAttributes extends ChartNumericAxisAttributes with a labelLayoutStyle property.
let catAxis = ChartCategoryAxisAttributes()
catAxis.labelLayoutStyle = .allOrNothing  // show all labels or none
// or
catAxis.labelLayoutStyle = .range         // show only first and last label
catAxis.labels.isHidden = false
catAxis.labels.fontSize = 10
catAxis.gridlines.isHidden = true

let model = ChartModel(
    chartType: .line,
    data: [[200, 170, 165, 143]],
    titlesForCategory: [["Jan", "Feb", "Mar", "Apr"]],
    categoryAxis: catAxis
)

Showing and hiding gridlines

// Hide all gridlines
model.numericAxis.gridlines.isHidden = true

// Show dashed gridlines
model.numericAxis.gridlines.isHidden = false
model.numericAxis.gridlines.dashPatternLength = 4
model.numericAxis.gridlines.dashPatternGap = 4
model.numericAxis.gridlines.color = .gray.opacity(0.4)
model.numericAxis.gridlines.width = 1

Labels

ChartLabelAttributes controls the appearance of text on both axis labels and axis titles.
let labelAttrs = ChartLabelAttributes(
    color: .secondaryLabel,
    fontSize: 11,
    offset: 0,
    isHidden: false
)

// Or with an explicit SwiftUI Font:
let labelAttrs = ChartLabelAttributes(
    color: .primary,
    font: .system(size: 11, weight: .medium)
)
PropertyTypeDefaultDescription
colorColor.tertiaryLabelLabel text color
fontSizeCGFloat12Font size in points when font is not set (0–100)
fontFont?nilExplicit SwiftUI font; takes priority over fontSize
offsetCGFloat0Distance from the axis in points (–10 to 10)
isHiddenBoolfalseHides or shows the label
backgroundColorColor?nilBackground fill behind the label

Gridlines and baseline

ChartGridlineAttributes and its subclass ChartBaselineAttributes share the same dash-pattern-based line styling.
let gridline = ChartGridlineAttributes(
    width: 1,
    color: .gray.opacity(0.3),
    dashPatternLength: 4,
    dashPatternGap: 4,
    isHidden: false
)

model.numericAxis.gridlines = gridline
PropertyTypeDefaultDescription
widthCGFloat1Line width in points (0–20)
colorColor.secondaryFillLine color
dashPatternLengthCGFloat1Length of each dash segment (0–20)
dashPatternGapCGFloat0 for baseline, 3 for gridlinesGap between dash segments (0–20)
isHiddenBoolfalseHides or shows the line
ChartBaselineAttributes adds two read-only properties, value and position, that indicate the computed baseline value and its position in the chart’s coordinate space.

Custom axis label formatting

Use numericAxisLabelFormatHandler for full control over axis label strings.
let model = ChartModel(
    chartType: .line,
    data: [[1200, 3400, 2800, 4500]],
    titlesForCategory: [["Q1", "Q2", "Q3", "Q4"]],
    numericAxisLabelFormatHandler: { value, axisId in
        guard axisId == .y else { return nil }
        return "$\(Int(value / 1000))k"
    }
)
Return nil from the handler to fall back to the default formatter.

Number of gridlines

// Set at init
let model = ChartModel(
    chartType: .column,
    data: [[100, 200, 150]],
    numberOfGridlines: 5  // constrained to 2–20
)

// Change after init
model.numberOfGridlines = 4

Selection behavior

Selection mode

// Select one value in the active series and category
model.selectionMode = .single

// Select one value per series for the tapped category
model.selectionMode = .all

// Donut-only: allows multiple independent selections
// (set automatically for .donut charts)
model.selectionMode = .multiple

Programmatic selection

// Select category indices 0–6 in series 0
model.selections = [0: [0, 1, 2, 3, 4, 5, 6]]

// Select category 0 in both series
model.selections = [0: [0], 1: [0]]

// Clear the selection
model.selections = nil

Require a selection

Set selectionRequired = true to disallow the empty-selection state:
model.selectionRequired = true

Zoom and pan

// Enable all user interaction (pan + zoom)
model.userInteractionEnabled = true
model.scaleXEnabled = true
model.scaleYEnabled = true

// Snap to nearest data point while dragging
model.snapToPoint = true

// Set a programmatic zoom level
model.scaleX = 2.0  // range: 1.0–1024
model.scaleY = 1.5

// Center the viewport on a specific relative position
model.centerPosition = CGPoint(x: 0.5, y: 0.5)
Disable userInteractionEnabled when embedding a chart in a List row or an iOS Widget to prevent gesture conflicts.

Secondary value axis

Assign one or more series to a secondary Y axis on .line, .area, and .combo charts:
let model = ChartModel(
    chartType: .line,
    data: [
        [200, 170, 165, 143, 166, 112, 110],  // primary axis
        [1.2, 0.8, 1.5, 0.9, 1.1, 1.4, 0.7]  // secondary axis
    ],
    titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]],
    indexesOfSecondaryValueAxis: [1]
)

// Style the secondary axis independently
model.secondaryNumericAxis.labels.color = .orange
model.secondaryNumericAxis.title = "Ratio"

Build docs developers (and LLMs) love