How to Plot 3D Boxes in Origin

This blog describes how to make 3D boxes like the following picture by a LabTalk function. (Click picture to enlarge.)


This graph sample was created by the following LabTalk code, which contains four functions – plot3DBox to make a single 3D box and its subroutines plotOneSide and cleanMatData, and the main function make3DBoxes to create multiple boxes specified in a worksheet (Book1 in above sample). You can run the program by simply issuing make3DBoxes command in the Script window,

 

[Main]
@global = 1; //Set the following as global functions
// The explanation of this script can be find in the blog at: https://blog.originlab.com/graphing/how-to-plot-3d-cubes-in-origin

//################################################################################################
function int plotOneSide(int isheet, string gname$, int colorN) {
  if(exist(gname$)!=3)       //Plot the face in new graph
    plotm im:=[%K]$(isheet)!1 plot:=103 x:=2 y:=3;
  else                       //Plot the face into existing graph
    plotm im:=[%K]$(isheet)!1 plot:=103 x:=2 y:=3 ogl:=[gname$]1!;
  set %K@$(isheet) -b3cc colorN; //Set color
  set %K@$(isheet) -b3m 0;       //No meshgrid
  return 0;
}
//################################################################################################
function int cleanMatData(string mname$, int isheet) {
    //Copy face matrix to a Msheet
    range minp=[%(mname$)]1!1, mout=[%K]$(isheet)!1; mcopy im:=minp om:=mout; 
    range minp=[%(mname$)]1!2, mout=[%K]$(isheet)!2; mcopy im:=minp om:=mout; 
    range minp=[%(mname$)]1!3, mout=[%K]$(isheet)!3; mcopy im:=minp om:=mout; 
    layer.name$=mname$;   //Give the face name to the MSheet
    window -cd %(mname$); //Delete original matrix
    Return 0;
}
//################################################################################################
function int plot3DBox(ref string gname$, double Px1, double Py1, double Pz1, double Wx, double Wy, double Wz, int colorLR, int colorFB, int colorTB) {
    double Px2=Px1+Wx, Py2=Py1+Wy, Pz2=Pz1+Wz;
    int newg = exist(gname$)==3?0:1;  //Flag whether new graph, or not
    int npts = 2;   //Face matrix dimension
    window -t mat;  //Make a new MBook
    %K=%H;          //MBook name
    page.comments$="Pos=["+Text(Px1)$+","+Text(Py1)$+","+Text(Pz1)$+"] Dim=["+Text(Wx)$+","+Text(Wy)$+","+Text(Wz)$+"]";

    ///////////////// Create Matrices for 3D pParametric Function Plot ///////////////////////////
    //// LEFT ///////////////////////////////////////////////////
    create myx -fp2 npts u Px1 Px2 npts Pz1 Pz2;      //Create 2D loose datasets for X
    create myy -fp2 npts Py1 Px1 Px2 npts Pz1 Pz2;      //Create 2D loose datasets for Y
    create myz -fp2 npts v Px1 Px2 npts Pz1 Pz2;      //Create 2D loose datasets for Z
    create LEFT -mfph myz myx myy "u,v";  //Create matrices for LEFT for 3D parametric function plot
    cleanMatData("LEFT",2); 
    //// RIGHT ///////////////////////////////////////////////////
    create myx -fp2 npts u Px2 Px1 npts Pz1 Pz2;    //Create 2D loose datasets for X: Outward face
    create myy -fp2 npts Py2 Px1 Px2 npts Pz1 Pz2;    //Create 2D loose datasets for Y
    create myz -fp2 npts v Px1 Px2 npts Pz1 Pz2;     //Create 2D loose datasets for Z
    create RIGHT -mfph myz myx myy "u,v";  //Create matrices for RIGHT
    cleanMatData("RIGHT",3); 
    //// FRONT  ///////////////////////////////////////////////////
    create myx -fp2 npts Px2 Py1 Py2 npts Pz1 Pz2;    //Create 2D loose datasets for X
    create myy -fp2 npts u Py1 Py2 npts Pz1 Pz2;     //Create 2D loose datasets for Y
    create myz -fp2 npts v Py1 Py2 npts Pz1 Pz2;     //Create 2D loose datasets for Z
    create FRONT -mfph myz myx myy "u,v";  //Create matrices for FRONT
    cleanMatData("FRONT",4); 
    //// BACK  ///////////////////////////////////////////////////
    create myx -fp2 npts Px1 Py1 Py2 npts Pz1 Pz2;    //Create 2D loose datasets for X
    create myy -fp2 npts u Py2 Py1 npts Pz2 Pz1;    //Create 2D loose datasets for Y: Outward face
    create myz -fp2 npts v Py1 Py2 npts Pz1 Pz2;     //Create 2D loose datasets for Z
    create BACK -mfph myz myx myy "u,v";  //Create matrices for BACK
    cleanMatData("BACK",5); 
    //// TOP  ///////////////////////////////////////////////////
    create myx -fp2 npts u Px1 Px2 npts Py1 Py2;     //Create 2D loose datasets for X
    create myy -fp2 npts v Px1 Px2 npts Py1 Py2;     //Create 2D loose datasets for Y
    create myz -fp2 npts Pz2 Px1 Px2 npts Py1 Py2;    //Create 2D loose datasets for Z
    create TOP -mfph myz myx myy "u,v";  //Create matrices for TOP
    cleanMatData("TOP",6); 
    //// BOTTOM  ///////////////////////////////////////////////////
    create myx -fp2 npts u Px2 Px1 npts Py1 Py2;    //Create 2D loose datasets for X: Outward face
    create myy -fp2 npts v Px1 Px2 npts Py1 Py2;     //Create 2D loose datasets for Y
    create myz -fp2 npts Pz1 Px1 Px2 npts Py1 Py2;    //Create 2D loose datasets for Z
    create BOTTOM -mfph myz myx myy "u,v";  //Create matrices for BOTTOM
    cleanMatData("BOTTOM",7);
    //////////////////////////////////////////////////////////

    //Make All Faces of the 3D Box
    if(newg==0) {  //Add a plot to the existing gname$ for LEFT
      win -o %(gname$) {
        plotOneSide(2, gname$, colorLR);  //plot LEFT wall in CYAN
      }
    }
    else {  //Create a new graph for LEFT
        plotOneSide(2, gname$, colorLR);  //plot LEFT wall in CYAN
        gname$=%H; //hold the created graph window name
    }
    win -o %(gname$) {  //Make other faces
        plotOneSide(3, gname$, colorLR);  //plot RIGHT wall in CYAN
        plotOneSide(4, gname$, colorFB);  //plot FRONT wall in CYAN
        plotOneSide(5, gname$, colorFB);  //plot BACK wall in CYAN
        plotOneSide(6, gname$, colorTB);  //plot TOP wall in CYAN
        plotOneSide(7, gname$, colorTB); //plot BOTTOM wall in CYAN
    }
    window -a %K;    //Activate the MBook
    layer -d 1;      //Delete unnecessary first MSheet
    window -hc 1 %K; //Hide matrix window
    return 0;
}
//################################################################################################
function int make3DBoxes() {  //Make 3D Boxes from a Worksheet
  if(exist(%H)!=2) {
    type -a [make3DBoxes] Error! The current window is not a workbook.;
    Return 0;
  }
  if(wks.nCols<9) {
    type -a [make3DBoxes] Error! Your worksheet does not have necessary 9 columns.;
    Return 0;
  }
  int nr=wks.maxRows;
  range rPx=col(1);  //X column of Base Point
  range rPy=col(2);  //Y column of Base Point
  range rPz=col(3);  //Z column of Base Point
  range rWx=col(4);  //Column of X length
  range rWy=col(5);  //Column of Y length
  range rWz=col(6);  //Column of Z length
  range rcLR=col(7); //Column for LEFT/RIGHT color
  range rcFB=col(8); //Column for FRONT/BACK color
  range rcTB=col(9); //Column for TOP/BOTTOM color
  string str$;
  for(ii=1; ii<=nr; ii++) { 
    plot3DBox(str, rPx[ii],rPy[ii],rPz[ii], rWx[ii],rWy[ii],rWz[ii], rcLR[ii],rcFB[ii],rcTB[ii]);
  }
  type -a [make3DBoxes] Total $(nr) 3D boxes have been created.;
  Return 0;
}
//################################################################################################
@global = 0; //End of the global functions

 

