Created
July 13, 2020 16:58
-
-
Save Wikunia/aa6f8b95e53576ca8f8e592c70258787 to your computer and use it in GitHub Desktop.
Visualzing digits
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Luxor, ColorSchemes | |
using UnicodeFun | |
using Primes | |
struct PNGScene | |
opts::Dict{Symbol, Any} | |
end | |
function get_coord(val, radius) | |
θ = 2π*0.1*val | |
return Point( | |
radius*sin(θ), | |
-radius*cos(θ), | |
) | |
end | |
function draw_background(scene, framenumber) | |
background("black") | |
radius = scene.opts[:radius] | |
show_dots = scene.opts[:show_dots] | |
show_dots && (radius += 20) | |
show_bars = scene.opts[:show_bars] | |
show_bars && (radius += 5) | |
colors = scene.opts[:colors] | |
center_text = scene.opts[:center_text] | |
setline(10) | |
fontsize(20) | |
for i in 0:9 | |
from = get_coord(i, radius) | |
to = get_coord(i+1, radius) | |
sethue(colors[i+1]) | |
θ = 2π*0.1*i+0.1*π | |
mid = Point( | |
radius*sin(θ), | |
-radius*cos(θ), | |
) | |
if show_bars | |
label(string(i), -π/2+θ, mid; offset=35) | |
else | |
label(string(i), -π/2+θ, mid; offset=15) | |
end | |
move(from) | |
arc2r(O, from, to, :stroke) | |
end | |
sethue("white") | |
fontsize(60) | |
text(center_text, Point(-2, 0), valign=:middle, halign=:center) | |
end | |
function draw_bars(scene, framenumber) | |
next_digit_mat = scene.opts[:next_digit_mat] | |
next_digit_mat .= 0 | |
digits = scene.opts[:digits] | |
colors = scene.opts[:colors] | |
max_digits = scene.opts[:max_digits] | |
radius = scene.opts[:radius] | |
show_dots = scene.opts[:show_dots] | |
show_dots && (radius += 20) | |
show_bars = scene.opts[:show_bars] | |
show_bars && (radius += 8) | |
last_i = min(framenumber, max_digits-1) | |
multiplier = 1000 | |
for i=1:last_i | |
from_val = digits[i] | |
to_val = digits[i+1] | |
next_digit_mat[from_val+1, to_val+1] += 1 | |
ndm = next_digit_mat[from_val+1, to_val+1] | |
sethue(colors[to_val+1]) | |
θ = 2π*0.1*(from_val+to_val/10) | |
height = ndm/max_digits*multiplier | |
bl = Point((radius+5)*sin(θ), -(radius+5)*cos(θ)) | |
tl = Point((radius+5+height)*sin(θ), -(radius+5+height)*cos(θ)) | |
θ = 2π*0.1*(from_val+(to_val+1)/10) | |
tr = Point((radius+5+height)*sin(θ), -(radius+5+height)*cos(θ)) | |
br = Point((radius+5)*sin(θ), -(radius+5)*cos(θ)) | |
poly([bl,tl,tr,br,bl], :fill) | |
end | |
end | |
function dig_line(scene, framenumber) | |
radius = scene.opts[:radius] | |
colors = scene.opts[:colors] | |
center_text = scene.opts[:center_text] | |
bezier_radius = scene.opts[:bezier_radius] | |
max_digits = scene.opts[:max_digits] | |
digits = scene.opts[:digits] | |
setline(0.1) | |
for i in 1:min(framenumber, max_digits-1) | |
from_val = digits[i] | |
to_val = digits[i+1] | |
f = from_val+(i-1)/max_digits | |
t = to_val+i/max_digits | |
from = get_coord(f, radius) | |
to = get_coord(t, radius) | |
# get the correct mid point for example for 0-9 it should be 9.5 and not 4.5 | |
mid_val = (f+t)/2 | |
mid_control = get_coord(mid_val, bezier_radius) | |
if abs(f-t) >= 5 | |
mid_control = get_coord(mid_val+5, bezier_radius) | |
end | |
pts = Point[from, mid_control, mid_control, to] | |
bezpath = BezierPathSegment(pts...) | |
# reverse the color to see where it is going | |
setblend(blend(from, to, colors[to_val+1], colors[from_val+1])) | |
drawbezierpath(bezpath, :stroke, close=false) | |
end | |
end | |
function draw_dots(scene, framenumber) | |
radius = scene.opts[:radius] | |
colors = scene.opts[:colors] | |
center_text = scene.opts[:center_text] | |
bezier_radius = scene.opts[:bezier_radius] | |
max_digits = scene.opts[:max_digits] | |
digits = scene.opts[:digits] | |
current_len = 1 | |
for i in 1:min(framenumber, max_digits-1) | |
from_val = digits[i] | |
to_val = digits[i+1] | |
if from_val == to_val | |
current_len += 1 | |
continue | |
end | |
current_len == 1 && continue | |
f = from_val+(i-1)/max_digits | |
from = get_coord(f, radius + 10) | |
sethue(colors[to_val+1]) | |
circle(from, current_len, :fill) | |
current_len = 1 | |
end | |
end | |
function viz(;radius=250, bezier_radius=50, colors=ColorSchemes.rainbow[7:end], | |
max_digits=1000, show_dots=false, show_bars=false, number=:pi, anim=true, width=500, height=500, | |
fname="testing", show_lines=true | |
) | |
center_text = "" | |
if number isa Symbol | |
if number == :primes | |
println("You have chosen to visualize the last digit of primes.") | |
println("Be aware that max_digits now means the largest number.") | |
digits_arr = [digits(x)[1] for x in primes(max_digits)] | |
max_digits = length(digits_arr) | |
else | |
center_text = to_latex("\\$number") | |
digits_arr = setprecision(BigFloat, Int(ceil(log2(10) * max_digits+10))) do | |
if number == :pi | |
return parse.(Int, collect(string(BigFloat(pi))[3:max_digits+2])) | |
elseif number == :tau | |
return parse.(Int, collect(string(2*BigFloat(pi))[3:max_digits+2])) | |
end | |
end | |
end | |
elseif number isa Integer | |
digits_arr = reverse(digits(number)) | |
elseif eltype(number) <: Integer | |
digits_arr = number | |
else | |
throw(DomainError(number, "$number should be either :pi, :tau, :primes or an integer")) | |
end | |
args = Dict(:radius => radius, | |
:bezier_radius => bezier_radius, | |
:colors => colors, :max_digits => max_digits, | |
:digits => digits_arr, :center_text => center_text, | |
:show_dots => show_dots, | |
:show_bars => show_bars, :next_digit_mat => zeros(Int, (10,10)) | |
) | |
if anim | |
movie = Movie(width, height, "test") | |
scenes = [ | |
Scene(movie, draw_background, 0:max_digits+50, optarg=args), | |
] | |
if show_lines | |
push!(scenes, Scene(movie, dig_line, 0:max_digits+50, optarg=args)) | |
end | |
if show_dots | |
push!(scenes, Scene(movie, draw_dots, 0:max_digits+50, optarg=args)) | |
end | |
if show_bars | |
push!(scenes, Scene(movie, draw_bars, 0:max_digits+50, optarg=args)) | |
end | |
animate(movie, scenes, | |
creategif = true, | |
pathname = "./$fname.gif" | |
) | |
else | |
scene = PNGScene(args) | |
@png begin | |
draw_background(scene, max_digits) | |
if show_lines | |
dig_line(scene, max_digits) | |
end | |
if show_dots | |
draw_dots(scene, max_digits+50) | |
end | |
if show_bars | |
draw_bars(scene, max_digits+50) | |
end | |
end 700 700 "./$fname.png" | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment