# Copyright (c) 2025-2026 Gigasoft, Inc. All rights reserved. === ProEssentials Multi-Axis (knowledge rev 4.2) Architecture === Multi-axis charts display multiple Y axes on a single chart. Each axis gets its own scale, grid numbers, label, and color. Subsets are assigned to axes. *** CRITICAL RULE -- AXIS CAPACITY *** Each axis group (MultiAxesSubsets entry) supports AT MOST 1 left Y-axis and 1 right Y-axis. This is a hard constraint of the architecture. VISUAL COUNTING METHOD to determine MultiAxesSubsets: Look at each vertical region of the chart. Count the maximum number of Y-axes visible on ONE side (left or right). That count = minimum number of MultiAxesSubsets entries needed for that region. Then use OverlapMultiAxes to stack those axis groups into shared vertical space. Example: Bottom region shows 2 right-side Y-axes (Efficiency, Power). --> Need 2 separate MultiAxesSubsets entries (one subset each). --> OverlapMultiAxes groups them: OverlapMultiAxes[2] = 2. WRONG: MultiAxesSubsets = [1, 1, 2] with OverlapMultiAxes = [1, 1, 1] (puts 2 subsets in one axis group -- only 1 right Y available!) RIGHT: MultiAxesSubsets = [1, 1, 1, 1] with OverlapMultiAxes = [1, 1, 2] (each subset gets its own axis group -- 2 overlapped at bottom) SETUP STEPS: 1. Set total PeData.Subsets across all axes 2. Count Y-axes per side per region to determine axis group count 3. Set MultiAxesSubsets array -- one entry per axis group MultiAxesSubsets[0] = 1 --> first subset on axis 0 MultiAxesSubsets[1] = 1 --> next subset on axis 1 4. Set OverlapMultiAxes to group axes into shared vertical sections Number of entries = number of visual sections (NOT axis groups) Values = how many axis groups share each section 5. Set MultiAxesProportions -- SAME count as OverlapMultiAxes entries (NOT same count as MultiAxesSubsets). Must sum to 1.0. 6. Set MultiAxisStyle for layout: Query: pe_query.py enum "MultiAxisStyle" GroupAllAxes(0) = overlapping, SeparateAxes(1) = stacked with gaps 7. Configure each axis individually using WorkingAxis WORKINGAXIS MECHANISM: Set WorkingAxis = N, then set axis-dependent properties. Those property values apply ONLY to axis N. Then set WorkingAxis = N+1 and configure the next axis. This is how you set independent scales, colors, labels per axis. Example flow: chart.PeGrid.WorkingAxis = 0; chart.PeGrid.Configure.ManualScaleControlY = ManualScaleControl.MinMax; chart.PeGrid.Configure.ManualMinY = 0; chart.PeGrid.Configure.ManualMaxY = 100; chart.PeGrid.WorkingAxis = 1; chart.PeGrid.Configure.ManualScaleControlY = ManualScaleControl.MinMax; chart.PeGrid.Configure.ManualMinY = 0; chart.PeGrid.Configure.ManualMaxY = 5000; IMPORTANT: See pe-workingaxis-dependent-properties for the complete list of which properties are axis-dependent. IMPORTANT: Always reset WorkingAxis = 0 when done configuring axes. Leaving it set to a non-zero value can cause subsequent property sets to apply to the wrong axis unexpectedly. MULTI-AXIS VISUAL OPTIONS: Separators between axis sections: PeGrid.Option.MultiAxesSeparators = MultiAxesSeparators.Thin; Enum values: None, Thin, Thick (query to confirm). Draws a visible divider line between stacked axis regions. Interactive axis sizing: PeUserInterface.Allow.MultiAxesSizing = true; Lets the end user drag separators to resize axis proportions at runtime. ANNOTATIONS IN MULTI-AXIS CHARTS: Graph annotations are a flat global array but can be targeted to specific axis regions. Each annotation has: PeAnnotation.Graph.Axis[i] = axisIndex; // 0--15, matches WorkingAxis The Y coordinate is interpreted in that axis's scale and the annotation renders in that axis's vertical strip. Without setting .Axis[], all annotations default to axis 0. See pe-annotations for the complete multi-axis annotation pattern. OVERLAPPED AXES BEST PRACTICE: When using OverlapMultiAxes, synchronize PeColor.YAxis (the axis label and grid number color) with PeColor.SubsetColors[i] for each axis so the user can visually associate which Y-axis scale belongs to which data: chart.PeGrid.WorkingAxis = i; chart.PeColor.YAxis = myColors[i]; chart.PeColor.SubsetColors[i] = myColors[i]; EQUALLY SPACED GRIDLINES ACROSS AXES: When axes have different scales/heights, use ManualYAxisTicknLine per axis to control grid density so gridlines align visually across sections: chart.PeGrid.WorkingAxis = N; chart.PeGrid.Configure.ManualYAxisTicknLine = true; chart.PeGrid.Configure.ManualYAxisLine = 10.0; // grid line spacing chart.PeGrid.Configure.ManualYAxisTick = 2.0; // tick mark spacing ManualYAxisLine must be divisible by ManualYAxisTick. Same pattern for RY: ManualRYAxisTicknLine, ManualRYAxisLine, ManualRYAxisTick. RIGHT Y-AXIS (independent of multi-axis): Pego, Pesgo, AND Pepso all support a built-in Right Y-Axis via two methods: 1. RYAxisComparisonSubsets = N --> last N subsets plot against RY axis Uses MethodII for RY plotting style. See example 003. 2. PePlot.Methods[i] + OnRightAxis(1000) --> any subset on RY axis See pe-mixing-methods-xaxis for details and enum values. For simple dual-Y charts, use these directly -- no multi-axis needed. Both approaches are valid; Methods[] is often cleaner for complex charts. IMPORTANT: MultiAxesSubsets creates separate axis *sections* (stacked or overlapped) but does NOT assign subsets to the right Y-axis. To get a right Y-axis within a multi-axis layout, combine OverlapMultiAxes with RYAxisComparisonSubsets or Methods[]+1000 inside the axis group. YAXISONRIGHT: PeGrid.Option.YAxisOnRight = true flips ALL Y axes to the right side globally. When combined with RYAxisComparisonSubsets, the comparison subsets plot against the left Y instead (roles swap). LAYOUT OPTIONS: MultiAxisSeparatorSize controls the visual divider between axis sections. MultiAxisStyle controls overlapping vs. separated rendering. Use pe_query.py to look up exact enum values and property paths. BASE EXAMPLE INHERITANCE: Multi-axis examples often build upon a base "CreateSimple" example. When code says "builds upon CreateSimpleGraph '000'", refer to example 000 for all base configuration (data, labels, table, styling, etc.). Base examples by chart type: 000 (Pego), 100 (Pesgo), 200 (Pepso), 300 (Pepco), 400 (Pe3do). RECONFIGURING MULTI-AXIS LAYOUTS DYNAMICALLY: MultiAxesSubsets, OverlapMultiAxes, and MultiAxesProportions are all empty by default. If you switch between layouts at runtime, old array values persist until explicitly cleared. Always Clear() before rebuilding: chart.PeGrid.MultiAxesSubsets.Clear(); chart.PeGrid.OverlapMultiAxes.Clear(); chart.PeGrid.MultiAxesProportions.Clear(); Then re-populate only the entries the new layout requires. Do NOT zero elements individually -- .Clear() empties the array completely. KEY: Query pe_query.py for all property paths before coding. pe_query.py props "MultiAxesSubsets,MultiAxisStyle,WorkingAxis" pe_query.py search "multi axis"