Skip to content

Commit

Permalink
axes: Prepare axis code for log axes
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-wolf committed Jul 15, 2024
1 parent 95c11b1 commit 82c8906
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 43 deletions.
88 changes: 69 additions & 19 deletions src/axes.typ
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": util, draw, vector, styles, process, drawable, path-util
#import "/src/cetz.typ": util, draw, vector, matrix, styles, process, drawable, path-util, process

#let typst-content = content

Expand Down Expand Up @@ -462,6 +462,51 @@
return axis
}

// Transform a single vector along a x, y and z axis
//
// - size (vector): Coordinate system size
// - origin (vector): Coordinate system origin
// - x-axis (axis): X axis
// - y-axis (axis): Y axis
// - z-axis (axis): Z axis
// - vec (vector): Input vector to transform
// -> vector
#let transform-vec(size, x-axis, y-axis, z-axis, vec, origin: (0, 0, 0)) = {
let (ox, oy, ..) = origin
ox += x-axis.inset.at(0)
oy += y-axis.inset.at(0)

let (sx, sy) = size
sx -= x-axis.inset.sum()
sy -= y-axis.inset.sum()

let x-range = x-axis.max - x-axis.min
let y-range = y-axis.max - y-axis.min
let z-range = 0 //z-axis.max - z-axis.min

let fx = sx / x-range
let fy = sy / y-range
let fz = 0 //sz / z-range

let x-low = calc.min(x-axis.min, x-axis.max)
let x-high = calc.max(x-axis.min, x-axis.max)
let y-low = calc.min(y-axis.min, y-axis.max)
let y-high = calc.max(y-axis.min, y-axis.max)
//let z-low = calc.min(z-axis.min, z-axis.max)
//let z-hihg = calc.max(z-axis.min, z-axis.max)

let (x, y, ..) = vec

if x < x-low or x > x-high or y < y-low or x > x-high {
return none
}

return (
(x - x-axis.min) * fx + ox,
(y - y-axis.min) * fy + oy,
0) //(z - z-axis.min) * fz + oz)
}

// Draw inside viewport coordinates of two axes
//
// - size (vector): Axis canvas size (relative to origin)
Expand All @@ -470,23 +515,28 @@
// - y (axis): Vertical axis
// - name (string,none): Group name
#let axis-viewport(size, x, y, origin: (0, 0), name: none, body) = {
draw.group(name: name, ctx => {
let origin = origin
let size = size

origin.at(0) += x.inset.at(0)
size.at(0) -= x.inset.sum()
origin.at(1) += y.inset.at(0)
size.at(1) -= y.inset.sum()

size = (rel: size, to: origin)
draw.set-viewport(origin, size,
bounds: (x.max - x.min,
y.max - y.min,
0))
draw.translate((-x.min, -y.min))
body
})
draw.group(name: name, (ctx => {
let transform = ctx.transform

ctx.transform = matrix.ident()
let (ctx, drawables, bounds) = process.many(ctx, util.resolve-body(ctx, body))

ctx.transform = transform

drawables = drawables.map(d => {
d.segments = d.segments.map(((kind, ..pts)) => {
(kind, ..pts.map(pt => {
transform-vec(size, x, y, none, pt, origin: origin)
}))
})
return d
})

return (
ctx: ctx,
drawables: drawable.apply-transform(ctx.transform, drawables)
)
},))
}

// Draw grid lines for the ticks of an axis
Expand All @@ -512,7 +562,7 @@
let offset = vector.add(vector.scale(dir, distance), offset)
let start = vector.add(low, offset)
let end = vector.add(high, offset)

// Draw a major line
if is-major and (kind == 1 or kind == 3) {
draw.line(start, end, stroke: style.grid.stroke)
Expand Down
26 changes: 15 additions & 11 deletions src/plot.typ
Original file line number Diff line number Diff line change
Expand Up @@ -433,11 +433,14 @@
if "plot-stroke" in d {
(d.plot-stroke)(d, plot-ctx)
}
if "mark" in d and d.mark != none {
})

if "mark" in d and d.mark != none {
draw.group({
draw.set-style(..d.style, ..d.mark-style)
mark.draw-mark(d.data, x, y, d.mark, d.mark-size, size)
}
})
})
}
}

// Foreground Annotations
Expand All @@ -456,14 +459,15 @@
let (x, y) = a.axes.map(name => axis-dict.at(name))
let plot-ctx = make-ctx(x, y, size)

data-viewport(a, x, y, size, {
let (ax, ay) = a.position
if ax == "min" {ax = x.min} else if ax == "max" {ax = x.max}
if ay == "min" {ay = y.min} else if ay == "max" {ay = y.max}
draw.anchor("default", (0,0))
draw.anchor(a.name, (ax, ay))
}, name: "anchors")
draw.copy-anchors("anchors", filter: (a.name,))
let pt = a.position.enumerate().map(((i, v)) => {
if v == "min" { return axis-dict.at(a.axes.at(i)).min }
if v == "max" { return axis-dict.at(a.axes.at(i)).max }
return v
})
pt = axes.transform-vec(size, x, y, none, pt)
if pt != none {
draw.anchor(a.name, pt)
}
}
})

Expand Down
20 changes: 7 additions & 13 deletions src/plot/mark.typ
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#import "/src/cetz.typ": draw
#import "/src/axes.typ"

// Draw mark at point with size
#let draw-mark-shape(pt, size, mark, style) = {
let (sx, sy) = if type(size) != array {
(size, size)
} else { size }
let sx = size
let sy = size

let bl(pt) = (rel: (-sx/2, -sy/2), to: pt)
let br(pt) = (rel: (sx/2, -sy/2), to: pt)
Expand Down Expand Up @@ -35,17 +35,11 @@
}

#let draw-mark(pts, x, y, mark, mark-size, plot-size) = {
// Scale marks back to canvas scaling
let (sx, sy) = plot-size
sx = (x.max - x.min) / sx
sy = (y.max - y.min) / sy
sx *= mark-size
sy *= mark-size
let pts = pts.map(pt => {
axes.transform-vec(plot-size, x, y, none, pt)
}).filter(pt => pt != none)

for pt in pts {
let (px, py, ..) = pt
if px >= x.min and px <= x.max and py >= y.min and py <= y.max {
draw-mark-shape(pt, (sx, sy), mark, (:))
}
draw-mark-shape(pt, mark-size, mark, (:))
}
}
Binary file modified tests/chart/ref/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/plot/ref/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 82c8906

Please sign in to comment.