Author |
Topic  |
|
couturier
France
291 Posts |
Posted - 08/29/2017 : 02:47:54 AM
|
Origin Ver. and Service Release (Select Help-->About Origin): 2017 SR2 Operating System:win10 64bit
Hi,
I have a bunch of vertical lines (more than a thousand) from which I want to get the color and the X value. Line names are line1, line2, ... Sor far, I've used LT:
dataset ds1, ds2; int nLine=0; doc -e G { if (%[%b,1:4]=="line") { nLine++; ds1[nLine]=%b.x1; ds2[nLine]=%b.color; }; };
To make things faster, I've tried to write this part in OC: int Get_Line_Info(vector& vecX, vector& vecCol) { vector v1, v2; int n=0; GraphLayer gly = Project.ActiveLayer(); if( gly.IsValid() ) { fpoint ptNode; foreach (GraphObject grobj in gly.GraphObjects) { string str1=grobj.GetName(); string str2=str1.Mid(0, 4); if (str2=="Line") { grobj.GetNode(0, ptNode); v1.SetSize(n+1); v1[n]=ptNode.x; v2.SetSize(n+1); Tree trFormat; trFormat = grobj.GetFormat(FPB_ALL, FPB_ALL, TRUE, TRUE); v2[n]=trFormat.Root.Color.nVal; n++; } } } vecX=v1; vecCol=v2; return n; }
The OC function works but is about 2 times slower than LT. Most of the time is spent in getting the color info from the tree.
Is there a way to significantly speed things up ?
Thanks |
|
yuki_wu
896 Posts |
Posted - 08/30/2017 : 04:28:12 AM
|
Hi,
I modified your OC code a little bit:
void GetLineInfo()
{
vector vX, vColor;
GraphLayer gl = Project.ActiveLayer();
if(gl)
{
foreach(GraphObject grobj in gl.GraphObjects)
{
if(grobj.GetObjectType() == "Line")
{
vX.Add(grobj.X);
Tree trFormat;
trFormat = grobj.GetFormat(FPB_STYLE_COLOR, FOB_ALL, TRUE, TRUE);
vColor.Add(trFormat.Root.Color.nVal);
}
}
}
}
In fact, you don’t have to get the whole format tree since you only want to know what color it is. Also, the second bit should be FOB_* not FPB_*. For bit description, you can find it in OC_const.h.
Hope it helps.
Regards, Yuki OriginLab
|
 |
|
couturier
France
291 Posts |
Posted - 08/30/2017 : 12:41:08 PM
|
Thanks a lot for your help.
I have simplified things for the example but objects' name are different and I must check their names because there might be other lines I dont care about.
I didn't recall of the Add method, instead of setting size in each iteration. Much more elegant, even if it didn't make a significant diff in time execution.
One issue in your script is that grobj.X seem to read screen X, instead of real X.
One of the main issue in my script was retrieving the whole tree.
I mixed your script, mine and GetSpecialGraphicObjectsCollection method and get a faster time execution.
|
 |
