crossframe » VSTO http://crossframe.iiv.jp Windows Dev. Site Tue, 07 Nov 2023 06:31:52 +0000 ja hourly 1 https://wordpress.org/?v=3.8.41 jQueryPlot from Excel ../../../20131207651/ ../../../20131207651/#comments Sat, 07 Dec 2013 14:35:10 +0000 http://xfra.me/?p=651 データビジュアライゼーション。最近とてもブームでもあり私自身も大変興味深い領域です。Excelデータをビジュアライゼーションするとき、どんな形が面白そうかと考えてみたところ、WebでJavaScriptライブラリという結論になりました。Webで表示させるためには、VSTOを使ってWindowsForm上のWebViewにhtmlファイルを読み込ませる方法にしました。もともと今大人気のD3.jsを使いたかったのですが、WebViewがIE7相当のため(Webサーバログで確認)動作しませんでした。対応しないメソッドがあったり、SVGを使うということが原因と思われます。(ちなみにQtのQWebViewでは表示できました。)しかしながら個人的にこのD3.jsを初めて知ったときは、jQueryが登場したときと同じくらい衝撃を受けました。ちょっとはまっています。
そこでD3.jsのかわりにIE7にも対応しているjQueryPlot(http://www.jqplot.com/)を使うことにしました。

前置きが長くなりましたが、ExcelシートにあるデータをWindowFormのボタンを押すとWebViewのグラフが更新されるデモをつくってみました。

jqplot1

jqplotdata1

データを変更(赤字部分)してボタン押下

jqplot2

jqplotdata2

環境 : VisualStudio 2010, Excel 2010 / Windows 7
ThisWorkbook.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using Microsoft.Office.Tools.Excel;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;

namespace ExcelWorkbook_Web
{
    public partial class ThisWorkbook
    {
        private void ThisWorkbook_Startup(object sender, System.EventArgs e)
        {
            Form1 fm = new Form1();
            fm.Show();
        }
        public String getData()
        {
            String str = "[";

            for (int i = 1; i <= 7; i++)
            {
                str += "[";

                var o1 = Globals.Sheet1.Cells[i, 2].Value;
                var o2 = Globals.Sheet1.Cells[i, 3].Value;
                var o3 = Globals.Sheet1.Cells[i, 4].Value;

                str += o1.ToString() + "," + o2.ToString() + "," + o3.ToString();
                var o4 = Globals.Sheet1.Cells[i, 1].Value;
                str += ",'" + o4.ToString() + "'";
                str += "]";
                if (i != 7)
                {
                    str += ",";
                }
            }
            str += "]";
            return str;
        }

        private void ThisWorkbook_Shutdown(object sender, System.EventArgs e)
        {
        }

        #region VSTO デザイナーで生成されたコード
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisWorkbook_Startup);
            this.Shutdown += new System.EventHandler(ThisWorkbook_Shutdown);
        }
        #endregion
    }
}

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ExcelWorkbook_Web
{
    [System.Runtime.InteropServices.ComVisibleAttribute(true)]
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            webBrowser1.ObjectForScripting = this;
            webBrowser1.Navigate(new Uri("file:///C:/work/test.html"));

        }

        private void button1_Click(object sender, EventArgs e)
        {
            String str = Globals.ThisWorkbook.getData();
            object[] args = {str};
            webBrowser1.Document.InvokeScript("plot", args);
        }
    }
}

test.html

<html>
<head>
<!--[if lt IE 9]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery.jqplot.min.js"></script>
<script type="text/javascript" src="jqplot.bubbleRenderer.min.js"></script>
<link rel="stylesheet" type="text/css" href="jquery.jqplot.min.css" />
<script>
function plot(arg)
{
    var arr = eval(arg);

    plot1 = $.jqplot('chart1',[arr],{
        title: 'Transparent Bubbles',
        seriesDefaults:{
            renderer: $.jqplot.BubbleRenderer,
            rendererOptions: {
                bubbleAlpha: 0.6,
                highlightAlpha: 0.8
            },
            shadow: true,
            shadowAlpha: 0.05
        }
    });
}
</script>
</head>
<body>
<div id="chart1" style="height:300px;width:300px; "></div>
</body>
</html>

Excelシートのデータを変更してボタンを押すと、BubbleChart(というらしい)が変化する模様は、なかなかわかりやすいくて使いやすいと思いました。
いろいろと応用がききそうです。

]]>
../../../20131207651/feed/ 0
C# – IronPython データ連携 ../../../20131020567/ ../../../20131020567/#comments Sun, 20 Oct 2013 08:20:16 +0000 http://xfra.me/?p=567 C#とIronPythonを連携させようと思ったのは、Pythonの数値計算ライブラリNumPyがIronPythonでもインストールできるというサイトを見つけたからです。(また、VSTOでExcelのデータ処理にも使えればと)

