Skip to content

Commit

Permalink
refactor: const and uppercase
Browse files Browse the repository at this point in the history
  • Loading branch information
guo-yong-zhi committed Oct 10, 2024
1 parent 17a4260 commit 08c4801
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 86 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ paint(wc, "alice.png")
## Semantic
[![semantic](res/semantic.png)](./examples/semantic.jl)
*try `runexample(:semantic)` or `showexample(:semantic)`*
The variable `WordCloud.examples` holds all available examples.
The variable `WordCloud.EXAMPLES` holds all available examples.

# About Implementation
WordCloud.jl stands out from other tools due to its unique approach based on image local gradient optimization. Unlike conventional algorithms, WordCloud.jl utilizes a non-greedy algorithm that enables words to be [repositioned](res/animation2.gif) even after their initial placement. This dynamic adjustment process provides unparalleled freedom in assigning words to any desired position, irrespective of potential overlaps. Furthermore, it eliminates the necessity of scaling words during the adjustment phase. This ingenious design choice maximizes the generator's flexibility, opening up boundless possibilities for customization. For a more detailed understanding of the algorithm, you can refer to the [Stuffing.jl - Algorithm Description](https://github.com/guo-yong-zhi/Stuffing.jl#algorithm-description).
Expand Down
6 changes: 3 additions & 3 deletions WordCloudApp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ else
end

# ╔═╡ 14666dc2-7ae4-4808-9db3-456eb26cd435
md"**text colors:** $(@bind colors_ Select([:auto; WordCloud.Schemes])) $(@bind colorstyle Select([:random, :gradient])) $(@bind glinting CheckBox(default=false))✨ [*Browse colorschemes*](https://juliagraphics.github.io/ColorSchemes.jl/stable/catalogue)"
md"**text colors:** $(@bind colors_ Select([:auto; WordCloud.COLOR_SCHEMES])) $(@bind colorstyle Select([:random, :gradient])) $(@bind glinting CheckBox(default=false))✨ [*Browse colorschemes*](https://juliagraphics.github.io/ColorSchemes.jl/stable/catalogue)"

