技術屋にゃん兵衛のてくてくらぼ by データウィズ [DataWith]

気の向くままソフトについて書いてます。バリバリエンジニアではないのであくまでも初心者目線で。

Wolfram EngineをVisualBasicで使う(8:化学構造式の描画)

Wolfram EngineをVisualBasicで使う(8:化学構造式の描画)

 

今回は化学構造式を描画してみようと思います。

これはグラフの表示と同じでとっても簡単。

 

  1. これまで何度も使ってきたフォームで。TexBox1、Button1、PictureBox1です。

    GUIのレイアウト
  2. コードはグラフを書いた時と全く同じ。

    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     

            Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

            ml.WaitAndDiscardAnswer()

     

           Dim result As Image = ml.EvaluateToImage(TextBox1.Text, 200, 200)

            PictureBox1.Image = result

     

        End Sub

    End Class

  3. まずは、化学の分野でよくつかわれるSMILES(スマイルス)形式で書かれた分子を書いてみます。

    MoleculePlot[Molecule["CN1C=NC2=C1C(=O)N(C(=O)N2C)C"]]

    SMILESをWolfram Languageの関数に渡す
  4. 実行すると。正しくカフェインが描画されました!

    分子構造が表示された
  5. Wolfram Languageのドキュメントでは「Molecule」では、「体系的な化学名」も使えると書かれています。これは「IUPAK命名法」も受け付けるということです。なので、今度はカフェインのIUPAK名を入れてみます。

    MoleculePlot[Molecule["1,3,7-Trimethylpurine-2,6-dione"]]

    なんとなく向きが違いますが、同じ結果が出ました。

    IUPAK名で指定したときの表示
  6. 分子を表現する関数にはもうひとつ、「MoleculePlot3D」というのがあります。使い方は全く同じです。

    MoleculePlot3D[Molecule["CN1C=NC2=C1C(=O)N(C(=O)N2C)C"]]

    3Dでの分子の表示
  7. プロットの描画方法も指定することができます。

    MoleculePlot3D[Molecule["CN1C=NC2=C1C(=O)N(C(=O)N2C)C"], PlotTheme->”SpaceFilling”]

    のようすると、次のように描画できます。

    別の表示の形式

 

短いですが、今日はここまで。

 

Wolfram EngineをVisualBasicで使う(7:画像ファイルの処理)

Wolfram EngineをVisualBasicで使う(7:画像ファイルの処理)

 

今回は画像ファイルを処理してみようと思います。

次の2つが思いつきました。

a.VisualBasic側で画像ファイルを読み込んでWolfram Engineに渡す

b.VisualBasic側は画像表示のみとして、Wolfram Language側で画像ファイルを読み込む

 

KernelLinkのクラスを見ると「evaluate***」関数には文字列を渡すものが多く、画像のバイナリを渡すのは面倒そうなので、まずは、bの方法から試してみることにしました。

 

  1. まずは、GUIを次のようにしました。

    GUIデザインを調整

    それぞれ、TextBox1、Button1、PictureBox1です。

  2. 画像の読み込みなどは、Wolfram Language側でするので、コードはいたって簡単。

    画像の読み込みなどは、Wolfram Language側でするので、コードはいたって簡単。

    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     

            Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

            ml.WaitAndDiscardAnswer()

     

            Dim result As Image = ml.EvaluateToImage(TextBox1.Text, 200, 200)

            PictureBox1.Image = result

     

        End Sub

    End Class

     

  3. 起動します。画像は「C:\data\rose.png」にあるとして、テキストボックスに次のように入力します。Wolfram Languageでは、パスには「/」を使うことに注意。「\」ではエラーになります。

    Import[“C:/data/rose.png”]

    Wolfram Language の入力

     

  4. 「Evaluate」をクリックすると、次のようになります。ただしく、読み込まれています。

    正しく画像が読み込まれた
  5. Wolfram Languageがそのまま処理されるので、画像処理も行えます。テキストボックスに次のように入力してみます。

    img = Import["C:/data/rose.png"]

    EdgeDetect[img]

    輪郭抽出の関数を適用した結果

 

おお、簡単。VisualBasicで輪郭抽出をしようとするとかなり面倒ですが、Wolfram Engineはこういうときには便利かも。

 

出力が画像の時は、関数を入れ替えていけばそれなりに範囲が広がります。

