Skip to content

Commit

Permalink
Update documentation for colormaps (#515)
Browse files Browse the repository at this point in the history
This adds visual examples for `sequential_palette`.
  • Loading branch information
kimikage authored Sep 9, 2021
1 parent 9b57362 commit 60d9add
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 106 deletions.
183 changes: 183 additions & 0 deletions docs/colormapparams.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
module ColormapParams

using Colors
using Main.PNG16x16

struct ColormapParamSVG <: Main.SVG
buf::IOBuffer
end

function ColormapParamSVG(target::Symbol)
io = IOBuffer()
write(io,
"""
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="45mm" height="45mm"
viewBox="0 0 270 270" preserveAspectRatio="none"
shape-rendering="crispEdges" stroke="none" stroke-width="1">
""")
write(io,
"""
<rect width="270" height="270" fill="#aaa" opacity="0.2" />
""")
if target in (:c, :s, :b)
write_chart_csb(io, target)
elseif target in (:w, :d)
write_chart_wd(io, target)
end
write(io, "</svg>")
ColormapParamSVG(io)
end

function write_chart_csb(io, target::Symbol)
pp = (0.1, 0.5, 0.9)
pc = map(_ -> 0.88, pp)
ps = map(_ -> 0.60, pp)
pb = map(_ -> 0.75, pp)
markers = ("m -5,-5 v 10 h 10 v -10 z",
"m 0,-5 l -5,9 h 10 z",
"m 0,-4 l -4,4 4,4 4,-4 z")
if target === :c
col = Colors.JULIA_LOGO_COLORS.purple
label = "contrast"
pc = pp
elseif target === :s
col = Colors.JULIA_LOGO_COLORS.red
label = "saturation"
ps = pp
elseif target === :b
col = Colors.JULIA_LOGO_COLORS.green
label = "brightness"
pb = pp
end
h = round(Int, hue(convert(Luv, col)))
n = 16
ls = (100/2/n):(100/n):100
cs = (175/2/n):(175/n):175
mc(l) = Colors.find_maximum_chroma(LCHuv(l, 0.0, h))
plane = [LCHuv(100.0 - l, min(c, mc(l)), h) for l in ls, c in cs]
write(io,
"""
<g transform="translate(80, 20)" fill="none" stroke-width="1.5"
style="font-size: 18px; font-style: italic;">
<image width="100" height="100" transform="scale(1.75, 2)" xlink:href=\"""")
write_png_as_data(io, plane)
write(io, "\" />\n")
mc_coords = join(string(round(Int, mc(100 - l)), ",", 2l, " ") for l = 0:2:100)
write(io,
"""
<path d="m 175,0 L $mc_coords 175,200 z" fill="#aaa" />
<path d="m 0,200 v -215 l 5,10 m -10,0 l 5,-10" stroke="currentColor" />
<path d="m 0,200 h 185 l -10,5 m 0,-10 l 10,5" stroke="currentColor" />
<text fill="currentColor" x="150" y="220">C*</text>
<text fill="currentColor" x="-25" y="10" >L*</text>
""")
write(io, "</g>")
for i = 1:3
colors= sequential_palette(h, 7, c=pc[i], s=ps[i], b=pb[i], w=0, d=0)
write_colormap(io, 25 * i - 20, pp[i], colors, markers[i])
end
tcolors = (sequential_palette(h, 25, c=pc[i], s=ps[i], b=pb[i], w=0, d=0) for i = 1:3)
write_stroke(io, tcolors, markers)
write(io,
"""
<text fill="currentColor" y="260" style="font-size: 18px;">
<tspan x="70" style="font-style: italic;">$target</tspan>
<tspan x="90">- $label [0,1]</tspan>
</text>
""")
end

function write_chart_wd(io, target::Symbol)
pp = 0.0:0.2:1.0
pw = map(_ -> 0.15, pp)
pd = map(_ -> 0.0, pp)

if target === :w
col = Colors.JULIA_LOGO_COLORS.blue
cy = 40
pw = pp
kcol = "#ff0"
elseif target === :d
col = Colors.JULIA_LOGO_COLORS.green
cy = 200
pd = pp
kcol = "#00f"
end
h = round(Int, hue(convert(Luv, col)))
for i in eachindex(pp)
colors = sequential_palette(h, 9, w=pw[i], d=pd[i])
write_colormap(io, 30 * i - 10, pp[i], colors)
end
write(io,
"""
<rect x="205" y="$cy" width="20" height="20" fill="$kcol" />
""")
write(io,
"""
<text fill="currentColor" y="260" style="font-size: 18px;">
<tspan x="20" style="font-style: italic;">$target</tspan>
<tspan x="40">- strength of $(target)color [0,1]</tspan>
<tspan x="195" y="$(cy-5)" style="font-style: italic;">$(target)color</tspan>
</text>
""")
end

function write_colormap(io, x, p, colors, marker="")
y = 0
write(io,
"""
<g transform="translate($x, 40)" stroke-opacity="0.5">
""")
for col in colors
write(io,
"""
<rect x="0" y="$y" width="20" height="20" fill="#$(hex(col))" />
""")
y += 20
end
if !isempty(marker)
y += 10
write(io,
"""
<path d="m 10,$y $marker" fill="#$(hex(last(colors)))" stroke="white" />
""")
end
y += 20
write(io,
"""
<text x="0" y="$y" fill="currentColor" style="font-size: 15px;">$p</text>
""")
write(io, "</g>")
end

function write_stroke(io, tcolors, markers)
write(io,
"""
<g transform="translate(80, 20)" stroke="white" stroke-opacity="0.5">
""")
coord(c) = string(round(Int, c.c), ",", round(Int, 2 * (100 - c.l)), " ")
for (i, colors) in enumerate(tcolors)
coords = join(map(coord, LCHuv.(colors)))
op = (0.4, 0.6, 1.0)[i]
sw = (10, 4, 1)[i]
write(io,
"""
<path d="M $coords" fill="none" stroke-opacity="$op" stroke-width="$sw" />
""")
end
for (i, colors) in enumerate(tcolors)
mk = markers[i]
hx = hex(last(colors))
write(io,
"""
<path d="M $(coord(LCHuv(first(colors))))$mk" fill="#$hx" />
<path d="M $(coord(LCHuv(last( colors))))$mk" fill="#$hx" />
""")
end
write(io, "</g>")
end

end # module
71 changes: 3 additions & 68 deletions docs/crosssectionalcharts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
module CrossSectionalCharts

using Colors
using Base64
using Main.PNG16x16

struct CrossSectionalChartSVG <: Main.SVG
buf::IOBuffer
Expand Down Expand Up @@ -119,10 +119,8 @@ function crosssection(::Type{C}, x::Axis, y::Axis, z::Axis) where C <: Color
"""
<g>
<rect fill="#$(hex(ccolor))" width="4" height="$(barh)" x="36" y="$(isodd(i) ? 30 - barh : 0)" />
<image width="16" height="16" transform="scale(2) translate(-.5,0)" $op xlink:href="data:image/png;base64,""")
b64enc = Base64EncodePipe(io)
write_png(b64enc, plane)
close(b64enc)
<image width="16" height="16" transform="scale(2) translate(-.5,0)" $op xlink:href=\"""")
write_png_as_data(io, plane)
write(io, "\" />\n")
write(io,
"""
Expand Down Expand Up @@ -164,69 +162,6 @@ function crosssection(::Type{C}, x::Axis, y::Axis, z::Axis) where C <: Color
CrossSectionalChartSVG(io)
end