# ╔═╡ 2870a2ee-aa99-48ec-a26d-fed7b040e6de
@bind go Button(" 🎲 Try again ! ")
Expand Down Expand Up @@ -282,7 +282,7 @@ begin
colors__ = colors_
if colorstyle == :gradient
if colors__ == :auto
colors__ = rand(WordCloud.Schemes)
colors__ = rand(WordCloud.COLOR_SCHEMES)
end
md"""
**gradient range:** $(@bind colorstart NumberField(0.:0.01:1., default=0.)) to $(@bind colorstop NumberField(0.:0.01:1., default=1.)). $wordsnum colors of $colors__
Expand All @@ -307,7 +307,7 @@ begin
colors = tuple(colors_vec...)
colors_vec
elseif colorstyle == :gradient
colors = WordCloud.gradient(words_weights[end], scheme=colors, section=(colorstart, max(colorstart, colorstop)))
colors = WordCloud.gradient(words_weights[end], colorscheme=colors, section=(colorstart, max(colorstart, colorstop)))
else
C
end
Expand Down
2 changes: 1 addition & 1 deletion examples/pattern.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#md# The [engine](https://github.com/guo-yong-zhi/Stuffing.jl) is designed for general purpose, so the outputs don't have to be text, and shapes are OK
using WordCloud

sc = WordCloud.randomscheme() |> unique # unique makes Int -> Vector{Int}
sc = WordCloud.randomcolorscheme() |> unique # unique makes Int -> Vector{Int}
l = 200
wc = wordcloud(
repeat(["placeholder"], l), repeat([1], l),
Expand Down
12 changes: 6 additions & 6 deletions examples/semantic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ words_weights = Dict(zip(words_weights...))
#md# The positions of words can be initialized with pre-trained word vectors so that similar words will appear near each other.
using Embeddings
using TSne
const embtable = load_embeddings(GloVe{:en})
const get_word_index = Dict(word => ii for (ii, word) in enumerate(embtable.vocab))
const EMB = load_embeddings(GloVe{:en})
const WORDS_INDICES = Dict(word => ii for (ii, word) in enumerate(EMB.vocab))
function get_embedding(word)
ind = get_word_index[word]
emb = embtable.embeddings[:,ind]
ind = WORDS_INDICES[word]
emb = EMB.embeddings[:,ind]
return emb
end
wordvec = Dict()
for k in keys(words_weights)
if k in keys(get_word_index)
if k in keys(WORDS_INDICES)
wordvec[k] = get_embedding(k)
elseif lowercase(k) in keys(get_word_index)
elseif lowercase(k) in keys(WORDS_INDICES)
wordvec[k] = get_embedding(lowercase(k))
else
pop!(words_weights, k)
Expand Down
72 changes: 37 additions & 35 deletions src/artist.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ using Random
import Fontconfig: list, Pattern, format
using StopWords

FontCandidates::Dict{String, Vector{String}} = Dict{String, Vector{String}}()
WeightCandidates::Vector{String} = ["", " Regular", " Normal", " Medium", " Bold", " Light"]
const FONT_NAMES::Dict{String, Vector{String}} = Dict{String, Vector{String}}()
const FONT_WEIGHTS::Vector{String} = ["", " Regular", " Normal", " Medium", " Bold", " Light"]

function listfonts(lang="")
if !isempty(lang)
Expand All @@ -23,14 +23,14 @@ function reverse_dict(d)
end
return rd
end
const id_part1 = reverse_dict(StopWords.part1_id)
const mid_iid = reverse_dict(StopWords.iid_mid)
const _ID_PART1 = reverse_dict(StopWords.part1_id)
const _MID_IID = reverse_dict(StopWords.iid_mid)
function expandlangcode(c)
c in StopWords.id_all || (c = get(StopWords.name_id, c, c))
c in StopWords.id_all || (c = get(StopWords.name_id, titlecase(c), c))
cs = []
for c1 in Iterators.flatten((get(mid_iid, c, []), [c]))
for c2 in Iterators.flatten((get(id_part1, c1, []), [c1]))
for c1 in Iterators.flatten((get(_MID_IID, c, []), [c]))
for c2 in Iterators.flatten((get(_ID_PART1, c1, []), [c1]))
push!(cs, c2)
end
end
Expand All @@ -41,12 +41,12 @@ function fontsof(lang)
end
function getfontcandidates(lang)
lang = StopWords.normcode(String(lang))
if haskey(FontCandidates, lang)
return FontCandidates[lang]
if haskey(FONT_NAMES, lang)
return FONT_NAMES[lang]
else
fs = fontsof(lang)
push!(fs, "")
FontCandidates[lang] = fs
FONT_NAMES[lang] = fs
return fs
end
end
Expand All @@ -57,37 +57,39 @@ end
Customize font candidates for language `lang`
"""
function setfontcandidates!(lang::AbstractString, str_list)
FontCandidates[StopWords.normcode(String(lang))] = str_list
FONT_NAMES[StopWords.normcode(String(lang))] = str_list
end

