ワードクラウドを自作する①

C#でWordCloudを自作する①

WordCloudを自作する

以前、C#でスクレイピングと形態素解析を行うプログラムを自作してきましたが、今回はこれらのプログラムで収集したデータを活用するべくワードクラウドを自作しようと思います。
スクレイピング同様にWordCloudをするならPythonって感じがしますが、私はやっぱりC#で作成したい!!
ということで、C#でWordCloudを自作しようと思います。ちなみにライブラリを使用するのではなく、1から自分で作るつもりでいます。


作るイメージ

WordCloudを作るイメージとしては、まず単語の個数が多ければ字を大きくする。そして色々なところに単語を配置する。これらを描画するためのBitmapを使用する感じで行きたいと思います。

  • 描画用のBitmapを用意する
  • 単語を描画するための土台としてBitmapを使用します。
    そして字を描画するためにGraphicsDrawStringを使って図を作成します。
    このあたりはまだ知識不足で、もっと良い方法などあれば教えていただきたいです。

     Bitmap img = new Bitmap(400, 200);
     Graphics g = Graphics.FromImage(img);
                        

  • 頻度に応じて字を大きくする
  • 今回は試作として頻度の多い上位10個を描画します。データ自体は単語と個数を保持しているListで管理しているため、事前に文字の大きさを決めておけば、総数に対する比率をかけることで単語の大きさを調整することが可能になります。
    比率計算と文字サイズの計算は次のようになります。

     double ratio = (double)aggregate.Count / (double)_maxCount;
     int size = (int)Math.Round(200 * ratio);
                        

  • 色々な位置に字を配置する
  • DrawStringメソッドで描画する座標を指定しますが、この値を乱数を使ってランダムな位置に描画する方針とします。文字色は青で描画します。
    なお、枠外に描画する可能性もあるので、一旦Bitmapの縦横より小さい値を乱数の最大値として求めます。

     style="border: 1px solid #333333;"
     g.DrawString(aggregate.Word, new Font(font, size), Brushes.Blue, rnd.Next(0, width-30), rnd.Next(0, height-30));
                        

ということで上記3点を考慮し、引数に単語と個数を保有するクラスAggregateと総数を引数としたメソッドを作成します。
 private void DrawWord(AggregateData aggregate, int _maxCount)
 {
    double ratio = (double)aggregate.Count / (double)_maxCount;
    int size = (int)Math.Round(200 * ratio);
    g.DrawString(aggregate.Word, new Font(font, size), Brushes.Blue, rnd.Next(0, width-30), rnd.Next(0, height-30));
 }
        
そして、このメソッドを呼び出すためのメソッドを作成します。
このメソッドでは、単語の総数を計算、それぞれの単語を描画するDrawWordメソッドを呼び出し、最後に画像として保存する処理を行っています。
 public void MakeImg(List<AggregateData> _list)
 {
    g.FillRectangle(Brushes.White, g.VisibleClipBounds);

    int maxCount = 0;
    foreach(AggregateData data in _list)
    {
        maxCount += data.Count;
    }

    foreach(AggregateData data in _list)
    {
        DrawWord(data, maxCount);
    }

    img.Save(@"指定のパス");
 }
        
これらのメソッドなどを利用し出来上がったのでが次の画像です。
うーん、これじゃない感。。。


現状の課題

現状の課題としては、

  • 描画した文字が重なってしまう
  • 画面外に描画してしまうことがある
が挙げられます。
後者の課題に関しては、描画する単語の大きさ、文字数などからどのくらいの範囲で描画するのかを判断し、乱数を調整することで解決できると思います。
しかし、前者の課題に関しては、正直どう解決するかは考え中です。本当のWordCloudですと隙間なく文字を描画しているため、文字が重ならないだけでなく、文字の隙間などにも描画しています。さすがに文字の隙間に描画する仕組みは難しいと思われるので、せめて重ならないように描画するようにはしたいと思います。
そのためにはBitmapに関する知識が必要になると思いますが、勉強が必要ですね。。。


まとめ

ということで今回はWordCloudを自作しました。自作したと言っても課題はまだ多い状態ですが、、、
ちなみにコードはこちらです。
なんとなく「こうしようかな」という構想はあるのでそれをどう実現するか、あとはBitmapをどう学ぶかですね。ある程度課題が解決できたらまた記事を書きたいと思います。
今回はこの辺で、ではまた!!

コメント

このブログの人気の投稿

PowerAppsで座席表を作成する

Power AutomateでTeamsのキーワードをトリガーにする

Power Automateで文字列抽出