Contents

ChrisGVE/PlotSwift

Data visualization library for Swift

Overview

PlotSwift provides a low-level vector graphics system inspired by CoreGraphics but with a retained-mode architecture. All drawing operations are stored as commands that can be rendered at any resolution without quality loss.

Design Philosophy

  • Vector-first rendering - All drawing operations stored as commands for scale-free output
  • Multiple export formats - PNG, PDF, and SVG from the same drawing commands
  • CoreGraphics based - Native rendering using Apple's graphics stack
  • Foundation for plotting - Building block for data visualization (high-level plotting APIs coming in future versions)

Installation

Swift Package Manager

Add PlotSwift to your Package.swift:

dependencies: [
    .package(url: "https://github.com/ChrisGVE/PlotSwift.git", from: "0.1.0")
]

Or add it directly in Xcode via File > Add Package Dependencies.

Quick Start

Basic Drawing

import PlotSwift

// Create a drawing context
let ctx = DrawingContext()

// Draw shapes
ctx.setFillColor(.blue)
ctx.rect(50, 50, 200, 150)
ctx.fillPath()

ctx.setStrokeColor(.red)
ctx.setStrokeWidth(2.0)
ctx.circle(cx: 150, cy: 125, r: 50)
ctx.strokePath()

// Add text
ctx.text("Hello PlotSwift", x: 150, y: 220, style: TextStyle(
    fontSize: 16,
    fontWeight: .bold,
    color: .black,
    anchor: .middle
))

// Export to PNG
if let pngData = ctx.renderToPNG(size: CGSize(width: 400, height: 300)) {
    // Use the PNG data
}

Path Construction

let ctx = DrawingContext()

// Build a custom path
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)
ctx.closePath()

ctx.setFillColor(Color(hex: "#3498db")!)
ctx.setStrokeColor(.black)
ctx.setStrokeWidth(2.0)
ctx.fillAndStrokePath()

Curves and Arcs

let ctx = DrawingContext()

// Bezier curve
ctx.moveTo(50, 150)
ctx.curveTo(cp1x: 100, cp1y: 50, cp2x: 200, cp2y: 50, x: 250, y: 150)
ctx.setStrokeColor(.purple)
ctx.strokePath()

// Arc
ctx.arc(cx: 150, cy: 150, r: 80, startAngle: 0, endAngle: .pi * 1.5)
ctx.setStrokeColor(.orange)
ctx.setStrokeWidth(3.0)
ctx.strokePath()

Transforms

let ctx = DrawingContext()

// Save state before transform
ctx.saveState()

// Apply transforms
ctx.translate(200, 200)
ctx.rotate(.pi / 4)  // 45 degrees
ctx.scale(1.5, 1.5)

// Draw at transformed position
ctx.rect(-25, -25, 50, 50)
ctx.setFillColor(.green)
ctx.fillPath()

// Restore original state
ctx.restoreState()

Export Formats

let ctx = DrawingContext()
// ... add drawing commands ...

let size = CGSize(width: 800, height: 600)

// PNG with custom scale (for retina displays)
let pngData = ctx.renderToPNG(size: size, scale: 2.0)

// PDF (vector format)
let pdfData = ctx.renderToPDF(size: size)

// SVG (web-friendly vector)
let svgString = ctx.renderToSVG(size: size)

API Reference

Color

Create colors from RGB values, hex strings, or named colors:

let red = Color(red: 1, green: 0, blue: 0)
let blue = Color(hex: "#0000FF")!
let green = Color(name: "green")!

// Predefined colors
Color.black, Color.white, Color.red, Color.green, Color.blue
Color.yellow, Color.cyan, Color.magenta, Color.orange, Color.purple
Color.gray, Color.lightGray, Color.darkGray, Color.clear

TextStyle

Configure text rendering:

let style = TextStyle(
    fontFamily: "sans-serif",
    fontSize: 14,
    fontWeight: .bold,    // .normal, .bold, .light
    color: .black,
    anchor: .middle       // .start, .middle, .end
)

LineStyle

Available line styles:

LineStyle.solid     // Continuous line
LineStyle.dashed    // Long dashes
LineStyle.dotted    // Dots
LineStyle.dashDot   // Alternating dash-dot
LineStyle.none      // No line

MarkerStyle

Marker shapes for data points (rendering support coming soon):

MarkerStyle.circle, .square, .diamond
MarkerStyle.triangleUp, .triangleDown, .triangleLeft, .triangleRight
MarkerStyle.plus, .cross, .star, .dot

DrawingContext Methods

Path Construction:

  • moveTo( x:, y:) - Start a new subpath
  • lineTo( x:, y:) - Add line to current path
  • curveTo(cp1x:, cp1y:, cp2x:, cp2y:, x:, y:) - Cubic Bezier curve
  • quadCurveTo(cpx:, cpy:, x:, y:) - Quadratic Bezier curve
  • closePath() - Close the current subpath

Shapes:

  • rect( x:, y:, width:, height:) - Rectangle
  • ellipse(cx:, cy:, rx:, ry:) - Ellipse
  • circle(cx:, cy:, r:) - Circle (convenience)
  • arc(cx:, cy:, r:, startAngle:, endAngle:, clockwise:) - Arc

Text:

  • text(_ string:, x:, y:, style:) - Draw text

Style State:

  • setStrokeColor(_ color:) - Set stroke color
  • setStrokeWidth(_ width:) - Set line width
  • setStrokeStyle(_ style:) - Set dash pattern
  • setFillColor(_ color:) - Set fill color
  • setAlpha(_ alpha:) - Set global alpha

Drawing Operations:

  • strokePath() - Stroke the current path
  • fillPath() - Fill the current path
  • fillAndStrokePath() - Fill and stroke

Transforms:

  • translate( tx:, ty:) - Translate coordinate system
  • scale( sx:, sy:) - Scale coordinate system
  • rotate(_ angle:) - Rotate (radians)
  • pushTransform(_ transform:) - Push custom transform
  • popTransform() - Pop transform

State Management:

  • saveState() - Save graphics state
  • restoreState() - Restore graphics state
  • clear() - Clear all commands

Export:

  • renderToPNG(size:, scale:) - Export to PNG data
  • renderToPDF(size:) - Export to PDF data
  • renderToSVG(size:) - Export to SVG string

Current Limitations

  • SVG export: Transform nesting is approximate; deeply nested transforms may accumulate rounding. Clip regions use random IDs that may collide in very large documents.
  • Text measurement: Text bounding boxes are estimated from optical bounds, which can be inaccurate for some fonts and scripts. Y-label rotation is simulated via positioning rather than actual SVG/CG rotation.
  • Logarithmic scale: LogTransform clamps non-positive values silently. Tick generation for log scales uses the linear nice-number algorithm rather than decade-based ticks.
  • Animation: Frame-by-frame only; no native video encoding. Use the PNG frame sequence with an external tool (e.g., FFmpeg) for video output.
  • Conditional integration: NumericSwift and ArraySwift extensions are compiled only when those packages are present; they are not testable in standalone builds.
  • Bounds calculation: Stroke width expansion and transform-aware bounds are best-effort approximations; complex transform chains may undercount.

Requirements

  • Swift 5.9+
  • iOS 15.0+ / macOS 12.0+ / watchOS 8.0+ / tvOS 15.0+ / visionOS 1.0+
  • Frameworks: CoreGraphics, CoreText, ImageIO

License

PlotSwift is available under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Package Metadata

Repository: ChrisGVE/PlotSwift

Stars: 2

Forks: 0

Open issues: 0

Default branch: main

Primary language: swift

License: MIT

README: README.md