Schemes_colorbrewer = filter(s -> occursin("colorbrewer", colorschemes[s].category), collect(keys(colorschemes)))
Schemes_colorbrewer = filter(s -> (occursin("Accent", String(s))
|| occursin("Dark", String(s))
|| occursin("Paired", String(s))
|| occursin("Pastel", String(s))
|| occursin("Set", String(s))
|| occursin("Spectral", String(s))
), Schemes_colorbrewer)
Schemes_seaborn = filter(s -> occursin("seaborn", colorschemes[s].category), collect(keys(colorschemes)))
Schemes_tableau = filter(s -> occursin("tableau", colorschemes[s].category), collect(keys(colorschemes)))
Schemes_cvd = filter(s -> occursin("cvd", colorschemes[s].category), collect(keys(colorschemes)))
Schemes_gnuplot = filter(s -> occursin("gnuplot", colorschemes[s].category), collect(keys(colorschemes)))
Schemes_MetBrewer = filter(s -> occursin("MetBrewer", colorschemes[s].category), collect(keys(colorschemes)))
Schemes_general = [:bluegreenyellow, :cmyk, :darkrainbow, :deepsea, :dracula, :fall, :rainbow, :turbo]
Schemes = [Schemes_colorbrewer; Schemes_seaborn; Schemes_tableau; Schemes_cvd; Schemes_gnuplot; Schemes_MetBrewer; Schemes_general]

function getcolorschemes()
schemes_colorbrewer = filter(s -> occursin("colorbrewer", colorschemes[s].category), collect(keys(colorschemes)))
schemes_colorbrewer = filter(s -> (occursin("Accent", String(s))
|| occursin("Dark", String(s))
|| occursin("Paired", String(s))
|| occursin("Pastel", String(s))
|| occursin("Set", String(s))
|| occursin("Spectral", String(s))
), schemes_colorbrewer)
schemes_seaborn = filter(s -> occursin("seaborn", colorschemes[s].category), collect(keys(colorschemes)))
schemes_tableau = filter(s -> occursin("tableau", colorschemes[s].category), collect(keys(colorschemes)))
schemes_cvd = filter(s -> occursin("cvd", colorschemes[s].category), collect(keys(colorschemes)))
schemes_gnuplot = filter(s -> occursin("gnuplot", colorschemes[s].category), collect(keys(colorschemes)))
schemes_MetBrewer = filter(s -> occursin("MetBrewer", colorschemes[s].category), collect(keys(colorschemes)))
schemes_general = [:bluegreenyellow, :cmyk, :darkrainbow, :deepsea, :dracula, :fall, :rainbow, :turbo]
[schemes_colorbrewer; schemes_seaborn; schemes_tableau; schemes_cvd; schemes_gnuplot; schemes_MetBrewer; schemes_general]
end
const COLOR_SCHEMES = getcolorschemes()
function displayschemes()
for scheme in Schemes
for scheme in COLOR_SCHEMES
display(scheme)
colors = Render.colorschemes[scheme].colors
display(colors)
end
end
function gradient(weights_or_num; scheme=rand(Schemes), section=(0,1))
function gradient(weights_or_num; colorscheme=rand(COLOR_SCHEMES), section=(0,1))
@assert length(section) == 2
a,b = section
@assert a <= b
C = Render.colorschemes[scheme]
C = Render.colorschemes[colorscheme]
if weights_or_num isa Number
inds = range(a, b, length=max(2, weights_or_num))
else
Expand All @@ -102,9 +104,9 @@ function gradient(weights_or_num; scheme=rand(Schemes), section=(0,1))
end
return get.(Ref(C), inds)
end
function randomscheme(weights_or_num=100)
function randomcolorscheme(weights_or_num=100)
if rand() < 0.95
scheme = rand(Schemes)
scheme = rand(COLOR_SCHEMES)
C = Render.colorschemes[scheme]
if length(C) < 64 && rand() < 0.95
colors = randsubseq(C.colors, rand())
Expand All @@ -131,7 +133,7 @@ function randomscheme(weights_or_num=100)
a, b = round.(minmax(rand(), rand()), digits=3)
rand() < 0.2 && (a = 0.; b = 1.)
print(", random section: $a:$b")
colors = gradient(weights_or_num; scheme=scheme, section=(a,b))
colors = gradient(weights_or_num; colorscheme=scheme, section=(a,b))
end
end
if rand() > 0.5
Expand All @@ -147,7 +149,7 @@ function randomscheme(weights_or_num=100)
end
function randomfilteredscheme(args...; filter=colors->Gray(parsecolor(randommaskcolor(colors)))>0.5, maxiter=100)
for _ in 1:maxiter
colors = randomscheme(args...)
colors = randomcolorscheme(args...)
filter(colors) && return colors
end
@warn "randomfilteredscheme reach the `maxiter`."
Expand Down Expand Up @@ -354,10 +356,10 @@ randomoutline() = rand((0, 0, 0, rand(2:10)))
function randomfonts(lang="")
if rand() < 0.8
fonts = rand(getfontcandidates(lang))
fonts = fonts * rand(WeightCandidates)
fonts = fonts * rand(FONT_WEIGHTS)
else
fonts = rand(getfontcandidates(lang), 2 + floor(Int, 2randexp()))
fonts = [f * rand(WeightCandidates) for f in fonts]
fonts = [f * rand(FONT_WEIGHTS) for f in fonts]
rand() > 0.5 && (fonts = tuple(fonts...))
end
@show fonts
Expand Down
18 changes: 9 additions & 9 deletions src/textprocessing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@ function lemmatizer_eng(word)
return word
end
w = lowercase(word)
if w in s_ending_words || (length(word) <= 3 && w == word) || uppercase(word) == word
if w in S_ENDING_WORDS || (length(word) <= 3 && w == word) || uppercase(word) == word
return word
elseif endswith(w, "ies") && !(w[1:prevind(w, end, 1)] in xe_ending_words)
elseif endswith(w, "ies") && !(w[1:prevind(w, end, 1)] in XE_ENDING_WORDS)
return word[1:prevind(word, end, 3)] * "y"
elseif endswith(w, "ses")
wh = w[1:prevind(w, end, 2)]
if wh in s_ending_words || endswith(wh, "ss")
if wh in S_ENDING_WORDS || endswith(wh, "ss")
return word[1:prevind(word, end, 2)]
end
elseif endswith(w, r"xes|ches|shes|oes") && !(w[1:prevind(w, end, 1)] in xe_ending_words)
elseif endswith(w, r"xes|ches|shes|oes") && !(w[1:prevind(w, end, 1)] in XE_ENDING_WORDS)
return word[1:prevind(word, end, 2)]
elseif endswith(w, "ves")
wh = w[1:prevind(w, end, 3)]
wordh = word[1:prevind(word, end, 3)]
if wh * "fe" in f_ending_words
if wh * "fe" in F_ENDING_WORDS
return wordh * "fe"
elseif wh * "f" in f_ending_words
elseif wh * "f" in F_ENDING_WORDS
return wordh * "f"
end
end
Expand Down Expand Up @@ -56,12 +56,12 @@ function tokenizer_eng(text::AbstractString, regexp=r"\w[\w']*")
end

