Skip to content

Commit

Permalink
Merge pull request #397 from Mattriks/missing_and_nan
Browse files Browse the repository at this point in the history
Missing and NaN support
  • Loading branch information
Mattriks authored Jun 21, 2020
2 parents 6777e8f + 1f96ae3 commit 656ca90
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 52 deletions.
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[compat]
Expand Down
1 change: 1 addition & 0 deletions src/Compose.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ using Requires
using Dates
using Printf
using Base.Iterators
using Statistics
import JSON

import Base: length, isempty, getindex, setindex!,
Expand Down
2 changes: 2 additions & 0 deletions src/measure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ y_measure(a::Vector) = Measure[y_measure(y) for y in a]
size_measure(a::Measure) = a
size_measure(a) = a * mm

x_measure(a::Missing) = x_measure(NaN)
y_measure(a::Missing) = y_measure(NaN)

# Higher-order measures
# ---------------------
Expand Down
81 changes: 29 additions & 52 deletions src/svg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -537,58 +537,41 @@ end
# out: Output stream.
# points: points on the path
# bridge_gaps: when true, remove non-finite values, rather than forming
# separate lines.
# separate lines. (this arg is never used)
#
# Returns:
# A string containing SVG path data.
#
function print_svg_path(out, points::Vector{AbsoluteVec2},
bridge_gaps::Bool=false)
function print_svg_path(out, points::Vector{AbsoluteVec2})
isfirst = true
for point in points
x, y = point[1].value, point[2].value
if !(isfinite(x) && isfinite(y))
isfirst = true
continue
end

if isfirst
isfirst = false
endp = points[end]
for (currp, nxtp) in zip(points[1:end-1], points[2:end])
x1, y1 = currp[1].value, currp[2].value
x2, y2 = nxtp[1].value, nxtp[2].value
currentp = isfinite(x1) && isfinite(y1)
nextp = isfinite(x2) && isfinite(y2)

if (isfirst && currentp && nextp)
write(out, 'M')
svg_print_float(out, x)
svg_print_float(out, x1)
write(out, ',')
svg_print_float(out, y)
svg_print_float(out, y1)
write(out, " L")
else
write(out, ' ')
svg_print_float(out, x)
isfirst = false
elseif (!isfirst && currentp)
svg_print_float(out, x1)
write(out, ',')
svg_print_float(out, y1)
write(out, ' ')
svg_print_float(out, y)
end
!nextp && (isfirst = true)
end
svg_print_float(out, endp[1].value)
write(out, ',')
svg_print_float(out, endp[2].value)
write(out, ' ')
end

# TODO: This logic should be moved to Gadfly
# Return array of paths to draw with printpath
# array is formed by splitting by NaN values
#function make_paths(points::Vector{AbsoluteVec})
#paths = Vector{AbsoluteVec}[]
#nans = find(xy -> isnan(xy[1]) || isnan(xy[2]),
#[(point[1].value, point[2].value) for point in points])
#if length(nans) == 0
#push!(paths, points)
#else
#nans = [0, nans..., length(points) + 1]
#i, n = 1, length(nans)
#while i <= n-1
#if nans[i] + 1 < nans[i + 1]
#push!(paths, points[(nans[i]+1):(nans[i+1] - 1)])
#end
#i += 1
#end
#end
#paths
#end


# Property Printing
Expand Down Expand Up @@ -809,7 +792,7 @@ function draw(img::SVG, prim::PolygonPrimitive, idx::Int)
indent(img)

write(img.out, "<path d=\"")
print_svg_path(img.out, translated_path, true)
print_svg_path(img.out, translated_path)
write(img.out, " z\"")
print(img.out, " class=\"primitive\"")
write(img.out, "/>\n")
Expand All @@ -823,7 +806,7 @@ function draw(img::SVG, prim::ComplexPolygonPrimitive, idx::Int)
Compose.write(img.out, "<path d=\"")
for ring in prim.rings
indent(img)
print_svg_path(img.out, ring, true)
print_svg_path(img.out, ring)
write(img.out, " ")
end
write(img.out, " z\"")
Expand Down Expand Up @@ -901,16 +884,10 @@ end
function draw(img::SVG, prim::LinePrimitive, idx::Int)
length(prim.points)<=1 && return

x0, y0, n = prim.points[1][1], prim.points[1][2], 1
for p in prim.points[2:end]
if isfinite(p[1].value) && isfinite(p[2].value)
x0 += p[1]
y0 += p[2]
n +=1
end
end
x0, y0 = x0/n, y0/n
translated_path = [(p[1]-x0,p[2]-y0) for p in prim.points]
i = [isfinite(p[1].value) && isfinite(p[2].value) for p in prim.points]
any(i) || return
x0, y0 = mean(prim.points[i])
translated_path = prim.points .- [(x0, y0)]

indent(img)

Expand All @@ -925,7 +902,7 @@ function draw(img::SVG, prim::LinePrimitive, idx::Int)
indent(img)

print(img.out, "<path fill=\"none\" d=\"")
print_svg_path(img.out, translated_path, true)
print_svg_path(img.out, translated_path)
print(img.out, "\"")
print(img.out, " class=\"primitive\"")
print(img.out, "/>\n")
Expand Down
22 changes: 22 additions & 0 deletions test/examples/forms_and_nans.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Compose
import Cairo, Fontconfig

set_default_graphic_size(14cm, 10cm)


y = [0.26, 0.5, missing, 0.4, NaN, 0.48, 0.58, 0.83]
p1 = collect(Tuple, zip(1:8, y))
p2 = collect(Tuple, zip(1:9, vcat(NaN, y)))

img = compose(context(units=UnitBox(0, 0, 10, 1)),
(context(), line([p1]), stroke("black")),
(context(), line([p2]), stroke("red"))
)

imgs = [SVG("forms_and_nans.svg"), PDF("forms_and_nans.pdf")]

draw.(imgs, [img])




5 changes: 5 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,8 @@ end
@test occursin("fill-opacity=\"0.3\"", String(img2.out.data))
@test img3.fill_opacity == 0.3
end

@testset "Missing" begin
@test Compose.x_measure(missing)===NaN*cx
@test Compose.y_measure(missing)===NaN*cy
end

0 comments on commit 656ca90

Please sign in to comment.