DataObject Introduction


Introduction

DataObject was created specifically for use with the INT ChartObject, which allows developers to create a wide variety of graphical data displays in the Motif environment easily. DataObject simply provides the mechanism to "package" and edit data, while the ChartObject provides the graphical viewing tools.

DataObject is a system of Xt intrinsic tools that provides for the retrieval, storage and manipulation of sets or groups of data. DataObject serves as the model component of the MVC architecture described earlier. As explained in the following pages, treating sets of data as individual objects not only makes the MVC architecture possible, but also provides the mechanism for a wide range of advanced data handling and graphical display features.


Summary of components

DataObject provides the following object classes that can be used to classify and manipulate sets of data:

Similar to the the GraphicObject classes, the data classes are all derived from the Xt Object class. These classes can be manipulated using resources, functions, and callbacks, just like any standard Motif/Xt object or widget. The data objects must not be managed. Modification of the data can be accomplished using either standard Xt resource setting mechanisms or the convenience functions provided by INT.


Example

The following illustration shows a bar chart view containing annual sales data for four metropolitan areas.


Figure 4: Bar Chart View of Grouped DataSampled Objects

The following example (see file chart_1.c in directory examples) shows the complete programming code required to produce the bar chart display shown above.

    #include <Xint/EditObject.h>
    #include <Xint/Chart.h>

    static String   x_labels[] = {"Houston", "Dallas", "Austin", "San Antonio"};
    static float    d1992[] = { 00.0, 30.0, 20.0, 20.0};
    static float    d1993[] = { 10.0, 45.0, 32.0, 30.0};
    static float    d1994[] = { 15.0, 25.0, 27.0, 35.0};
    
    main(argc, argv)
    int     argc;
    char    *argv[];
    {
      XtAppContext  app_context;
      Widget        top_level;
      Widget        edit;
      Object        data_group;
      Object        chart;
      XintGeometry  chart_geometry;

      top_level  = XtAppInitialize(&app_context, "test",
	                           (XrmOptionDescList)NULL, 0,
	                           &argc, argv, NULL, NULL, 0);

      /* Create an EditObject widget*/

      edit = XtVaCreateManagedWidget("edit_object", 
	                             xintEditObjectWidgetClass,top_level,
	                             XmNwidth, 600, XmNheight, 600,
	                             XmNobjectEditMode, XintEDIT_ADJUST,
	                             NULL);

      /* Create Chart object */

       chart_geometry.x1 = 0;
       chart_geometry.y1 = 0;
       chart_geometry.x2 = 100;
       chart_geometry.y2 = 100;
       chart = (Object) XtVaCreateWidget("BarPlot",
                                         (WidgetClass)xintChartObjectClass, 
                                         edit,
                                         XmNgeometry, &chart_geometry,
                                         XmNchartType, XintCHART_TYPE_BAR,
                                         XmNchartTitle, "Yearly Sales",
                                         XmNshowLegend, True,
                                         NULL);

       /* Create a data group */

       data_group = XintCreateDataGroup(edit, "Yearly Sales", NULL, 0);

       XtVaCreateWidget("Cities", (WidgetClass)xintDataLabelObjectClass, 
                        edit,
                        XmNlabelStrings, x_labels,
                        XmNlabelCount, sizeof(x_labels)/sizeof(String),
                        XmNlabelOrientation, XintLABEL_X,
                        XmNdataGroup, data_group, NULL);

       XtVaCreateWidget("1992", (WidgetClass)xintDataSampledObjectClass, 
                        edit,
                        XmNdataArray, d1992,
                        XmNcount, sizeof(d1992)/sizeof(float),
                        XmNdataType, XintDATA_TYPE_FLOAT,
                        XmNdataGroup, data_group, NULL);

       XtVaCreateWidget("1993", (WidgetClass)xintDataSampledObjectClass, 
                        edit,
                        XmNdataArray, d1993,
                        XmNcount, sizeof(d1993)/sizeof(float),
                        XmNdataType, XintDATA_TYPE_FLOAT,
                        XmNdataGroup, data_group, NULL);

       XtVaCreateWidget("1994", (WidgetClass)xintDataSampledObjectClass, 
                        edit,
                        XmNdataArray, d1994,
                        XmNcount, sizeof(d1994)/sizeof(float),
                        XmNdataType, XintDATA_TYPE_FLOAT,
                        XmNdataGroup, data_group, NULL);

       /* Associate the data group with the chart object */

       XintChartAssociateData(chart, data_group);

       /* Loop forever */

       XtRealizeWidget(top_level);
       XtAppMainLoop(app_context);
    }


Understanding Groups

In the previous example, notice that we created a group containing multiple data objects. The DataGroup conceptually serves as a "container" for all other data object classes. The following diagram shows an example of parent-child relationships that could occur between various objects in a group.


Figure 5: Example of a DataObject group

Notice that you can have multiple instances of any data object type within the same group. The DataLabel object provides annotation for either the entire group or for individual objects. It accompanies the group to any destination view, and is inserted into the view in the appropriate context (for example, as column/row annotation in a table or as an axis label in a chart).


Linked Views

The object classes discussed above allow interlinking between multiple views of the same data, so that any changes to one view are automatically applied to all other connected views. For example, if the user changes data in a table view (such as INT's EditTable), this automatically updates the model and the model updates all other views, such as bar charts, pie charts, and all the other INT chart types.

Drag and Drop

DataObject provides an advanced, built-in "drag and drop" feature that allows users to select any group of data from one view, then drag the data and drop it into another view, effectively creating a linked view as described above. For instance, the user might highlight a range of cells in a table then drag and drop the highlighted selection into a chart. When this happens, the data points that were dragged to the chart are automatically inserted correctly in the appropriate view context. If the user drags data into a bar chart, it appears as a series of bars; in a pie chart it appears as a series of wedges, and so forth. The drag and drop function can optionally link the views so that updates in one are automatically reflected in the other.

In addition, the data labelling follows the data from one view to the next. In a table, the labels might appear as horizontal and vertical titles. In a chart they appear as axis labels. When a user performs a drag-and-drop, the built-in widget mechanism automatically creates the appropriate groups and data objects to accomplish the task. The widget automatically maintains correct hierarchical relationships between data elements, and attaches the appropriate label to the new view.


Missing Values

All data objects that handle numerical values support the concept of missing or null values. To specify that a data value is missing just insert one of the following constants into the data array based on the data format.

ConstantDescription
XintUNDEFINED_DOUBLEMissing value for double data format.
XintUNDEFINED_FLOATMissing value for float data format.
XintUNDEFINED_INTEGERMissing value for integer data format.
XintUNDEFINED_LONGMissing value for long data format.
XintUNDEFINED_SHORTMissing value for short data format.


Creating a View

Data objects or groups are associated with chart objects through the following function:

     void XintChartAssociateData (Object chart, Object data)

This function creates a view of the data object that is displayed by the chart object. See Reference pages for more information on this function.

A similar function is available to associate a data object with an EditTable widget:

     Boolean XintEditTableAssociateData(Widget edit_table, Object data, 
                                        int col_start, int row_start, 
                                        Boolean link)

See the EditTable Reference pages for a complete description of this function.


Data Editing

DataObject provides editing functions that are available to both the application programmer and the end-user. An application programmer may modify the contents of a data object through resources (XtSetValues or XtVaSetValues) or convenience functions. Whenever possible, it is better to update the data using the convenience functions provided by the various data objects classes for optimization reasons. The following code segment shows how to replace the first sample in a DataSampled object:

    float new_value;
    ...
    XintDataSampledReplace (data_sampled, &new_value, 0, 1);

The end-user of an application may optionally modify data indirectly by interactively editing a tabular or graphical view of the data. Real-time editing features for replacing, extending or shifting the contents of a data object are also provided. Application programmers can be notified of editing operations using the callback XmNupdateCallback, which can be registered on each data object or at the data group level and may override any requested editing operation. Also, resource XmNeditable can be used to prevent a specific data object or data group from being modified through the editing of a graphical view.

Data groups can also be modified at any time by adding or destroying data objects. Again, if the data group is connected to a chart, the chart will automatically update itself to take into account the changes in the data.

If you need to update several data objects inside a data group that is connected to a chart, use function XintDataBatchUpdate to freeze the propagation of updates to the views and minimize flashing. The following code sample illustrates how to insert two new DataSampled objects to a data group data_group that is already connected to a chart.

    /* Freeze propagation of updates for this data group */
    XintDataBatchUpdate(data_group, True);

    /* add the two new data_sampled objects */
    XtVaCreateWidget ("new1", (WidgetClass) xintDataSampledObjectClass,
                      edit,
                      XmNdataArray, data1,
                      XmNcount,     count1,
                      XmNdataGroup, data_group, NULL);
    XtVaCreateWidget ("new2", (WidgetClass) xintDataSampledObjectClass,
                      edit,
                      XmNdataArray, data2,
                      XmNcount,     count2,
                      XmNdataGroup, data_group, NULL);

   /* allow updates */
   XintDataBatchUpdate(data_group, False);


Memory Allocation

By default, data objects make an internal copy of the data. Set resource XmNcopyData to False, when creating the data object, if you don't want the data object to copy your data. In this case, the data passed to the data object should not be deallocated so long as the data object is not destroyed.

Data resource XmNlastViewDestroy can be used to cause a data object be destroyed automatically after it is no longer associated with a view (chart or table). If you are using a data group, you only need to set this resource on the data group; you don't need to set it for the data objects belonging to the data group.


Navigating Inside a DataGroup

If you are using a DataGroup object to store your data, you don't need to keep your own list of the data objects belonging to the data group. Function XintDataGroupIterate is designed to retrieve data objects from a data group. For example, the following code sample shows how to print the name of all the data objects of type DataSeries in DataGroup data_group.

    Object data_group, data_series;
    ...
    index = 0;
    while ((data_series = XintDataGroupIterate (data_group, 
            xintDataSeriesObjectClass, index++)) != NULL) {

            printf("series name = %s number = %d\n", 
                   XtName((Widget) data_series), index);
    }

If you specify NULL for the name of the object class, function XintDataGroupIterate iterates through all the data objects, whatever the type.