https://www.enthought.com/repo/.iron/

これを使って、C#、IronPython間のデータの受け渡しテストをしてみました。

環境 : IronPython 2.7.3 (2.7.0.40) on .NET 4.0.30319.296 (32-bit), Visual Studio 2010 / Windows 7

インストール
1)ironpkg-1.0.0.pyをダウンロード
2)以下コマンド実行

ipy ironpkg-1.0.0.py –install
ironpkg scipy
ipy -X:Frames -c “import scipy”

いろいろと調べてトライしましたが、残念ながらSciPyは使えないようです。しかしNumPyは使えるので、こちらだけ使いました。
(NumPyだけできるものにしました)

csTest.py

import sys
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7')
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\DLLs')
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib\site-packages')

import clr
clr.AddReference('mtrand.dll')

import numpy as np

na = np.zeros(shape=(2,2))

for i in range(2):
	for j in range(2):		
		na[i, j] = mx[i, j]

mr = np.linalg.inv(na)
print '- Iron Python -'
print mr
print np.dot(na, mr)

for i in range(2):
	for j in range(2):
		mx[i, j] = float(mr[i, j])

C#で設定した2次元配列のデータをNumPyを使って逆行列の計算をして戻すというものです。
しかしC#の配列からのNumPy配列に渡す(その逆も)やり方ついていろいろと悩みました。
mxのままだと逆行列を求める関数でエラーをだしました。(np.array(mx)とやるときは、mxはジャグ配列([][])でないといけないみたいだし・・)
結果代入という形にしてしまいましたが、もっといい方法がないかまた調べたいと思います。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using System.Collections;
using IronPython.Runtime;

namespace csPyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var pe = Python.CreateEngine();           
            ScriptSource src = pe.CreateScriptSourceFromFile(@"C:\csTest.py");
            ScriptScope scope = pe.CreateScope();

            double[,] mx = new double[,] {{0,1},{2,3}};
            scope.SetVariable("mx", mx);

            src.Execute(scope);

            var m = scope.GetVariable<double[,]>("mx");

            Console.WriteLine(" - C# - ");
            for (int i = 0; i < 2; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    Console.Write(m[i, j] + " ");
                }
                Console.WriteLine();
            }
            Console.ReadLine();
        }
    }
}

C#からダイナミック言語のPythonの変数に直接アクセスできるのも、強力な機能ですね。しかしもうすこしCPythonのライブラリが使えるようになってほしいところです。

以下は実行結果です。逆行列の確認として、単位行列を出力しています。
NumPy

]]>
../../../20131020567/feed/ 0
Excel と R via VSTO ../../../20131013539/ ../../../20131013539/#comments Sun, 13 Oct 2013 07:35:47 +0000 http://xfra.me/?p=539 RExcelアドインを使ってExcelとR連携は前々回テストしましたが、VSTOを使ってRを呼び出すテストをしてみました。
これには、“C#, Python で R.NET”でテストしたR.NETを使います。
プロジェクトは“LINQ/VSTO”と同じ方法で作成します。

環境: Excel2010, R 3.0.0 / Windows 7
VisualStudio 2010 参照設定追加
RDotNet
RDotNet.NativeLibrary

using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using RDotNet;
using Excel = Microsoft.Office.Interop.Excel;

namespace ExcelWorkbook3
{
    public partial class Sheet1
    {
        private void InternalStartup()
        {
            DataTable table = new DataTable();
            Excel.Worksheet activeSheet = ((Excel.Worksheet)Application.ActiveSheet);

            var envPath = Environment.GetEnvironmentVariable("PATH");
            var rBinPath = @"C:\Program Files\R\R-3.0.0\bin\i386";
            Environment.SetEnvironmentVariable("PATH", envPath + Path.PathSeparator + rBinPath);
            using (REngine engine = REngine.CreateInstance("RDotNet"))
            {
                engine.Initialize();

                StringBuilder plotCommmand = new StringBuilder();  
                plotCommmand.Append(@"rnorm(100)");
                var e = engine.Evaluate(plotCommmand.ToString());
                int k = 1;
                foreach (var v in e.AsNumeric().ToArray<double>())
                {
                    activeSheet.Cells[k, 1].Value = v;
                    k++;
                }
            }
        }
    }
}