次にWolfram Languageの画像処理関数で、画像の認識をやってみようと思います。これは、Wolfram Researchに接続してデータをやり取りするので、ネットワーク環境が必要です。

 

  1. 認識した後は、単語が出力されるのでGUIを次のようにしてみました。今回はPictureBoxは使いません。

    GUIデザインを変更
  2. 出力は文字列になるので、コードを次のように変更します。

    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     

            Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

            ml.WaitAndDiscardAnswer()

     

            Dim result As String = ml.EvaluateToOutputForm(TextBox1.Text, 0)

            TextBox2.Text = result

     

        End Sub

    End Class

  3. さてやってみます。画像を認識するWolfram Languageの関数は「ImageIdentity」です。

    ImageIdentifyを記述
  4. そうか。ドキュメントセンターにおもいきり、「デフォルトで,ImageIdentifyEntity["Concept",…]の形式のオブジェクトを返す.」と書いてありました。

    ImageIdentifyの結果1
  5. ということで、Entityから文字を取り出す行を追加しました。

    img = Import["C:/data/rose.png"]

    entity = ImageIdentify[img]

    entity["Name"]

    ImageIdentifyの結果2

    うまく返ってきました。

  6. 別の画像でも試してみます。次の画像ファイルを認識させてみます(画像は何年か前のドイツでの私の夕食)。

    その他の画像を認識させてみる


  7. その結果は。「fish and chips」。実際には、チキンなのと、チップスもないですが。このあたりは辞書の関係ですね。結果としては、まあいいですね。

    認識の結果(料理は難しいか。。。)


ということで、ここまで。

Wolfram EngineをVisualBasicで使う(6:オンラインリソースって使えるの?)

Wolfram EngineをVisualBasicで使う(6:オンラインリソースって使えるの?)

 

これまでは、普通の数式処理システム的な動きを確認しました。

しかし、こういうレベルは最近はPythonでもGUI付きでできるし、あえてWolfram Engineでやるのは、「好きでないと」という風になってしまいます。

 

Wolframのエンジンの特徴を生かすには、Wolfram Researchがこの何年か推してきたものを使ってみないと、ということで、今回はWolframのオンラインリソースのような情報が得られるのか検証します。

MathematicaでWolfram のオンラインリソースを使うには、データのダウンロードのためにインターネット接続が必要なので、今回も繋げた状態で始めます。

 

Wolfram言語ではエンティティ(実体)、「物理的に存在するもの」って感じ?、という呼び方をします。

 

  1. 今まで作成したプログラムを実行して、

    CountryData[“Japan”, “Population”]

    と入れてみました。
    後ろで、なんかディスクがごそごそやって、その結果は、、、

    Wolfram言語の入力


    きっちり動く。
  2. 単なる文字列っぽいものだといけそうなので、ドキュメントセンターの次の例を入力してみました。("Gettysburg Address"とは、アメリカの南北戦争の時に当時の大統領、リンカーンがペンシルバニア州ゲティスバーグで行った演説)

    ResourceData["Gettysburg Address"] // Snippet

    オンラインリソースの取得結果

出力部分が小さいので、わかりにくいですが、

Four score and seven years ago, our fathers brought forth upon this continent a

と返ってきてました。

 

GUIをもっと整えれば、それなりかな。

 

Wolfram EngineをVisualBasicで使う(5:グラフィックスの対応範囲を広げる)

Wolfram EngineをVisualBasicで使う(5:グラフィックスの対応範囲を広げる)

 

前回のGraphics3D関数に対応せるとと同時に、他のグラフ系の関数の対応を増やすことにしました。

関数名に共通した文字列を判断するようにIf文を拡張します。

Wlfram Researchのドキュメントセンターからめぼしい関数名をピックアップすると…

 

「データの可視化」セクション

ListPlot

ListLinePlot

ListStepPlot

StackedListPlot

ListPlot3D

ListPointPlot3D

ListDensityPlot

ListLogLinerPlot

ListLogLogPlot

ListPolarPlt

MatrixPlot

ParallelAxisPlot

などなど。共通部分は「Plot」なので、”*Plot*”とすれば、「Histgram」以外はほぼ拾えそう。

もちろん、今回は関数のプロットを想定しているので、棒グラフ「BarChart」や円グラフ「PieChart」などは含まれない。

 

「関数の可視化」セクション

Plot

LogPlot

Plot3D

ContourPlot

ContourPlot3D

DensityPlot

DensityPlot3D

ParametricPlot

PolarPlot

RegionPlot

ComplexPlot

DiscretePlot

などなど。これらも”*Plot*”で吸収できる。

前回のような”Sphere”のようなものは少し特殊なケースだが、”*2D*”と”*3D*”も判断すればかなり範囲が広がりそう。

 