|
rdremov
USA
28 Posts |
Posted - 08/30/2017 : 3:42:32 PM
|
This LT script speed is not simple to beat. It has few lines and fast built in collection. Also, LT speed was greatly improved some time ago, such that it does not parse on every iteration anymore.
Now, OriginC is using XML tree, which is string based and has big overhead. However, here is my code which beats LT speed:
#include <../Originlab/okThemeID.h>
void GetLineInfo3()
{
vector<double> vX;
vector<int> vColor;
GraphLayer gl = Project.ActiveLayer();
if(gl)
{
Tree trFormat;
trFormat = gl.GetFormat(FPB_STYLE_COLOR|FPB_DATA, FOB_LINES, FALSE, TRUE);
TreeNode trLines;
if(octree_theme_tree_get_node_by_id(&trLines, &trFormat, OTID_LINES, 1, true))
{
int nCount = trLines.Children.Count();
vX.SetSize(nCount);
vColor.SetSize(nCount);
int nIndex = 0;
vector<double> xx;
TreeNode trData, trX, trColor;
foreach(TreeNode trLine in trLines.Children)
{
trData = trLine.FindNodeByAttribute(STR_ID_ATTRIB, OTID_ANCHOR_DATA, false);
if(trData)
{
trX = trData.FindNodeByAttribute(STR_ID_ATTRIB, OTID_ANCHOR_DATA_X, false);
if(trX)
{
xx = trX.dVals;
vX[nIndex] = xx[0];
}
}
trColor = trLine.FindNodeByAttribute(STR_ID_ATTRIB, OTID_LINE_COLOR, false);
if(trColor)
vColor[nIndex] = trColor.nVal;
nIndex++;
}
}
}
}
As you can see I call GetFormat only once. I set filter to get only data and colors and only for Line objects. I preset vector sizes to children count before the loop to avoid memory re-allocations. Also, I skip on node name strings in favor of faster IDs.
These optimization results in 125ms (OriginC) vs 187ms (LT) on my computer.
It should be possible to improve it more by eliminating FindNodeByAttribute assuming rigid tree structure, not sure if worth it. |
 |
|
rdremov
USA
28 Posts |
Posted - 08/30/2017 : 5:33:51 PM
|
quote: Originally posted by couturier
I did more measuring with lines1000.opj. Out of 125ms total time of GetLineInfo3 about 80ms is the GetFormat call time. This means other optimization in GetLineInfo3 will lead to diminishing results, as it can not be better than GetFormat time. This timing is based on my computer and Origin 2017sr2 release build.
However, if you try Origin 2018 results are much better. GetFormat only takes 25ms on the same pc, which means 3x improvement in speed. This must be due to the fact that Origin 2017 and earlier were using msxml.dll for XML processing, while Origin 2018 is not anymore. It has faster XML engine. |
Edited by - rdremov on 08/30/2017 5:36:18 PM |
 |
|
cpyang
USA
1406 Posts |
Posted - 08/30/2017 : 8:33:36 PM
|
quote: Originally posted by couturier .... One issue in your script is that grobj.X seem to read screen X, instead of real X. ....
Can you be more specific? I tried the following simple code with a vertical line on a graph
void test(string strName = "line")
{
GraphLayer gl = Project.ActiveLayer();
GraphObject grobj;
grobj = gl.GraphObjects(strName);
out_double("X = ", grobj.X);
}
I get the same X as LT "line.x=", regardless of the line's attachment. I remember we had issue with this a long time ago.
Separately, I have added JIRA https://originlab.jira.com/browse/ORG-16946 for general access to all the LabTalk properties available to GraphObject.
CP
|
 |
|
couturier
France
291 Posts |
Posted - 08/31/2017 : 04:41:20 AM
|
@CP This is because there's the same issue with grobj.x and line.x Yes we had a discussion about this a long time ago. X property doesn't return real x value but screen X, so it is affected by scale. For getting real in LT, better use x1 and x2. Same in OC.
void test(string strName = "line") { GraphLayer gl = Project.ActiveLayer(); GraphObject grobj; grobj = gl.GraphObjects(strName); fpoint ptNode; grobj.GetNode(0, ptNode); out_double("screen X = ", grobj.X); out_double("real X = ", ptNode.x); }
In Origin, new an empty graph. layer.x.from=0.01; layer.x.to=0.02; draw -n line -l {0.015, 0, 0.015, 8}; test(line); line.x=; line.x1=;
layer.x.from=-500; layer.x.to=1000; test(line); line.x=; line.x1=; |
Edited by - couturier on 08/31/2017 06:27:57 AM |
 |
|
couturier
France
291 Posts |
Posted - 08/31/2017 : 07:24:55 AM
|
@Roman
your code looks good. My whole story is I have 4 kinds of lines: - Names starting with LIM (e.g. LIM1, LIM2, ...) - Names sarting with LIIM (e.g LIIM1, LIIM2, ...) - Each of them can have 2 different color.
I need to get: - X and color for each of them, and put into vectors - total number - number of LIM lines - number of LIIM lines
In FindNodeByAttribute, is there any name property, so I can filter them ?
Thanks |
 |
