diff --git a/examples/animation.jl b/examples/animation.jl index 8c04720..7315674 100644 --- a/examples/animation.jl +++ b/examples/animation.jl @@ -6,7 +6,7 @@ df = CSV.File(pkgdir(WordCloud)*"/res/guxiang_frequency.txt", header=false)|> Da words = df[!, "Column2"] weights = df[!, "Column3"] -wc = wordcloud(words, weights, density=0.7) +wc = wordcloud(words, weights, density=0.65) gifdirectory = "guxiang_animation" #eval# try rm("guxiang_animation", force=true, recursive=true) catch end generate_animation!(wc, 100, outputdir=gifdirectory) diff --git a/examples/benchmark.jl b/examples/benchmark.jl index 779a31e..6d05876 100644 --- a/examples/benchmark.jl +++ b/examples/benchmark.jl @@ -27,7 +27,7 @@ for (i,wc) in enumerate(wcs) println("\n", i-1, "==== ", j, "/", length(ts), " ", nameof(t)) placement!(wc) @time e = @elapsed generate!(wc, trainer=t, retry=1) - push!(es[i],nameof(t)=>e) + push!(es[i], string(nameof(t)) * (getstate(wc)==:generate! ? " ✔" : " ✘")=>e) end end println("SUMMARY") diff --git a/examples/highdensity.jl b/examples/highdensity.jl index aad328f..e374d8b 100644 --- a/examples/highdensity.jl +++ b/examples/highdensity.jl @@ -6,7 +6,7 @@ using WordCloud #md# mask = shape(box, 400, 300, 10), #md# colors = :Dark2_3, #md# angles = (0, 90), -#md# density = 0.75) |> generate! +#md# density = 0.7) |> generate! #md# paint(wc, "highdensity.png") #md# ``` #md# But you may find that doesn't work. That is because there should be at least 1 pixel gap between two words, which is controlled by the `border` parameter (default 1) in `wordcloud`. While, when the picture is small, 1 pixel is expensive. So, that can be done as follows: @@ -15,7 +15,7 @@ wc = wordcloud( mask = shape(box, 400*2, 300*2, 10*2), colors = :Dark2_3, angles = (0, 90), - density = 0.75) |> generate! + density = 0.7) |> generate! paint(wc, "highdensity.png", ratio=0.5) #md# println("results are saved to highdensity.png") diff --git a/src/strategy.jl b/src/strategy.jl index 4f59f46..d89ed3c 100644 --- a/src/strategy.jl +++ b/src/strategy.jl @@ -18,7 +18,7 @@ end function feelingoccupied(imgs, border=0, bgvalue=imgs[1][1]) bs = boxoccupied.(imgs, border) os = occupied.(imgs, bgvalue) - s = (0.8 * sum(bs) .+ 0.2 * sum(os)) / 0.93 #兼顾饱满字体(华文琥珀)和清瘦字体(仿宋) + s = (0.8 * sum(bs) + 0.2 * sum(os)) / 0.93 #兼顾饱满字体(华文琥珀)和清瘦字体(仿宋) # sum(os) ≈ 2/3 sum(bs), 故除以0.93还原到sum(bs)的大小 th = 10quantile(bs, 0.1) bigind = findall(x->x>th, bs) @@ -53,7 +53,7 @@ function prepareword(word, fontsize, color, angle; backgroundcolor=(0,0,0,0), fo angle=angle, border=border, font=font, type=:both) end -wordmask(img, bgcolor, border) = dilate(img.!=img[1], border) +wordmask(img, bgcolor, border) = dilate(img.!=img[1], border) #use `img[1]` instead of `convert(eltype(img), parsecolor(bgcolor))` #https://github.com/JuliaGraphics/Luxor.jl/issues/107 @@ -75,12 +75,17 @@ function find_weight_scale!(wc::WC; initialscale=0, density=0.3, maxiter=5, erro ground_size = wc.params[:groundoccupied] words = wc.words if initialscale <= 0 - initialscale = √(ground_size/length(words)/0.4*density) #初始值假设字符的字面框面积占正方格比率为0.4(低估了汉字) + initialscale = √(ground_size/length(words)/0.45*density) #初始值假设字符的字面框面积占正方格比率为0.45(低估了汉字) end @assert sum(wc.weights.^2 .* length.(words)) / length(wc.weights) ≈ 1.0 + target = density * ground_size target_lower = (density - error) * ground_size target_upper = (density + error) * ground_size target = density * ground_size + best_tar_H = Inf + best_tar_L = -Inf + best_scale_H = Inf + best_scale_L = -Inf step = 0 sc1 = initialscale fonts = getfonts(wc, words) @@ -89,24 +94,47 @@ function find_weight_scale!(wc::WC; initialscale=0, density=0.3, maxiter=5, erro while true step = step + 1 if step > maxiter - @warn "find_weight_scale reach maxiter. This may be caused by too small background image or too many words or too big `minfontsize`." + @warn "find_weight_scale reach maxiter. This may be caused by too small background or too many words or too big `minfontsize`." break end + # cal tg1 + @assert sc1 < 50initialscale #防止全空白words的输入,计算出sc过大渲染字体耗尽内存 wc.params[:scale] = sc1 tg1 = textoccupied(words, getfontsizes(wc, words), fonts) dens = tg1 / ground_size println("scale=$(wc.params[:scale]), density=$dens\t", dens>density ? "↑" : "↓") + if tg1 > target + if best_tar_H > tg1 + best_tar_H = tg1 + best_scale_H = sc1 + end + else + if best_tar_L <= tg1 + best_tar_L = tg1 + best_scale_L = sc1 + end + end + # cal sc2 sc2 = scalestep(sc0, tg0, sc1, tg1, target) +# @show sc0, tg0, sc1, tg1, sc2 + if !(best_scale_L < sc2 < best_scale_H) + if isfinite(best_tar_H + best_tar_L) + sc2_ = √((best_scale_H^2 + best_scale_L^2)/2.) + println("bisection takes effect: scale $sc2 -> $sc2_") + sc2 = sc2_ +# @show best_scale_L best_scale_H + else + Base.error("scalestep failed!") + end + end + # next iter init tg0 = tg1 sc0 = sc1 sc1 = sc2 - @assert sc1 < 50initialscale #防止全空白words的输入,计算出sc过大渲染字体耗尽内存 if target_lower <= tg1 <= target_upper break end - end -# @show textoccupied(words, weights, sc, radius=border) wc.params[:scale] = sc1 return sc1 end