ということで、

  1. If文に条件を追加します。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

        ml.WaitAndDiscardAnswer()

     

        Dim strarg As String = TextBox2.Text

        If strarg Like "*Plot*" Or strarg Like "*2D*" Or strarg Like "*3D*" Then

            Dim result As Image = ml.EvaluateToImage(strarg, 200, 200)

            PictureBox1.Image = result

        Else

            Dim result As String = ml.EvaluateToOutputForm(strarg, 0)

            TextBox1.Text = result

        End If

    End Sub

    のようにします。

  2. 実行して、

    Graphics3D[Sphere[{0, 0, 0}]]

    を入力すると、「Graphics3D」の「3D」の部分が拾われて、次のような結果となりました。OK!

    Sphereが表示された

    Mathematicaでは、1つの関数の記述でグラフを横に並べて表示したりできるので、今回のプログラムでも実行できるか試してみました。

  3. ドキュメントセンターの「VectorPlot」のページの

    VectorPlot[{{x + y, y - x}, {y, x + y}}, {x, -3, 3}, {y, -3, 3}, PlotLayout -> "Row"]

    を入力してみます。

    ベクタープロットの表示(一部)


    画像領域に収まらなかった。

  4. GUIのデザインでPictureBoxを横に広げて、

    Dim result As Image = ml.EvaluateToImage(strarg, 400, 200)

    のように横長にして、再実行。

    ベクタープロットを横に並べて表示

 

まだまだ見栄えの調整の余地はありますが、Wolfram言語内で複数並べて実行できることは確認できました。

 

今回はページ稼ぎでスミマセン。。。

Wolfram EngineをVisualBasicで使う(4:入力により結果を数字とグラフで切り替える)

Wolfram EngineをVisualBasicで使う(4:入力により結果を数字とグラフで切り替える)

 

前回までは、数式の場合は数式だけ、グラフの場合はグラフだけ、だったので、今日は自動で切り替えられるようにしました。

あと、何回も実行すると前のものが残るので、クリアボタンを付けました。

 

  1. デザインエディターでラベルやボックスを下のように調節して、新しいボタン「Clear result」を追加しました。

    デザイン変更とボタンの追加
  2. まずは、「Evaluate」ボタンの動きを変えます。If文でテキストボックスの文字列が「Plot」が含まれるかどうかで、数式(文字)として出力するか、グラフ(画像)として出力するかを分岐します。文字だった場合は、文字列としてテキストボックスに出力し、グラフだった場合には画像ボックスにグラフを出力します。

     

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

        ml.WaitAndDiscardAnswer()

        Dim strarg As String = TextBox2.Text

        If strarg Like "*Plot*" Then

            Dim result As Image = ml.EvaluateToImage(strarg, 200, 200)

            PictureBox1.Image = result

        Else

            Dim result As String = ml.EvaluateToOutputForm(strarg, 0)

            TextBox1.Text = result

        End If

    End Sub

  3. 次に「Clear result」ボタンの動きです。テキストボックス2つと画像ボックス1つの内容を消します。

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        TextBox1.Text = Nothing

        TextBox2.Text = Nothing

        PictureBox1.Image = Nothing

    End Sub

  4. さて実行してみます。

  5. まずは数式。

    Expand[(x + 3)(x + 2)]

    とすると、結果は次の通り、正解。

    数式の処理
  6. 「Clear result」をクリックすると、入力と出力がクリアされます。
  7. 次はグラフ。Wolframのドキュメントセンターから次をピックアップしました。

    ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}]

    その結果は、

    グラフの描画

 

いい感じに動きました。もちろん、これも「Clear result」でクリアできます。

 

しかしこれには問題が、、、

Graphics3D[Sphere[{0, 0, 0}]]

は、球体のグラフィックスを変えるものです。これには「Plot」という文字がないので、その結果は、

Sphere3Dの場合

この対応は次回。

短いですが、今日はここまで。

Wolfram EngineをVisualBasicで使う(3:グラフを表示してみる)

Wolfram EngineをVisualBasicで使う(3:グラフを表示してみる)

 

今回は、グラフを表示してみたい。

実際やってみたところ、簡単なものであればそれほど手間はかからないことが分かった。

 

前回のコードをそのまま流用します。

 

  1. レイアウトに「PictureBox」を追加します。画面の左下のテキストボックス「TextBox1」は今回は使わないので、端によけておきます。

    画像のエリアを配置
  2. コードを次のように書き換えます。

     

    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     

            Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

            ml.WaitAndDiscardAnswer()

     

            Dim result As Image = ml.EvaluateToImage(TextBox2.Text, 200, 200)

            PictureBox1.Image = result

     

        End Sub

    End Class

     

    Wolfram Kernelで画像を生成するときには、「EvaluateToImage()」を使います。出力はbyte[]になるので、VisualBasicでは「Image」として定義します。

    この「Image」を「PictureBox」の「Image」に代入すればいいです。

    200px x 200px で画像を出力することにします。

  3. 起動して、テキストボックスに

    Plot[Sin[x], {x, 0, 6 Pi}]

    と入力し、「Evaluate」をクリックします。

    画像の時には、表示間で少し時間がかかります。

    グラフが表示された
  4. グリッド線と凡例を入れてみます。

    まずは凡例を試します。入力フィールドのWolgram言語はこれ。

    Plot[Sin[x], {x, 0, 6 Pi}, PlotLegends->”Expressions”]

    凡例は対応していない模様。

    凡例は表示できない?
  5. デバッガで見てみると、それぞれの値は次のようになってます。「"Expressions”」のダブルクオートをエスケープすればうまくいくのかな、と思ったりしたのですが、いくつか試してみてもダメでした。。。方法を発見できたらまた書きます。

  6. 3次元のグラフもかけるのかな、ということで、

    Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2}]

    を入力してみました。3次元でもいけるんですね。

    3次元の関数プロット

    上記の関数はWolframのドキュメントセンターのものを使いました。同じページにもっと複雑なものもあるので、ついでに結果を書いておきます。

     

    Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2}]



    Plot3D[Im[ArcSin[(x + I y)^4]], {x, -2, 2}, {y, -2, 2}]