function write_png(io::IO, cs::AbstractArray{T}) where T <: Color
buf = IOBuffer() # to calculate chunk CRCs
n = 16 # 16 x 16
u8(x) = write(buf, UInt8(x & 0xFF))
u16(x) = (u8((x & 0xFFFF)>>8); u8(x))
u32(x) = (u16((x & 0xFFFFFFFF)>>16); u16(x))
b(bstr) = write(buf, bstr)
function palette(c::Color)
rgb24 = convert(RGB24,c)
u8(rgb24.color>>16); u8(rgb24.color>>8); u8(rgb24.color)
end
crct(x) = (for i = 1:8; x = x & 1==1 ? 0xEDB88320 (x>>1) : x>>1 end; x)
table = UInt32[crct(i) for i = 0x00:0xFF]
function crc32()
seekstart(buf)
crc = 0xFFFFFFFF
while !eof(buf)
crc = (crc>>8) table[(crc&0xFF) read(buf, UInt8) + 1]
end
u32(crc 0xFFFFFFFF)
end
flush() = write(io, take!(seekstart(buf)))

# The following is a pre-encoded 256-indexed-color PNG with size of 16x16.
# We only rewrite "pallets".
b(b"\x89PNG\x0D\x0A\x1A\x0A")
# Image header
u32(13); flush(); b(b"IHDR"); u32(n); u32(n); u8(8); u8(3); u8(0); u8(0); u8(0); crc32()
# Palette
u32(n * n * 3); flush();
b(b"PLTE")
for y = 1:n, x = 1:n
palette(cs[y,x])
end
crc32()
# Image data
u32(58); flush(); b(b"IDAT")
b(b"\x78\xDA\x63\x64\x60\x44\x03\x02\xE8\x02\x0A\xE8\x02\x06\xE8\x02")
b(b"\x0E\xE8\x02\x01\xE8\x02\x09\xE8\x02\x05\xE8\x02\x0D\xE8\x02\x13")
b(b"\xD0\x05\x16\xA0\x0B\x6C\x40\x17\x38\x80\x2E\x70\x01\x5D\xE0\x01")
b(b"\xBA\xC0\x07\x34\x3E\x00\x54\x4D\x08\x81"); crc32()
# Image trailer
u32(0); flush(); b(b"IEND"); crc32()
flush()
end

"""
# Image data
using CodecZlib
raw = IOBuffer()
for y = 0:15
write(raw, UInt8(1)) # filter: SUB
write(raw, UInt8(y*16)) # line head
write(raw, UInt8[1 for i=1:15]) # left + 1
end
flush(raw)
cd = ZlibCompressorStream(raw,level=9)
flush(cd)
seekstart(cd)
@show read(cd) # UInt8[0x78, 0xda, 0x63, 0x64, ...
"""

crosssection(::Type{HSV}) = crosssection(HSV, x=(2, "S", 0:1),
y=(3, "V", 0:1),
z=(1, "H", 0:360))
Expand Down
3 changes: 2 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ function Base.show(io::IO, ::MIME"text/html", svg::SVG)
write(io, "</body></html>")
flush(io)
end

include("png16x16.jl")
include("crosssectionalcharts.jl")
include("colordiffcharts.jl")
include("colormaps.jl")
include("colormapparams.jl")
include("namedcolorcharts.jl")
include("sampleimages.jl")

Expand Down
77 changes: 77 additions & 0 deletions docs/png16x16.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module PNG16x16

using Colors
using Base64

export write_png_as_data, write_png

function write_png_as_data(io::IO, cs::AbstractMatrix{<:Color})
write(io, "data:image/png;base64,")
b64enc = Base64EncodePipe(io)
write_png(b64enc, cs)
close(b64enc)
end

function write_png(io::IO, cs::AbstractMatrix{<:Color})
buf = IOBuffer() # to calculate chunk CRCs
n = 16 # 16 x 16
u8(x) = write(buf, UInt8(x & 0xFF))
u16(x) = (u8((x & 0xFFFF)>>8); u8(x))
u32(x) = (u16((x & 0xFFFFFFFF)>>16); u16(x))
b(bstr) = write(buf, bstr)
function palette(c::Color)
rgb24 = convert(RGB24,c)
u8(rgb24.color>>16); u8(rgb24.color>>8); u8(rgb24.color)
end
crct(x) = (for i = 1:8; x = x & 1==1 ? 0xEDB88320 (x>>1) : x>>1 end; x)
table = UInt32[crct(i) for i = 0x00:0xFF]
function crc32()
seekstart(buf)
crc = 0xFFFFFFFF
while !eof(buf)
crc = (crc>>8) table[(crc&0xFF) read(buf, UInt8) + 1]
end
u32(crc 0xFFFFFFFF)
end
flush() = write(io, take!(seekstart(buf)))

# The following is a pre-encoded 256-indexed-color PNG with size of 16x16.
# We only rewrite "pallets".
b(b"\x89PNG\x0D\x0A\x1A\x0A")
# Image header
u32(13); flush(); b(b"IHDR"); u32(n); u32(n); u8(8); u8(3); u8(0); u8(0); u8(0); crc32()
# Palette
u32(n * n * 3); flush();
b(b"PLTE")
for y = 1:n, x = 1:n
palette(cs[y,x])
end
crc32()
# Image data
u32(58); flush(); b(b"IDAT")
b(b"\x78\xDA\x63\x64\x60\x44\x03\x02\xE8\x02\x0A\xE8\x02\x06\xE8\x02")
b(b"\x0E\xE8\x02\x01\xE8\x02\x09\xE8\x02\x05\xE8\x02\x0D\xE8\x02\x13")
b(b"\xD0\x05\x16\xA0\x0B\x6C\x40\x17\x38\x80\x2E\x70\x01\x5D\xE0\x01")
b(b"\xBA\xC0\x07\x34\x3E\x00\x54\x4D\x08\x81"); crc32()
# Image trailer
u32(0); flush(); b(b"IEND"); crc32()
flush()
end

"""
# Image data
using CodecZlib
raw = IOBuffer()
for y = 0:15
write(raw, UInt8(1)) # filter: SUB
write(raw, UInt8(y*16)) # line head
write(raw, UInt8[1 for i=1:15]) # left + 1
end
flush(raw)
cd = ZlibCompressorStream(raw,level=9)
flush(cd)
seekstart(cd)
@show read(cd) # UInt8[0x78, 0xda, 0x63, 0x64, ...
"""

end # module
Loading

0 comments on commit 60d9add

Please sign in to comment.