# Copyright (c) 2025-2026 Gigasoft, Inc. All rights reserved. === ProEssentials Graph Annotations (knowledge rev 4.2) (Pego, Pesgo, Pepso, Pe3do) === OVERVIEW: Graph annotations place symbols, text, lines, shapes, and bitmaps at data coordinates. Collection under PeAnnotation.Graph. Stored in a single FLAT GLOBAL array -- NOT per-axis or per-subset. All share one index space. Supports: Pego, Pesgo, Pepso (2D), Pe3do (3D adds Z coordinate). INVERTEDYAXIS INTERACTION: When PeGrid.Option.InvertedYAxis = true (C++: PEP_bINVERTEDYAXIS), ALL Y coordinates must be negated. This applies to YData, ManualMinY/ManualMaxY, AND graph annotation Y values. The axis label inversion is display-only; the coordinate space stays positive-up. See Example 108 for a working InvertedYAxis + graph annotations demo. C++ CONSTANT NAMES: The rectangle annotation pattern uses: PEGAT_TOPLEFT=46, PEGAT_BOTTOMRIGHT=47, PEGAT_RECT_FILL=55 Do NOT guess C++ prefixes. See pe-cpp-api-reference for all PEGAT_ values. RUNNING COUNTER PATTERN (recommended): int aCnt = 0; PeAnnotation.Graph.X[aCnt] = ...; PeAnnotation.Graph.Y[aCnt] = ...; PeAnnotation.Graph.Type[aCnt] = ...; aCnt++; CORE PER-ANNOTATION ARRAYS: X[i], Y[i] -- data coordinates (Z[i] for Pe3do) Type[i] -- int cast from GraphAnnotationType enum Text[i] -- label text with optional prefix codes (see below) Color[i] -- Color.FromArgb(alpha, r, g, b) Axis[i] -- target axis 0--15 for multi-axis charts InFront[i] -- AnnotationInFront enum (Default/Behind/InFront/Hide) HotSpot[i] -- AnnotationHotSpot per-annotation (NoHotSpot/GraphOnly/etc.) Shadow[i] -- bool, per-annotation drop shadow GradientStyle[i] -- int cast from PlotGradientStyle enum GradientColor[i] -- gradient start color (default White) Bold[i], Italic[i], Underline[i] -- per-annotation font style booleans Font[i] -- per-annotation font face string (e.g., "Courier New") FontSize[i] -- per-annotation relative text size (float) NOTE: Using any Font/Bold/Italic/Underline/FontSize causes a performance hit -- per-annotation font objects must be allocated. Omit for best speed. GLOBAL GRAPH ANNOTATION PROPERTIES: PeAnnotation.Graph.Show -- bool, show graph annotations PeAnnotation.Graph.ShowShadows -- bool, global shadow toggle (both this AND Shadow[i] must be true for shadow to appear on annotation i) PeAnnotation.Graph.BackColor -- Color behind ALL annotation text PeAnnotation.Graph.Moveable -- bool/GraphAnnotMoveable enum (enables Pointer-type annotations to be dragged by user) PeAnnotation.Graph.GraphAnnotRectHotSpots -- bool, true = entire rect is hotspot, false = only corners are hotspots PeAnnotation.Graph.MinSymbolSize -- MinimumPointSize enum PeAnnotation.Graph.MaxSymbolSize -- MinimumPointSize enum (set both equal to lock symbol size) PeFont.GraphAnnotationTextSize -- int 25--300 (global text size) +1000 RIGHT Y-AXIS OFFSET: Adding 1000 to any GraphAnnotationType integer places the annotation Y coordinate on the RIGHT Y-axis scale instead of left: Graph.Type[i] = (int)GraphAnnotationType.SmallDotSolid + 1000; See Example 015. GRAPH ANNOTATION TEXT PREFIX CODES: Text strings support a two-character prefix: pipe + code character. Format: "|{code}{text}" e.g., "|rMy Label" or "|CBelow Center". Default (no prefix) = centered, bottom-justified (same as |c). HORIZONTAL TEXT (8 codes, normal font): |c Center, bottom-justified (text centered above point) -- DEFAULT |l Left, bottom-justified (text extends right, above point) |r Right, bottom-justified (text extends left, above point) |C Center, top-justified (text centered below point) |L Left, top-justified (text extends right, below point) |R Right, top-justified (text extends left, below point) |f Left-justified, vertically centered on point |g Right-justified, vertically centered on point PATTERN: lowercase = bottom anchor (text above), uppercase = top anchor (text below). Exception: f/g are vertically centered. VERTICAL TEXT (8 codes, 90-degree rotated font): |s Bottom, vertical text, left-side |S Top, vertical text, right-side |m Bottom, vertical text, right-side |M Top, vertical text, left-side |d Centered on left side, vertical text |D Centered on right side, vertical text |e Top, vertical text, centered |E Bottom, vertical text, centered SPECIAL TEXT CODES (3 codes): |H Manual text offset from pointer. Format: |H{x}|{y}|{text} Text drawn at data coordinates (x,y) while symbol stays at X[i],Y[i]. Used with Pointer type. See Example 031. |V Same as |H but text is vertically oriented. |a Absolute angled text. Format: |a{angle_tenths}|{text} Angle in tenths of degrees: |a450| = 45 deg, |a-850| = -85 deg. REQUIRES preceding NullPen annotation (see below). ANGLED TEXT -- TWO METHODS: METHOD A -- DATA-LINE ANGLE (Example 015): Angle computed from line between two annotation coordinates. Text follows the data-line slope if placed on a data line. Graph.X[n] = x1; Graph.Y[n] = y1; Graph.Type[n] = (int)GraphAnnotationType.NullPen; Graph.Text[n] = ""; n++; Graph.X[n] = x2; Graph.Y[n] = y2; Graph.Type[n] = (int)GraphAnnotationType.AngledTextLeftTop; Graph.Text[n] = "Label"; n++; AngledText enum variants control anchor corner: AngledText(194), AngledTextCenter(195), AngledTextTop(196), AngledTextLeftBottom(241), AngledTextLeftTop(242), AngledTextRightBottom(243), AngledTextRightTop(244). METHOD B -- ABSOLUTE ANGLE (Example 149): Angle explicitly specified. Requires NullPen + NoSymbol pair at SAME X,Y. NullPen carries justification state; NoSymbol carries the |a text. // Step 1: NullPen sets justification state Graph.X[n] = x; Graph.Y[n] = y; Graph.Type[n] = (int)GraphAnnotationType.NullPen; Graph.Text[n] = "|L"; // justification: l/L/r/R/c/C Graph.Color[n] = Color.FromArgb(0,0,0,0); n++; // Step 2: NoSymbol carries angled text Graph.X[n] = x; Graph.Y[n] = y; Graph.Type[n] = (int)GraphAnnotationType.NoSymbol; Graph.Text[n] = "|a-450|Right Top -45"; Graph.Color[n] = Color.FromArgb(255,0,255,255); n++; // Step 3: Optional visible symbol at same point Graph.X[n] = x; Graph.Y[n] = y; Graph.Type[n] = (int)GraphAnnotationType.SmallDotSolid; Graph.Text[n] = ""; n++; NoSymbol enables text to be its own hotspot. The separate symbol (SmallDotSolid) provides the visible marker with HotSpot = NoHotSpot. NullPen justification codes for angled text: l, L, r, R, c, C. TEXT BOUNDING BOX (state toggle): TextBoundingBox is a sequential toggle affecting all subsequent annotations. // Turn ON bounding box Graph.Type[n] = (int)GraphAnnotationType.TextBoundingBox; Graph.Color[n] = Color.FromArgb(255, 0, 100, 0); n++; // box color // ... annotations here get bounding boxes ... // Turn OFF bounding box Graph.Type[n] = (int)GraphAnnotationType.TextBoundingBox; Graph.Color[n] = Color.FromArgb(0, 0, 0, 0); n++; // alpha=0 turns off See Examples 015 and 149. COMPOSITE ANNOTATION PATTERNS: CONNECTED LINES: ThinSolidLine at start --> LineContinue for each segment. End with ArrowSolidSmall/Medium/Large for arrow-tipped lines. RECTANGLE/ELLIPSE: TopLeft at corner1 --> BottomRight at corner2 --> EllipseFill/RectFill/RoundRectFill with fill color + optional shadow. Hatch variants: EndPolygonHatchCross, RectHatchDiagonal, etc. POLYGON: StartPoly --> AddPolyPoint(s) --> EndPolygon (or EndPolygonHatch*). PARAGRAPH TEXT: StartText (first line) --> AddText (additional lines) --> Paragraph at final position with color and optional Font[i]. Each line includes '\n' newline. See Example 015. REGION BANDS (Top/Bottom/RectFill triple): Top with Y=1.0E+20 --> Bottom with Y=threshold --> RectFill with alpha color. Creates colored horizontal band. See Example 101. POINTER ARROW: PointerArrowSmall/Medium/Large -- draws arrow from text to annotation point. Moveable when Graph.Moveable = true. BITMAP GRAPH ANNOTATIONS: Custom images as annotation symbols. Uses the same WorkingBitmap slot system as subset point types. A bitmap registered here can be reused by table annotations and legend annotations. // 1. Set the annotation color FIRST (Mask/Tint colorize from this). Graph.Color[i] = Color.FromArgb(255, 215, 0, 215); // 2. Configure the bitmap slot. PePlot.Bitmaps.WorkingBitmap = 0; // slot 0--150 PePlot.Bitmaps.Filename = "image.png"; PePlot.Bitmaps.ColorizeMode = ResourceBitmapColorizeMode.Tint; PePlot.Bitmaps.Style = ResourceBitmapStyle.LargeCentered; // 3. Assign the type (10001 + slot index). Graph.Type[i] = (int)10001; Graph.X[i] = 3.5; Graph.Y[i] = 1390; Graph.Text[i] = "Label"; COLORIZEMODE (ResourceBitmapColorizeMode enum): None -- bitmap drawn in its native colors (Graph.Color[i] unused) Mask -- all visible pixels swapped to Graph.Color[i] (silhouette recolor) Tint -- white/gray highlights preserved, hue retinted to Graph.Color[i] For graph annotation bitmaps, the color source is Graph.Color[i] (NOT SubsetColors). Set Graph.Color[i] BEFORE assigning Graph.Type[i]. REGISTRATION SIDE-EFFECT: Assigning Graph.Type[i] = 10001+N also registers bitmap slot N for reuse by PeAnnotation.Table.Type and PeLegend.AnnotationType. If the bitmap is only needed in a table or legend, define a throwaway graph annotation at off-screen coordinates just to register the slot. LEGACY: PePlot.Bitmaps.Colorize (bool) still compiles but is deprecated; Colorize=true mapped to Mask only. New code should use ColorizeMode. ResourceBitmapStyle controls size/position: ActualSizeCentered, SmallCentered, MediumCentered, LargeCentered, DataSized, plus directional variants (SmallN, SmallNE, etc.). See pe-pointcolors for the full bitmap reference. See Examples 015, 140. TEXT DODGING SYSTEM (auto-positioning to avoid overlaps): Graph.TextLocation[i] -- array of angles (0--360 deg) defining search order. Default is internal. Setting TextLocation[0] = 270 makes "directly above" the first attempted position. Dodging iterates through all defined angles, then increases radius by 10% and retries. Graph.TextDodge -- int 0--100, number of dodging iterations (0 = no dodging). Graph.SubsetObstacles[s] -- bool per subset, true = dodge around that subset. Graph.SymbolObstacles -- bool, true = dodge around other annotation symbols. Graph.AllDodging -- bool (Pe3do), enables dodging for non-Pointer types. See Example 031. MULTI-AXIS TARGETING: Graph.Axis[i] = axisIndex (0--15) routes annotation to correct axis strip. Y coordinate interpreted in that axis's scale. Without this, all annotations render in axis 0's region. See Examples 012, 031, 149. DISPLAY AND INTERACTION: PeAnnotation.Show = true -- global master switch PeAnnotation.InFront = true/false -- global z-order default PeAnnotation.ShowAnnotationText = true -- show/hide all annotation text PeUserInterface.HotSpot.GraphAnnotation = AnnotationHotSpot.GraphOnly PeUserInterface.Menu.AnnotationControl = true PeUserInterface.Menu.ShowAnnotationText = MenuControl.Show Pe3do 3D GRAPH ANNOTATIONS: See DEDICATED file pe-3d-graph-annotations for comprehensive coverage of: 3D shapes (Cylinder, Cone, Sphere, Box, 3D EllipseFill), AxisDirection/ MajorMinorRadii state machine, wireframe vs solid mode toggle, GraphAnnotationPolyData via PEvset, OIT transparency, and 3D-specific properties (LeftJustificationOutside, AnnotationTextFixedSize, SizeCntl, SetViewingAt, AllDodging). All 2D patterns above also work in Pe3do with the addition of Graph.Z[i] for depth positioning. KEY: Always query paths before coding: pe_query.py enum GraphAnnotationType pe_query.py props "Graph.Text" pe_query.py search "annotation"