R側では正規分布の乱数を生成するrnorm関数を使い、その出力をExcelシートに表示させます。Excel側では、グラフ表示をして正規分布を確認しました。(手動)
(ちなみにRのPlotを呼び出すこともできます)
R_VSTO1
このような単純な例では、どんな連携方法も大差ありませんが、その他に組み合わせるものがある場合、いろいろと解決方法を知っておくと便利です。

]]>
../../../20131013539/feed/ 0
Excel-DNA ../../../20131005486/ ../../../20131005486/#comments Sat, 05 Oct 2013 14:16:33 +0000 http://xfra.me/?p=486 Excelと外部ツールが連携できるものをいろいろと調べていたら、Excel-DNAというものが面白そうだったので試してみました。
ver 0.30 (Wed Dec 12, 2012 at 4:00 PM)

http://exceldna.codeplex.com/

また以下サイトに大変詳しく説明されています。

http://supermab.com/wp/

今回これを参考にさせていただきました。

ExcelDna-0.30を上記サイトからダウンロードしDistributionフォルダの以下のファイルをワークフォルダにコピーします。
ExcelDna.dna
ExcelDna.xll
この二つのファイルは同じフォルダに置き、拡張子以外のファイル名は変更してもいいですが同じものにします。
編集するのは.dnaファイルのみで.xllファイルはExcelへのインポート(ドラッグ&ドロップまたはアドイン追加)に使用します。

ExcelDna.dna

<![CDATA[
using System;
using System.Numerics;

public class Test
{
	public static object [] TestArray(int n)
	{
		int x = 10;
		object [] arr = new object[x];

		for(int i=0;i<x;i++){
 			arr[i] = n + i;
 		}
 		return arr;
 	} 
} 
]]>

C#のソースをコンパイルをすることなく、テキストエディタで編集するだけというのがとても手軽です。
そしてこれだけで、なんとTestArry()がユーザ定義関数として、Excelで利用できます。ちょっと驚きです。

私がやりたかった「ユーザ関数から配列を返した結果を複数のセルに表示させる」ことにはちょっと戸惑いました。
そもそもExcelの配列数式なるものを知らなかったためです。
あと、配列をint[]で返すとExcelから見えないようです。エラーをださないので原因がわかりませんでした。

以下に手順をメモしておきたいと思います。

excelDna1
上のような状態で、CTRL + SHIFT + Enter を押します。セルは複数選択しておく必要があります。
選択したセルが一つだったり、Enterキーだけ押した場合は、一つのセルにしか表示しません。
excelDna2
無事表示できました。^^;
個人的にはVSTOが好きですが、この手軽さはとても魅力に思いました。

]]>
../../../20131005486/feed/ 0
LINQ / VSTO ../../../20130519266/ ../../../20130519266/#comments Sat, 18 May 2013 15:51:15 +0000 http://xfra.me/?p=266 VSTOとは、Visual Studio Tools for Office の略です。前回WebのTableでやったLINQによるソートをExcelのシートでやってみました。ExcelのシートのプロクラムといえばVBAですが、前からC#でやってみたいと思っていて、だったらLINQだよね、となり、今ちょうど調査しているし、という流れでテストしてみました。

環境 VSTO / Visual Studio 2010 & Excel 2010 / Windows 7
プロジェクトは、Visual C# -> Office -> 2010 -> Excel 2010 ブック です。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using Microsoft.Office.Tools.Excel;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;

namespace ExcelWorkbook
{
    public partial class Sheet1
    {
        private void InternalStartup()
        {
            this.button1.Click += new System.EventHandler(this.button1_Click);
        }
       private void button1_Click(object sender, EventArgs e)
        {
            DataTable table = new DataTable();
            Excel.Worksheet activeSheet = ((Excel.Worksheet)Application.ActiveSheet);

            table.Columns.Add("c1");
            table.Columns.Add("c2");
            table.Columns.Add("c3");
            for (int r = 1; r <= 6; r++)
            {
                table.Rows.Add(activeSheet.Cells[r, 1].Value, activeSheet.Cells[r, 2].Value, activeSheet.Cells[r, 3].Value);
            }
            var data = from dt in table.AsEnumerable()
                       orderby dt.Field<string>("c2")
                               select new
                               {
                                   a = dt.Field<string>("c1"),
                                   b = dt.Field<string>("c2"),
                                   c = dt.Field<string>("c3")
                               };
            int i=1;
            foreach (var d in data)
            {
                activeSheet.Cells[i, 1].Value = d.a;
                activeSheet.Cells[i, 2].Value = d.b;
                activeSheet.Cells[i, 3].Value = d.c;
                i++;
            }
        }
    }
}

table2

ボタンを押すと、中央の列がソートされます。

table3

VSTOって興味がありつつもなかなか使う機会が少ないのですが、やっばりまだVBAなのでしょうか。という私もVBAの手軽さはとても便利なので、よく使うのですが・・

]]>
../../../20130519266/feed/ 0