6 Replies Latest reply: Dec 6, 2016 5:55 AM by moran pliner RSS

    Get fields name of an IGenericObject

    moran pliner

      Hello,
      I'm new to Qlik Sense sdk and I'm trying to retrieve the data of an IGenericObject,
      I've encountered with a few issues:

       

      1. How do I know the height and width of the IGenericObject data?

       

      I found this code but not all the object are HyperCube (what type of object is myObject in the code below)

       

      var first10RowsPage = new NxPage { Top = 0, Left = 0, Width = myObject.HyperCube.Size.cx, Height = myObject.HyperCube.Size.cy };


      2. When I get the result I can't seem to find the column names and I only get the matrix with the data.

      3. Not all object types has the method: GetData(...), e.g :filterpane

      4. Is there a way to retrieve all the data without paging?


      Here is my code for a table type object:

      IGenericObject child = sheet.GetChild(objId);

      System.Data.DataTable dt = null;


      var cellsPage = new NxPage { Top = 0, Height = 100, Left = 0, Width = 100 };

       

      Table tbl = (Table)child;

      IEnumerable<NxDataPage> data= tbl.GetData(new[] { cellsPage });

       

      foreach (NxDataPage page in data)

      {

        IEnumerable<NxCellRows> rows = page.Matrix;

        if (dt==null)

        {

            dt = new System.Data.DataTable();

        Rect rect = page.Area;

        int colCount = rect.Width;

        for (int i = 0; i < colCount; i++)

        {

      dt.Columns.Add("col_" + i);

        }

        }

        foreach (NxCellRows row in rows)

        {

        DataRow dr = dt.NewRow();

        int j = 0;

        foreach (NxCell cell in row)

        {

        String value = "";

        double num = cell.Num;

        if (Double.IsNaN(num))

            value = cell.Text;

        else

            value = num + "";

        dr[j] = value;

        j++;

        }

        dt.Rows.Add(dr);

        }

      }

           

      Thanks in advance,

        • Re: Get fields name of an IGenericObject
          Lars-Goran Book

          Hi,

          1. IGenericObject is a base class, you must use abstract structure to data as different objects for example :
          var myHypercube =  genericObject.Get<HyperCube>("hypercube")

          myHypercube.Size...

           

          2. You must access the hypercube properties, the DimensionInfo array and MeasureInfo array.

           

          3. Filterpane is an array of ListObjects (IListBox), you will need to retrieve its children.
          Example:

          if (filterpane.Items.Any())

          {

            return "[" + chart.Items.Select(item => (IListbox)chart.GetChild(item.Info.Id)).Aggregate("", (current, child) => current + String.Join(", ", child.Properties.ListObjectDef.Def.FieldDefs)) + "]";

          }

           

          4. If you have a small amount data you can set the InitialDataFetch size to the size of the field. NOTE this can have performance impacts.

           

          Best regards

          Lars-Göran Book

            • Re: Get fields name of an IGenericObject
              moran pliner

              Hi Lars,

               

              Thank you for your response,

              I'm still left with the question how do I retrieve the data from all types of object,

              since not all object are hypercubes.

               

              I need to support the following types:

              barchart,combochart,filterpane,scatterplot,pivot-table,table,kpi,piechart,linechart,treemap,map,gauge,text-image

               

              I've tried to get the hypercube of the objects but it doesn't work,


              IGenericObject iGenObj = (IGenericObject)iapp.GetGenericObject(objId);

              var myHypercube =  iGenObj .Get<HyperCube>("hypercube")??

               

              I also tried to get the hypercube of a table:

              String type = iGenObj.Info.Type;

              Table tbl = (Table)iGenObj;

              var myHypercube =  tbl.Get<HyperCube>("hypercube")??

               

              what did you mean by : you must use abstract structure to data as different objects

              can you give me example of a structure that has the method Get<HyperCube>("hypercube")

               

              All I managed do so far is to get the pages of the object, go through them and get the matrix of each page,

               

              for example, if the object is table type

               

              Table tbl = (Table)iGenObj;

              IEnumerable<NxDataPage> pages = tbl.DataPages;

              for (int i = 0; i < pages.Count() ; i++) {

                        var page = pages.ElementAt(i);

                        IEnumerable<NxCellRows> rows=page.Matrix;

              }

               

              But as I've mentioned before I don't know which field belongs to which column,

              Am I missing something?

               

              Thanks again,
              Moran

                • Re: Get fields name of an IGenericObject
                  Patric Amatulli

                  Hi Moran,

                   

                  have you got a solution?

                  I am stuck in the same problem.

                   

                  How we can retrieve dynamically the size of a Hypercube?

                  I tried several approaches but without any success.

                   

                  var genericObject = app.GetGenericObject(objId);
                     
                  var first10RowsPage = new NxPage { Top = 0, Left = 0, Width = 2, Height = 10 };
                  IEnumerable<NxDataPage> data = genericObject.GetHyperCubeData("/qHyperCubeDef", new[] { first10RowsPage });
                  
                  

                   

                  I read that on hypercube level there is the property size which can help me to get the width and height dynamically.

                  Can someone of you give me an example how to access this property?

                   

                  Thanks and regards,

                   

                  Patric

                    • Re: Get fields name of an IGenericObject
                      Øystein Kolsrud

                      I think there is some confusion regarding a couple of concepts here. GenericObject is the base class of all visualization objects (like bar charts), but a generic object can not be a hypercube directly. Instead, a GenericObject has a properties definitions that may contain definitions of hypercubes. The data for the hypercube is extract from the layout of the object. I have created a project on branch that illustrates how to work with hypercubes through the SDK:

                       

                      http://branch.qlik.com/#!/project/5818518b9fa7b8156fa73588

                       

                      There is a class in the SDK called HyperCubePager that you can use to access the size information you are looking for. The class is primarily intended to make it easy to access hypercube data from generic objects, but you can also get information about the table size there. If you know there is exactly one hypercube in your object, then you can do something like this:

                       

                      var thePager = theObject.GetAllHyperCubePagers().Single();
                      var columns = thePager.NumberOfColumns;
                      var rows = thePager.NumberOfRows;
                      
                      

                       

                      You might also want to have a look at this the following page, and its sub pages discussing generic objects and paging:

                       

                      Retrieving data ‒ Qlik Sense

                       

                      Best regards, Øystein Kolsrud

                      • Re: Get fields name of an IGenericObject
                        Øystein Kolsrud

                        As a side note, the classes representing client visualizations contain a set of properties that are basically short cuts to those elements of the layout of the object. If you for instance want to access the title of a bar chart, then you can do like this:

                         

                        IBarchart theBarChart;
                        var title = theBarChart.Title;
                        

                         

                        This will be equivalent to getting the layout of the bar chart and then accessing the Title property of the layout. Like this:

                         

                        IBarchart theBarChart;
                        IBarchartLayout theLayout = theBarChart.GetLayout().As<BarchartLayout>();
                        var title = theLayout.Title;
                        

                         

                        The call to "As<BarchartLayout>()" in row two above is used to reinterpret the GenericObjectLayout returned by the GetLayout call as an instance of BarchartLayout. This utilizes the "AbstractStructure" concept to do reinterpretation of data returned from the engine (which is originally untyped json). More information about the "AbstractStructure" concept can be found here:

                         

                        http://help.qlik.com/en-US/sense-developer/3.1/Subsystems/NetSDKAPI/Content/HowTos/Net-Sdk-How-To-Abstarct-Structure.htm

                        • Re: Get fields name of an IGenericObject
                          moran pliner

                          Hi Patric,

                           

                          I was able to come up with a solution, I'm going to demonstrate it on a table object:

                           

                          IGenericObject iGenObj = (IGenericObject)iapp.GetGenericObject(objId);

                          Table tbl = (Table)iGenObj;

                          HyperCubePager hcp = tbl.HyperCubePager;

                          int numOfColumns = hcp.NumberOfColumns;

                          int numOfRows = hcp.NumberOfRows;

                           

                            IEnumerable<IEnumerable<NxDataPage>> allDataPagesNext = hcp.IteratePages(new[] { new NxPage { Top = 0, Height = 1000, Left = 0, Width = numOfColumns } }, Pager.Next);

                          foreach (IEnumerable<NxDataPage> pages in allDataPagesNext){

                          ..........................

                          }

                           

                          I set Height (number of rows in a page) to be 1000 and not numOfRows since I want to manage the pages size,

                          The function IteratePages iterates all the pages according to the size you give it

                           

                          This link really helped me:
                          https://help.qlik.com/en-US/sense-developer/2.2/Subsystems/NetSDKAPI/Content/HowTos/Net-Sdk-How-To-Paging.htm

                           

                          Hope I helped you,

                          Moran