# ISO 639-3 macrolanguages
STOPWORDS = stopwords
TOKENIZERS = Dict(
const STOPWORDS = stopwords
const TOKENIZERS = Dict(
"_default_" => tokenizer,
"eng" => tokenizer_eng,
)
LEMMATIZERS = Dict(
const LEMMATIZERS = Dict(
"_default_" => identity,
"eng" => lemmatizer_eng,
)
Expand Down
42 changes: 21 additions & 21 deletions src/wc-class.jl
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ function processscheme(words, weights; colors=:auto, angles=:auto, fonts=:auto,
maskcolor0 = maskcolor
backgroundcolor0 = backgroundcolor

colors in DEFAULTSYMBOLS && (colors = randomscheme(weights))
colors in DEFAULTSYMBOLS && (colors = randomcolorscheme(weights))
angles in DEFAULTSYMBOLS && (angles = randomangles())
fonts in DEFAULTSYMBOLS && (language = detect_language(words, language); fonts = randomfonts(language))
colors isa Symbol && (colors = (colorschemes[colors].colors...,))
Expand Down Expand Up @@ -347,20 +347,20 @@ index(wc::WC, i) = i
getparameter(wc, args...) = getindex(wc.params, args...)
setparameter!(wc, args...) = setindex!(wc.params, args...)
hasparameter(wc, args...) = haskey(wc.params, args...)
getdoc = "This function accepts two positional arguments: a wordcloud object and an index. The index can be a string, number, list, or any other supported type of index. The index argument is optional, and omitting it will retrieve all the values."
setdoc = "This function accepts three positional arguments: a wordcloud object, an index, and a value. The index can be a string, number, list, or any other supported type of index."
@doc getdoc getcolors(wc::WC, w=:) = wc.params[:colors][index(wc, w)]
@doc getdoc getangles(wc::WC, w=:) = wc.params[:angles][index(wc, w)]
@doc getdoc getfonts(wc::WC, w=:) = wc.params[:fonts][index(wc, w)]
@doc getdoc getwords(wc::WC, w=:) = wc.words[index(wc, w)]
@doc getdoc getweights(wc::WC, w=:) = wc.weights[index(wc, w)]
@doc setdoc setcolors!(wc::WC, w, c) = @view(wc.params[:colors][index(wc, w)]) .= parsecolor(c)
@doc setdoc setangles!(wc::WC, w, a::Union{Number,AbstractVector{<:Number}}) = @view(wc.params[:angles][index(wc, w)]) .= a
@doc setdoc
const _GET_DOC = "This function accepts two positional arguments: a wordcloud object and an index. The index can be a string, number, list, or any other supported type of index. The index argument is optional, and omitting it will retrieve all the values."
const _SET_DOC = "This function accepts three positional arguments: a wordcloud object, an index, and a value. The index can be a string, number, list, or any other supported type of index."
@doc _GET_DOC getcolors(wc::WC, w=:) = wc.params[:colors][index(wc, w)]
@doc _GET_DOC getangles(wc::WC, w=:) = wc.params[:angles][index(wc, w)]
@doc _GET_DOC getfonts(wc::WC, w=:) = wc.params[:fonts][index(wc, w)]
@doc _GET_DOC getwords(wc::WC, w=:) = wc.words[index(wc, w)]
@doc _GET_DOC getweights(wc::WC, w=:) = wc.weights[index(wc, w)]
@doc _SET_DOC setcolors!(wc::WC, w, c) = @view(wc.params[:colors][index(wc, w)]) .= parsecolor(c)
@doc _SET_DOC setangles!(wc::WC, w, a::Union{Number,AbstractVector{<:Number}}) = @view(wc.params[:angles][index(wc, w)]) .= a
@doc _SET_DOC
function setfonts!(wc::WC, w, v::Union{AbstractString,AbstractVector{<:AbstractString}})
@view(wc.params[:fonts][index(wc, w)]) .= v
end
@doc setdoc
@doc _SET_DOC
function setwords!(wc::WC, w, v::Union{AbstractString,AbstractVector{<:AbstractString}})
m = word2index(wc)
@assert !any(v .∈ Ref(keys(m)))
Expand All @@ -369,24 +369,24 @@ function setwords!(wc::WC, w, v::Union{AbstractString,AbstractVector{<:AbstractS
@view(wc.words[i]) .= v
v
end
@doc setdoc setweights!(wc::WC, w, v::Union{Number,AbstractVector{<:Number}}) = @view(wc.weights[index(wc, w)]) .= v
@doc getdoc getimages(wc::WC, w=:) = wc.imgs[index(wc, w)]
@doc getdoc getsvgimages(wc::WC, w=:) = wc.svgs[index(wc, w)]
@doc _SET_DOC setweights!(wc::WC, w, v::Union{Number,AbstractVector{<:Number}}) = @view(wc.weights[index(wc, w)]) .= v
@doc _GET_DOC getimages(wc::WC, w=:) = wc.imgs[index(wc, w)]
@doc _GET_DOC getsvgimages(wc::WC, w=:) = wc.svgs[index(wc, w)]

@doc setdoc
@doc _SET_DOC
function setimages!(wc::WC, w, v::AbstractMatrix)
@view(wc.imgs[index(wc, w)]) .= Ref(v)
initqtree!(wc, w)
v
end
setimages!(wc::WC, w, v::AbstractVector) = setimages!.(wc, index(wc, w), v)
@doc setdoc
@doc _SET_DOC
function setsvgimages!(wc::WC, w, v)
@view(wc.svgs[index(wc, w)]) .= v
setimages!(wc::WC, w, tobitmap.(v))
end

@doc getdoc
@doc _GET_DOC
function getfontsizes(wc::WC, w=:)
inds = index(wc, w)
ids = wordids(wc, inds)
Expand All @@ -399,7 +399,7 @@ function getfontsizes(wc::WC, w=:)
end
end
end
@doc setdoc
@doc _SET_DOC
function setfontsizes!(wc::WC, w, v::Union{Number,AbstractVector{<:Number}})
push!.(Ref(wc.params[:custom][:fontsize]), wordids(wc, w) .=> v)
end
Expand All @@ -411,12 +411,12 @@ function getbackgroundcolor(wc::WC)
c == :maskcolor ? getmaskcolor(wc) : c
end
setbackgroundcolor!(wc::WC, v) = (setparameter!(wc, v, :backgroundcolor); v)
@doc getdoc * " The keyword argument `mode` can be either `getshift` or `getcenter`."
@doc _GET_DOC * " The keyword argument `mode` can be either `getshift` or `getcenter`."
function getpositions(wc::WC, w=:; mode=getshift)
Stuffing.getpositions(wc.maskqtree, wc.qtrees, index(wc, w), mode=mode)
end

@doc setdoc * " The keyword argument `mode` can be either `setshift!` or `setcenter!`."
@doc _SET_DOC * " The keyword argument `mode` can be either `setshift!` or `setcenter!`."
function setpositions!(wc::WC, w, x_y; mode=setshift!)
Stuffing.setpositions!(wc.maskqtree, wc.qtrees, index(wc, w), x_y, mode=mode)
end
Expand Down
12 changes: 6 additions & 6 deletions src/wc-helper.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Colors
DEFAULTSYMBOLS = [:original, :auto, :default]
const DEFAULTSYMBOLS = [:original, :auto, :default]
iter_expand(e) = Base.Iterators.repeated(e)
iter_expand(l::Vector) = Base.Iterators.cycle(l)
iter_expand(r::AbstractRange) = IterGen(st->rand(r))
Expand Down Expand Up @@ -218,11 +218,11 @@ function configsvgimages!(wc, w=:, args...; children=nothing, wrappers=nothing)
end
runexample(example=:random) = @time evalfile(pkgdir(WordCloud)*"/examples/$(example).jl")
showexample(example=:random) = read(pkgdir(WordCloud)*"/examples/$(example).jl", String)|>print
examples = [e[1:prevind(e, end, 3)] for e in basename.(readdir(pkgdir(WordCloud)*"/examples")) if endswith(e, ".jl")]
exampledoc = "Available values: [" * join(":".*examples, ", ") * "]"
@doc exampledoc runexample
@doc exampledoc showexample
function runexamples(examples=examples)
const EXAMPLES = [e[1:prevind(e, end, 3)] for e in basename.(readdir(pkgdir(WordCloud)*"/examples")) if endswith(e, ".jl")]
const _EXAMPLE_DOC = "Available values: [" * join(":" .* EXAMPLES, ", ") * "]"
@doc _EXAMPLE_DOC runexample
@doc _EXAMPLE_DOC showexample
function runexamples(examples=EXAMPLES)
println(length(examples), " examples: ", examples)
for (i,e) in enumerate(examples)
println("="^20, "\n# ",i,"/",length(examples), "\t", e, "\n", "="^20)
Expand Down
Loading

0 comments on commit 08c4801

Please sign in to comment.