ドキュメントセンターの画像とほぼ同じです。

なかなかうまくできてます。

Wolfram EngineをVisualBasicで使う(2:Wolfram言語の入力を受け付ける)

Wolfram EngineをVisualBasicで使う(2:Wolfram言語の入力を受け付ける)

 

前回は、式をハードコードして固定していましたが、今日は文字列を入力して、応答を表示するようにします。

とりあえず、前回の続きから始めます。

一応、「Release」->「Debug」に戻してから。

 

  1. まず「Run」ボタンのテキストを「Evaluate」に変えました。あと、結果表示の前に「Label」で「Result」を加えました。

    次に、新しいテキストボックスを「Evaluate」ボタンの上に配置しました。この上段のテキストボックスに入力したものを、評価して、結果を下に表示できるようにします。

    入力用の新しいテキストボックスを配置
  2. 「TextBox2」(上段のテキストボックス)の内容をWolfram Kernelに渡せるようにします。ほんの1か所を変えるだけです。

    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     

            Dim ml As IKernelLink = MathLinkFactory.CreateKernelLink("-linkmode launch -linkname 'C:\Program Files\Wolfram Research\Wolfram Engine\13.3\WolframKernel.exe'")

            ml.WaitAndDiscardAnswer()

     

            Dim result As String = ml.EvaluateToOutputForm(TextBox2.Text, 0)

            TextBox1.Text = result

        End Sub

    End Class

    ハードコードしていた部分を、「TextBox2」のテキスト、つまり入力値に変えただけです。

  3. Visual Studioツールバーの「WinFormsApp1」ボタンを押すか、F5キーでデバッグモードで実行します。すると、想定していたダイアログが表示されます。

  4. 上段のテキストボックスに「3+2」と入力し、「Evaluate」をクリックすると、きちんと計算されて表示されます。

    計算結果が表示された

    上段に入力した文字列をそのままWolfram Kernelに渡しているということは、Wolfram言語に基づいて書かれたコード(ただし出力はテキストでないといけない)を入れれば、そのまま動くのではと予想しました。

  5. ということで、Wolfram言語の因数分解「Factor」を使ってみます。

    上段のテキストボックスに、

    Factor[1 + 2 x + x^2]

    と入力してみました。

    その結果は、、、

    因数分解の結果

    ううむ、うまく表現できないのか。。。

    ただ、計算は正しくやってくれています。

     

    デバッガで、どのような文字列が「TextBox1.Text」に入ってきているかというと、

    「vbCrLf」という改行コードが入ってきていますね。2乗の「2」の前にスペースが入っているということは、2行で表現すればそれなりに見えるかも、と推察できます。

  6. ということで、2行が表示できるように「TextBox1」の「プロパティ」で「Multiline」を「True」にし、ボックスを少し大きくします。

  7. で、同じ因数分解をもう一度やってみると、その結果はこれ。

    2行で表示した結果

    うーん、おしい。

    おそらくこれは、フォントの関係で上の空白文字の幅が狭いのでしょう。フォントを等幅系にすれば、きっとうまくいくはず。

  8. 「TextBox1」の「プロパティ」の「Font」を「Courier New」にして実行してみると、それなりに見えました。

    フォントを変えて表示

    TeXっぽい表示はできないのかな。Wolfram言語では「TeXForm[]」という関数がありますが、VB側の画面があくまでもStringなので、そのままでは厳しい。

    これは、時間があれば、そのうち考えてみることします。

     

    もう一つ関数を試してみます。微分。

  9. 上段のテキストボックスに、

    D[x^n, x]

    と入力します。「Evaluate」をクリックすると、結果は次のようになります。

    これもよさそうですね。1行で表示したり、等幅ではないフォントだと「なんのこっちゃ」となるかもしれません。

 

今日はここまで。意外と簡単だったかも。