ujimushi(@旧sradjp(15364))の日記

旧スラドの日記の引越先です

Plots.jlのGRバックエンド用フォントパッチ(Windows用)

Julia言語のPlotsのGRバックエンドでttcフォントを使う方法とかを記事として挙げていたけど legend_font_family(Plots.jl(GR))のようにフォント名一覧が取れることが分かって

これって普通にWarningなしにできなくない?

ということで,実装してみた。今回はWindows用。

# plots_gr_font_patch_for_windows.jl
using Plots

@eval Plots begin
    function gr_custom_fontlist_windows()
        fontfilenames = [
            readdir(joinpath(ENV["LOCALAPPDATA"], "microsoft", "windows", "fonts"));
            readdir(joinpath(ENV["SYSTEMROOT"], "fonts"))
        ]
        fnames = filter(x -> endswith(x, r"[.](ttf|ttc|otf)"), fontfilenames)
        Dict([(chopsuffix(f, r"[.](ttf|ttc|otf)") , f) for f in fnames])
    end

    """
        パッチで指定可能なフォント名 => ファイル名の辞書型

    `"フォント名" in keys(Plots.gr_custom_fontlist)`
    でフォントが選択可能か分かる
    """
    const gr_custom_fontlist = gr_custom_fontlist_windows()
    
    function gr_set_font(
        f::Font, s; halign = f.halign, valign = f.valign, color = f.color,
        rotation = f.rotation,)
        family = lowercase(f.family)
        GR.setcharheight(gr_point_mult(s) * f.pointsize)
        GR.setcharup(sincosd(-rotation)...)
        if !haskey(gr_font_family, family)
            # この辺を変更
            gr_font_family[family] = GR.loadfont(gr_custom_fontlist[f.family])
        end
        haskey(gr_font_family, family) && GR.settextfontprec(
            gr_font_family[family],
            gr_font_family[family]  200 ? 3 : GR.TEXT_PRECISION_STRING,
        )
        gr_set_textcolor(plot_color(color))
        GR.settextalign(gr_haligns[halign], gr_valigns[valign])
        nothing
    end
end

特にレイアウトを気にしない時にはあまり脳みそを使わないで GUIっぽいもの作れるBlink.jl+Interact.jlの組み合わせで例を作ってみた。

using Plots
using Blink
using Interact

include("plots_gr_font_patch_for_windows.jl")

function my_plot(fontname)
    plot(sin; title="日本語のタイトル", titlefontfamily=fontname)
end

function real_main()
    fontnames = sort([fontname for fontname
                          in keys(Plots.gr_custom_fontlist)])
    
    menu = dropdown(fontnames; value="msgothic")
    win =Window(Dict(:width => 800, :height => 600,
                     :defaultEncoding=>"utf-8"))
    plt = map(my_plot, menu)
    ui = vbox(menu, plt)
    body!(win, ui)
    win
end

function julia_main()::Cint
    win = real_main()
    while Blink.AtomShell.active(win)
        sleep(1)
        yield()
    end
    return 0
end

Linuxでも出来そうなので,次の投稿で紹介できれば。

追記の注意

実はこのパッチを利用すると,GRで使用可能な標準フォントとOSにインストールされていないフォント名を指定すると エラーで落ちるようになっているので注意が必要です。

julia> include("plots_gr_font_patch_for_windows.jl")
gr_set_font (generic function with 1 method)

julia> plot(sin; title="日本語", titlefontfamily="hogehoge")
Error showing value of type Plots.Plot{Plots.GRBackend}:
ERROR: KeyError: key "hogehoge" not found
Stacktrace:
-----以上略 -----

"フォント名" in keys(Plots.gr_custom_fontlist)trueが出ることを確認してから使って下さい。