|
rdremov
USA
28 Posts |
Posted - 08/31/2017 : 11:41:52 AM
|
couturier, unfortunately we do not have Name exposed to theme yet.
You mentioned "Each of them can have 2 different color". Is it possible to filter by color if colors between LIM and LIIM do not overlap?
If they do overlap, there is this kind of code, which uses theme properties object access:
int GetLineInfo4()
{
vector<double> vPos;
vector<int> vColor;
int n=0;
GraphLayer gly = Project.ActiveLayer();
if( gly.IsValid() )
{
vector<double> xx;
foreach (GraphObject go in gly.GraphObjects)
{
if(go.GetName().Left(4)=="Line")
{
vColor.Add(go.Line.Color.nVal);
xx = go.Line.Data.X.dVals;
vPos.Add(xx[0]);
n++;
}
}
}
return n;
}
It is simple, but not very fast. On my pc it took 314ms in Origin 2017 sr2. However, Origin 2018 is much better - takes only 65ms.
to test speed use high res timer like this (Code Builder should be closed to avoid debug and breakpoints impact):
sec -AB; GetLineInfo4; sec -AE elapsed; elapsed=; |
Edited by - rdremov on 08/31/2017 12:08:19 PM |
 |
|
couturier
France
291 Posts |
Posted - 08/31/2017 : 12:14:37 PM
|
Not sure to understand what you mean with overlapping colors. Lines can only be red or green.
My actual code looks like this. About 2 x faster than LT, but still a bit long.
int EMG_Get_Bars_Info(vector& vecX, vector& vecDir, int& nLimS, int& nLimD)
{
int nLim=0;
vector vX, vCol;
GraphLayer gly = Project.ActiveLayer();
if( gly.IsValid() )
{
Collection<GraphObject> coll;
if ( gly.GetSpecialGraphicObjectsCollection(coll, "LIM") )
{
GraphObject grobj;
Tree trColor;
fpoint ptNode;
foreach(grobj in coll)
{
grobj.GetNode(0, ptNode);
trColor=grobj.GetFormat(FPB_STYLE_COLOR, FOB_OBJECT, TRUE, TRUE);
vX.Add(ptNode.x);
vCol.Add(trColor.Root.Color.nVal);
nLim++;
nLimS++;
}
}
if ( gly.GetSpecialGraphicObjectsCollection(coll, "LIIM") )
{
GraphObject grobj;
Tree trColor;
fpoint ptNode;
foreach(grobj in coll)
{
grobj.GetNode(0, ptNode);
trColor=grobj.GetFormat(FPB_STYLE_COLOR, FOB_OBJECT, TRUE, TRUE);
vX.Add(ptNode.x);
vCol.Add(trColor.Root.Color.nVal);
nLim++;
nLimD++;
}
}
vCol.Replace(22657947,1,MATREPL_TEST_EQUAL);
vCol.Replace(21844160,-1,MATREPL_TEST_EQUAL);
ocmath_sort_xy(vX, vCol, nLim);
}
vecX=vX;
vecDir=vCol;
return nLim;
}
|
 |
|
cpyang
USA
1406 Posts |
Posted - 08/31/2017 : 12:27:48 PM
|
2018 will have general OC access to all the LT properties, this will include GraphObject, Column, Worksheet, etc. I tested with Roman's project with 1000 lines.
int cc()
{
vector<double> vPos;
vector<int> vColor;
int n=0;
GraphLayer gly = Project.ActiveLayer();
if( gly.IsValid() )
{
vector<double> xx;
foreach (GraphObject go in gly.GraphObjects)
{
if(go.GetName().Left(4)=="Line")
{
vColor.Add(go.GetProp("color"));//color is integeter, can directly return
double xPos=0;
go.GetProp("x1",&xPos);
vPos.Add(xPos);
n++;
}
}
}
return n;
}
On my machine this now takes 17ms, while the corresponding LT code takes 173 ms.
CP
|
 |
|
|
Topic  |
|
|
|