以下の内容はhttps://memorandums.hatenablog.com/entry/2024/11/06/213123より取得しました。


ganttplot.jsを作ったったん

githubのREADME.mdにも書いたんだけど、こっちも書いておく。あ、ちなみにリポジトリは以下。

github.com

10年以上前の研究で論文にガントチャートを入れる必要があったんだけど適当なものがなくてどうしたものか。。。と思ったことがあった。そのときにどうやって見つけたのかわからないけど、以下のサイトにあったPythonのコードがあったので使わせてもらったことがあった。インターネットアーカイブのお陰でかろうじてサイトは見れたけどコードはなかったorz

web.archive.org

その頃の研究データを利用しようとバックアップデータを探したものの研究データはEvernoteにメモしていたらしく、Evernoteはnotionに移行したときにどこかに行ってしまい。。。再度、ガントチャートを書こうにもどうしようもならなくなった。

ググってみたら、その当時のコードをクローンした人がいた!

ただ、その方のコードも既に10年前になっていて。。。動かそうとしたけどPython2系でダルい感じになってしまった。それでも頑張ってpyenvでPython2をいれて動作させるところまでは行ったんだけど。。。今後、もし、これが必要になったらもうPython2とか動作するマシンがないかもしれないと思ったわけ。

とりあえずJSに移植しておけば当面は大丈夫だろうと思い、今朝からやり始めてなんとか昼くらいに移植が終わった。HTMLをつけてそれっぽくサイトにした。完全に自分専用のプログラムになっているんだけど、まぁ、ガントチャートを作りたいと思えば一つの手になるかなと思う。mermaidとかもありそうだけどね。

とりあえず日本人に興味がある人はほとんどいないだろうから、下手な英語でREADME.mdと動画をつけておいた。世界中だと1人くらいは役立つと言ってくれる人がいると思うので。

移植したときに最初から作り直す時間がもったいなかったのでもともとのPythonのコードをできるだけ使用した。移植したときにPythonっぽいコードをJSでどうやって実現したらいいか。。。で結構勉強になった。いくつかメモしておく。

これ何ていうんですかね?後置for文?便利ですね〜。ループ構造をしながら結果を代入できるというやつ。

    ytics = ''.join(['(',
                     ', '.join(('"%s" %d' % item)
                                for item in resource_map.iteritems()),
                     ')'])

これJSにはないので。。。ChatGPTの力を借りて以下にしました。可読性は低いですねぇ〜。素直に書いた方がよさそう。

    const ytics = `( ${Object.keys(resource_map).map(e => `"${e}" ${resource_map[e]}`).join(",")} )`;

以下も上記と同様のケースですね。後置for文?

    # Generate gnuplot rectangle objects
    plot_rectangles = (' '.join(['set object %d rectangle' % n,
                                 'from %f, %0.1f' % r.bottomleft,
                                 'to %f, %0.1f' % r.topright,
                                 'fillcolor %s %s' % (color_book.prefix,
                                                      r.fillcolor),
                                 'fillstyle solid 0.8'])
                    for n, r in itertools.izip(itertools.count(1), rectangles))

mapで実装しました。

    // Generate gnuplot rectangle objects
    const plot_rectangles = rectangles.map((r, index) => 
        [`set object ${index + 1} rectangle`,
            `from ${r.bottomleft[0]}, ${r.bottomleft[1]}`,
            `to ${r.topright[0]}, ${r.topright[1]}`,
            `fillcolor ${color_book.prefix} ${r.fillcolor}`,
            'fillstyle solid 0.8'].join(" "));

あと、Pythonにはタプルがあるので以下のように書けますが。

    return plot_dimensions, plot_rectangles, plot_lines, plot_labels

JSにはない(なくはないらしいが)ので、以下のようにArrayで返してArrayで受ける方式にしました。

    return [plot_dimensions, plot_rectangles, plot_lines, plot_labels];

ちなみに受ける側は以下です。この配列受取の場合の変数のスコープってどうなるんですかねぇ?グローバルとかになったら嫌ですねぇ。。。

    [plot_dims, plot_rects, plot_lines, plot_labels] = 
            generate_plotdata(activities, resources, tasks, rectangles, resource_map, color_book)

あと、もう1つ。Pythonでは以下のように書けます。activitiesオブジェクト配列に入っている要素を取り出してそのオブジェクトのstop(終了時刻)の最大値を取得しようということです。Pythonでは非常にクリアに書けますね。

        xmax = max(act.stop for act in activities)

これはJSでやろうとしたら。。。reduceとか使うのかなと思ったけどうまく動作しませんでした。結局、以下のやり方になりました。スプレッド構文っていうんですかね?使ったことないですが。。。

    const xmax = Math.max(...activities.map(item => item.stop));

という感じでした。片手間でやる程度なので新しい技術にはついていけていませんが。。。

意外とこの言語でこうだったけどこの言語だったらどうやって実装するんだろう?と考えるのはなかなかいいトレーニングになるなぁと思いました。あ、たぶん、Javascriptで実装しようとしたらもっとシンプルなやり方があるだろうなと思いますけどねぇ。日本語を英語に直訳しているような変な感じが残ってしまうのが移植の難しさかなと思います。

あぁ、もう9時半。帰ったら11時か。。。何してるんだか。帰ろう。




以上の内容はhttps://memorandums.hatenablog.com/entry/2024/11/06/213123より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14