ワークシートデータの操作
このセクションでは、Origin Cでデータを操作する方法を示すサンプルを紹介します。
目次
ワークシート選択の取得
Worksheet::GetSelectedRange は、ワークシートから1つまたは複数の選択したデータを取得するのに使うことができます。次のコードは、ワークシート選択で1つの列からデータを取得する方法を示しています。この関数は、1つの列、1つの行、ワークシート全体など範囲データ型を返します。
Worksheet wks = Project.ActiveLayer(); int r1, c1, r2, c2; int nRet = wks.GetSelectedRange(r1, c1, r2, c2); if( WKS_SEL_ONE_COL & nRet ) // 1つの列だけを選択 { // 選択でデータ範囲オブジェクトを構築 DataRange dr; dr.Add("X", wks, r1, c1, r2, c2); // 選択した列からデータを取得 vector vData; dr.GetData(&vData, 0); }
ワークシート内の表示範囲を設定する
Worksheet内の表示範囲を設定する場合、Worksheet::SetBoundsを使い、開始行/終了行に設定と同じです。
次のコードは、現在のワークシートウィンドウにすべての列の開始と終了をセットする方法を示します。
Worksheet wks = Project.ActiveLayer(); // 行の開始と終了 int begin = 9, end = 19; // すべての列の開始と終了をセット int c1 = 0, c2 = -1; // -1は終了 wks.SetBounds(begin, c1, end, c2);
ワークシートに大きなデータセットを配置する
ワークシート内で大きなデータセット(例:1000列)を操作するとき、Origin C関数を効率よく実行するためには、以下のステップを使います。
- ワークシートにデータを配置する列と行を準備します。
- サイズをセットするには、Worksheet::SetSizeを使い、Worksheet::AddCol は使いません。
- Originが新しい列を追加するときに重複した名前を持たないように既存の列のショートネームをチェックする必要があるので、事前に空のワークシートでサイズをセットし、列と行の属性は無しにします。これにより時間が削減できます。 while( wks.DeleteCol(0) ); を使って、すべての列を削除して、空のワークシートを作成します。
- DataObject::GetInternalDataBufferを使って、バッファでワークシート列にデータを配置します。
- 実行スピードを上げるために関数を実行しているとき、コードビルダは閉じておきます。
以下のサンプルコードをご覧ください。
// ワークシートサイズの準備 Worksheet wks; wks.Create("Origin"); while( wks.DeleteCol(0) ); int rows = 100, cols = 1000; wks.SetSize(rows, cols); // ワークシート列に1つずつデータを配置 foreach(Column col in wks.Columns) { col.SetFormat(OKCOLTYPE_NUMERIC); col.SetInternalData(FSI_SHORT); col.SetUpperBound(rows-1);// 最後の行のインデックス, 0 オフセット int nElementSize; uint nNum; LPVOID pData = col.GetInternalDataBuffer(&nElementSize, &nNum); short* psBuff = (short*)pData; // OC のループは遅いですがDLLにポインタを渡すと // 操作が高速になる。ここではポインタの動作の表示のみ for(int ii = 0; ii < rows; ii++, psBuff++) { *psBuff = (ii+1) * (col.GetIndex()+1); } col.ReleaseBuffer(); // この呼び出しを記録しない }
ワークシートの埋め込みグラフにアクセスする
新しいグラフと新しいワークシートを作成し、1つのワークシートセルにグラフを埋め込みます。
GraphPage gp; gp.Create("Origin"); Worksheet wks; wks.Create(); int nOptions = EMBEDGRAPH_KEEP_ASPECT_RATIO | EMBEDGRAPH_HIDE_LEGENDS; // ワークシートセル(0, 0)にグラフを配置 wks.EmbedGraph(0, 0, gp, nOptions);
ワークシート内に埋め込んだグラフに名前またはインデックスでアクセスします。
// アクティブワークシートから埋め込みグラフを取得 Worksheet wks = Project.ActiveLayer(); GraphPage gp; gp = wks.EmbeddedPages(0); // 埋め込みグラフページをインデックスで取得 gp = wks.EmbeddedPages("Graph1"); // 埋め込みグラフページを名前で取得
ワークシートデータのソート
Sort メソッドを使って列データをソートすることができます。 1つの列をソートし、vectorbase::Sort メソッドを使います。
// 列のソート // 実行前に2列を持つアクティブワークシートにデータを入力 // 例えば、\Samples\Mathematics\Sine Curve.datをワークシートにインポート Worksheet wks = Project.ActiveLayer(); Column colY(wks, 1); // Y 列 // ソートした後、 (x, y)の元の関係は崩れる vectorbase& vec = colY.GetDataObject(); vec.Sort();
ワークシート内のすべての列をソートするには、Worksheet::Sort メソッドを使います。
// ワークシートのソート // 実行前に2列を持つアクティブワークシートにデータを入力 // 例えば、\Samples\Mathematics\Sine Curve.datをワークシートにインポート Worksheet wks = Project.ActiveLayer(); int nCol = 1; // 2番目の列にすべてのワークシートデータを昇順ソート BOOL bIsAscending = true; BOOL bMissingValuesSmall = TRUE; // 欠損値を最小値として取り扱う int r1 = 0, c1 = 0, r2 = -1, c2 = -1; // -1はr2とc2の最後 // ソート後、各(x, y)は元の関係を維持 wks.Sort(nCol, bIsAscending, bMissingValuesSmall, r1, c1, r2, c2);
ワークシートデータをマスクする
次のコードは、指定した列に対して、0と等しいか、それより小さいデータ行にマスクをセットする方法を示します。
int nCol = 1; Worksheet wks = Project.ActiveLayer(); Column col(wks, nCol); vector vData = col.GetDataObject(); // 0と等しいか、それより小さいすべてのデータを見つけて、インデックスを返す vector<uint> vnRowIndex; vData.Find(MATREPL_TEST_LESSTHAN | MATREPL_TEST_EQUAL, 0, vnRowIndex); // 行と列のインデックスで追加される複数の部分範囲を含む範囲を構築 DataRange dr; for(int nn = 0; nn < vnRowIndex.GetSize(); nn++) { int r1, c1, r2, c2; r1 = r2 = vnRowIndex[nn]; c1 = c2 = nCol; dr.Add("X", wks, r1, c1, r2, c2); } // データ範囲にマスクをセット dr.SetMask();
サイズをセット
Worksheet::SetSize メソッドを使用して、ワークシートの行と列の数をセットできます。
// 行と列の数をセット。データは保持 // 一度に多くの列が行を追加したい場合SetSizeを使用した方が良い int nNumRows = 100; int nNumCols = 20; wks.SetSize(nNumRows, nNumCols); // 行の数を変更して列の数は変更しない場合 // 代わりに -1 を使用。例えば、 wks.SetSize(nNumRows, -1); // 列の数は変更して行は変更しない場合も同様
ワークシートデータを削減する
ワークシート内のXYデータの削減のために、Origin Cいくつかの関数を提供してます。 例えば、X増分によるXYデータの削減にはocmath_reducexy_fixing_increbin、グループの数によるXYデータの削減にはocmath_reducexy_n_groups、NポイントごとにXYデータを削減するにはocmath_reducexy_n_pointsを使用します。ここでは、NポイントごとにXYデータを削減する方法を、以下のサンプルで示します。
Worksheet wks = Project.ActiveLayer(); // アクティブワークシートを取得 if(!wks) { return; } Column colX(wks, 0); // ワークシートの1列目 Column colY(wks, 1); // ワークシートの2列目 if(colX && colY) { vectorbase &vbInterY = colY.GetDataObject(); // Y列データを取得 vector vY = vbInterY; vector vReduced(vY.GetSize()); int nPoints = 3; // 3ポイントごとに削減。結果は各3ポイントの平均とする int nNewSize = ocmath_reducexy_n_points(vY, vReduced, vY.GetSize(), nPoints, REDUCE_XY_STATS_MEAN); int iReduced = wks.AddCol("Reduced"); // 結果のために新しい列を追加 Column colReduced(wks, iReduced); vectorbase &vbReduced = colReduced.GetDataObject(); vbReduced = vReduced; }
LT条件でワークシートからデータを抽出
Worksheet::SelectRows メソッドを使ってワークシートデータを選択します。 行は、複数の列をまたがって選択できます。
// 条件を元にしたワークシートからデータを選択 // 'uint'型のvectorに選択した行のインデックスを配置 Worksheet wks = Project.ActiveLayer(); // 条件式に基づくワークシートデータをチェックし // 行インデックスを'vnRowIndices'に出力 // LabTalkの範囲オブジェクト 'a' = column 1, 'b' = column 2を定義 string strLTRunBeforeloop = "range a=1; range b=2"; string strCondition = "abs(a) >= 1 && abs(b) >= 1"; vector<uint> vnRowIndices; // 出力 int r1 = 0, r2 = -1; // 行範囲, -1はr2の最後の行 // 任意の最大行数, -1は制限なし int nMax = -1; int num = wks.SelectRows(strCondition, vnRowIndices, r1, r2, nMax, strLTRunBeforeloop);
選択をハイライトする2つの方法があります。 最初の方法は選択したインデックスをハイライトする方法です。
// 方法1:vnRowIndicesで行をハイライト Grid gg; if( gg.Attach(wks) ) { // uint型 の vectorデータを int型のvectorに変換 vector<int> vnRows; vnRows = vnRowIndices; gg.SetSelection(vnRows); }
データ選択をハイライトする2つ目の方法は、選択した行の塗り色を指定する方法です。
// 方法2: vnRowIndicesで選択した行の色を塗りつぶす DataRange dr; // vnRowIndicesで行インデックスでデータ範囲を構築 for(int index=0; index<vnRowIndices.GetSize(); index++) { // すべての列に対して 0(最初の列) および -1(最後の列) // 範囲名の変数に対して""であればデフォルト名を使用 dr.Add("", wks, vnRowIndices[index], 0, vnRowIndices[index], -1); } Tree tr; tr.Root.CommonStyle.Fill.FillColor.nVal = SYSCOLOR_BLUE; // 塗りつぶし色 = 青 tr.Root.CommonStyle.Color.nVal = SYSCOLOR_WHITE; // フォントの色 = 白 if( 0 == dr.UpdateThemeIDs(tr.Root) ) // エラーなしで0を返す { bool bRet = dr.ApplyFormat(tr, true, true); }
2つのワークシート内のデータを比較する
2つのワークシートの行数または列数を比較したり、データ自体を比較するのに役立ちます。 Datasheet::GetNumRowsおよび Datasheet::GetNumColsメソッドを使って、ワークシートから行や列をカウントします。
if( wks1.GetNumRows() != wks2.GetNumRows() || wks1.GetNumCols() != wks2.GetNumCols() ) { out_str("The two worksheets are not the same size"); return; }
似たような操作を実行する別の方法は、それぞれのワークシートのデータをvectorにコピーし、それぞれのvectorデータを比較します。
// ワークシート1の列から1つずつすべてのデータを取得 vector vec1; foreach(Column col in wks1.Columns) { vector& vecCol = col.GetDataObject(); vec1.Append(vecCol); } // ワークシート2の列から1つずつすべてのデータを取得 vector vec2; foreach(col in wks2.Columns) { vector& vecCol = col.GetDataObject(); vec2.Append(vecCol); } if( vec1.GetSize() != vec2.GetSize() ) { out_str("The size of the two data sets is not equal"); return; }
データ要素自体を比較するには、上記サンプルでvectorに対して、ocmath_compare_data 関数を使います。
bool bIsSame = false; double dTolerance = 1e-10; ocmath_compare_data(vec1.GetSize(), vec1, vec2, &bIsSame, dTolerance); if( bIsSame ) { out_str("Data in the two worksheets are the same"); }