Procedure

To Run this Script to make 3D Boxes from a worksheet data, you can follow the four steps below:

1) Using Notepad, save this script code as a script file, make3DBoxes.OGS in your User Files Folder(UFF).
Or, you can download the ZIP file of the code from here , and put the content “make3DBoxes.OGS” in the ZIP file into your UFF.
(To open your UFF location, choose “Help: Open Folder: User Files Folder” menu in Origin.)

2) For startup loading of the global functions, find Origin.INI file in your UFF, open it by Notepad, find “[Startup]” section, insert the following line just under this section line (where # is a number like 1, 2, 3,…):
File#=3DBoxes.OGS
and save it. Now you are ready to run “make3DBoxes” command any time available in Origin as described in the following steps. (See the details of these two steps here.)

3) Start Origin (your global functions will be automatically loaded), create a worksheet with 9 columns, and enter the data of your boxes. Each row of the worksheet specifies a box’s corner position, dimensions, and the colors. (See the sample worksheet in the above screenshot.) The columns contain the following data:
Column 1/2/3 : the base coordinates, X/Y/Z coordinates
Column 4/5/6 : Dimensions of the 3D box in X/Y/Z directions
Column 7/8/9 : Face pair colors of Right+Left/Front+Back/Top+Bottom. (1=Black, 2=Red, 3=Green, 4=Blue,… etc. See the whole color list.)

4) Set the worksheet active, and issue the following command in the Command window or in Script window:
make3DBoxes
Origin now draws 3D boxes specified in the worksheet, in a graph window.

If you want to draw a 3D box  in an existing 3D graph such as with a 3D scatter plot, you can issue a command like the following:

string str$=%H; //Set the current graph name
plot3DBox(str, 0, 0, 0, 1, 1, 1, 8, 3, 11);  //Make a 3D box into the graph where P=[0,0,0], Dim=[1,1,1], Colors=[8,3,9]

Finally, note that you can customize this sample code for your needs such as for specifying subtle colors using RGB values (using color() function), specifying six distinct colors for all faces (by increasing the number of color arguments), drawing edge lines (by overlaying 3D line plots), etc.

 

Notes

1: Currently LabTalk lacks the capability to control the transparency of the surface. OriginLab is working to implement this feature, and once it is done, I will update the above sample code.

2: This script code was modified from the sample code in this help page. In this sample code, you can find a sample function to draw a sphere.

3: You can also make a function to create a rectangle (similar to plotOneSide in this blog’s sample) by creating two triangles as a “triangle patch” from a worksheet which contains 4 columns; the first three for corner XYZ coordinates, and the fourth for the route of the corner connections. After creating the worksheet, you can create a Color Fill 3D Surface plot, then execute “Set -spi ” command like the following pseudo code:

  plotxyz iz:=<<Zcolumn>> plot:=103 ogl:=<new template:=glMESH.otp>;  //Plot Color Fill Surface
  set <<Zcolumn>> -spi 2;       //Set the next right column of Z to the route of the "triangular-patch"

 

Leave a Reply

Your email address will not be published. Required fields are marked *