Skip to content

Dynamic Subgroups

Subscription Tier Required

This feature requires the Premier subscription tier or higher.

Sometimes the number of samples being taken varies. This can happen for a number of reasons, such as:

  • Machines which have varying numbers of cavities.
  • Inconsistent product sampling.
  • Varying sampling rate requirements for different vendors.

In this guide, you will create an Inspection where the number of checks taken will vary based on the Machine Traceability selected by the operator. Each group of measurements will be automatically tagged with the appropriate Cavity Traceability, based on how many checks are being performed.

Warning

This guide changes the number of samples by copying Tests. While it is possible to modify the subgroup size of SPC Tests via scripting, it is not recommended. Most SPC statistics rely on a consistent subgroup size for statistical validity. In general, if you find yourself needing a varying subgroup size, you should instead use a subgroup size of 1 and take multiple measurements.

Prerequisites

This guide assumes that you have:

This guide will use:

  • The Final Inspection Process.
  • A Part named AD-50 with the Width Characteristic.
  • The Scratch Defect.

The Machine Traceability will make use of Preset Values, which will restrict the operators to a dropdown list. For the purpose of this guide, the preset values will be A, B, and C.

Information

Even though the Cavity Traceability will appear to be recorded as an integer, it is set up as a Text Traceability. This is because it is generally more useful to analyze Cavities as categories. A good litmus test for whether to use Text or Integer Traceability is whether you can change the numbers to letters. If changing your cavities from 1, 2, 3 to A, B, C does not change your analysis, then you should use Text.

Create the Inspection

To begin, create an Inspection:

  1. Navigate to the Inspection list.
  2. Press the Add button. An image showing the location of the Add button on the Inspection list
  3. Fill in the Name field with Dynamic Subgroups.
  4. Press the Save button. An image showing the location of the save button on the Inspection create

For this guide, the Process will be set directly on the Inspection. If you only have one Process created in your GS account, it will automatically be set on the Inspection. If you have created more than one Process, it will need to be set. To do this, open the Inspection Settings and select the desired Process.

Finally, open the Inspection Settings and set Auto-load first Sub-Inspection to Yes.

Traceability Test

Add a Traceability Test and select the Machine Traceability. Update the Script ID of this Test to machine.

An image showing the added Traceability test

Group Test

Add a Group Test. This will allow duplicating an entire group of Tests at once, instead of having to clone each Test individually.

Uncheck the Visible property, and set the Script ID of the Group Test to group-1.

An image showing the added Group Test

SPC Test

Drag an SPC Test into the Group Test. Position the SPC Test all the way on the left side of the Group Test, and set the Script ID to spc-test-1. Select the Width Characteristic for the AD-50 Part. If you chose a different Characteristic for this guide, select that instead.

An image showing the added SPC Test

Pass/Fail Test

Next, add a Pass/Fail Test to the Group. Reposition the SPC and Pass/Fail Test so they each take 50% of the width of the Group Test.

Select the Scratch Defect on the Pass/Fail Test, and set the Script ID to passfail-test-1.

An image showing the added Pass/Fail

Scripting

Now that the Inspection has been set up, you can begin scripting. Create a new Inspection Script and give it a memorable name. If this interface is unfamiliar, review the Inspection Scripting Principles and Code Editor articles.

An image showing the location of the Inspection Script action

An image showing the location of the add button in the Inspection Script overlay

The tasks we will use scripting to accomplish are:

  1. Listening for changes to the Machine Traceability.
  2. Adding or deleting Tests to take the appropriate number of checks for that Machine.
  3. Setting the Cavity as Traceability on each set of Tests.

Listen to Machine Traceability

In the newly created Inspection Script, get a reference to the Traceability API for the Traceability Test with the Script ID machine:

const subInspection = gsApi.inspection.subInspection('subi 1');
const machineTraceability = subInspection.traceability('machine');

Information

The first Sub-Inspection will have a Script ID of subi 1 by default. This may be changed in the Sub-Inspection Settings.

Next, bind to the onOptionSelected event:

machineTraceability.onOptionSelected(async () => {

});

This event will fire whenever a preset option is selected on this Traceability Test.

Update Number of Tests

In order to update the number of checks required, we will need to create a mapping from the Machine to the number of cavities available on that machine. Typically, this would come from a third party system or a file uploaded to GS. For the purpose of this guide, we will create this mapping directly in code:

const machineTraceability = subInspection.traceability('machine');
const machineToCavity = {
    A: 2,
    B: 4,
    C: 6
};

When the Machine Traceability is updated, look up the number of cavities and add or remove Tests to get the correct number of checks. We will also keep track of the current number of checks being performed, so we know how many Tests to add or remove when the Machine Traceability is updated:

let currentChecks = undefined;
machineTraceability.onOptionSelected(async () => {
    const properties = await machineTraceability.getProperties();
    const totalCavities = machineToCavity[properties.value];

    if (totalCavities === currentChecks) {
        // Already have the correct number of checks, return
        return;
    }
});

Next, check if it's the first time a Machine has been selected by the operator. If so, then currentChecks becomes 1 (for the existing group which was made in the UI), and that Group Test is set to visible:

if (totalCavities === currentChecks) {
    // Already have the correct number of checks, return
    return;
}

if (currentChecks === undefined) {
    // First run, make the first set of tests visible
    await subInspection.group('group-1').updateProperties({
        userDefinedVisible: true
    });
    currentChecks = 1;
}

It is time to start adding and removing groups. If the newly selected Machine has more cavities than the previously selected Machine (or if no Machine was previously selected), then Tests should be added. This is done by iterating upward from the current number of checks until we have reached the total number of checks which must be performed, and adding a new Group Test for each iteration. Each new Group Test will have the scriptId set based on the index, and it will use the copyFrom property to copy all of the properties and Tests within group-1.

if (totalCavities > currentChecks) {
    // Need to add additional checks
    for (let i = currentChecks + 1; i <= totalCavities; i++) {
        await subInspection.addGroupTest({
            copyFrom: 'group-1',
            scriptId: `group-${i}`,
        });
    }
}

Otherwise, if the newest Machine has fewer cavities than the previously selected Machine, any additional categories should be removed:

if (totalCavities > currentChecks) {
    ...
} else {
    // Need to remove checks
    for (let i = currentChecks; i > totalCavities; i--) {
        await subInspection.removeTest(`group-${i}`);
    }
}

Set Appropriate Cavity

When creating a new group, all Tests inside the group should have the Cavity Traceability set to the correct value. Begin by retrieving the ID of the Cavity Traceability:

const cavityPromise = gsApi.entity.getTraceabilityIdByName('Cavity');

Note that this does not use the await keyword. Instead, we are issuing a request to retrieve the Traceability's ID as soon as the script is loaded, and storing the resulting Promise for later use. This will allow us to begin fetching as soon as the script loads, but ensure that it has finished loading when the Traceability ID is actually needed:

await subInspection.addGroupTest({
    copyFrom: 'group-1',
    scriptId: `group-${i}`
});
const properties = await subInspection.group(groupId).getProperties();
for (let i = 0; i < properties.tests.length; i++) {
    const test = properties.tests[i];
    if (test.type === 'spc') {
        await subInspection.spc(test.scriptId).updateProperties({
            testSpecificTrace: [{
                traceabilityId: await cavityPromise,
                value: 1
            }]
        });
    } else if (test.type === 'passFail') {
        await subInspection.passFail(test.scriptId).updateProperties({
            testSpecificTrace: [{
                traceabilityId: await cavityPromise,
                value: 1
            }]
        });
    }
}

Additionally, apply the same Test Specific Traceability to the SPC and Pass/Fail Test in group-1 when it is first shown:

    await subInspection.group('group-1').updateProperties({
        userDefinedVisible: true
    });
    await subInspection.spc('spc-test-1').updateProperties({
        testSpecificTrace: [{
            traceabilityId: await cavityPromise,
            value: 1
        }]
    });
    await subInspection.passFail('passfail-test-1').updateProperties({
        testSpecificTrace: [{
            traceabilityId: await cavityPromise,
            value: 1
        }]
    });
    currentChecks = 1;

Information

await may be used on the same Promise multiple times. When the Promise is initially resolved, the value will be cached and returned on each subsequent await.

Test the Inspection

Save and Run the Inspection. Try selecting different Machines and submitting data. See that the number of measurements is updated dynamically as the Traceability value changes. Try drawing some charts in a Dashboard and check that the Cavity Traceability is set correctly.

An image the running Inspection, with Machine A selected and two group Tests

Final Code

const subInspection = gsApi.inspection.subInspection('subi 1');
const machineTraceability = subInspection.traceability('machine');
const machineToCavity = {
    A: 2,
    B: 4,
    C: 6
};
const cavityPromise = gsApi.entity.getTraceabilityIdByName('Cavity');
let currentChecks = undefined;

machineTraceability.onOptionSelected(async () => {
    const properties = await machineTraceability.getProperties();
    const totalCavities = machineToCavity[properties.value];

    if (totalCavities === currentChecks) {
        // Already have the correct number of checks, return
        return;
    }

    if (currentChecks === undefined) {
        // First run, make the first set of tests visible
        await subInspection.group('group-1').updateProperties({
            userDefinedVisible: true
        });
        await subInspection.spc('spc-test-1').updateProperties({
            testSpecificTrace: [{
                traceabilityId: await cavityPromise,
                value: 1
            }]
        });
        await subInspection.passFail('passfail-test-1').updateProperties({
            testSpecificTrace: [{
                traceabilityId: await cavityPromise,
                value: 1
            }]
        });
        currentChecks = 1;
    }

    if (totalCavities > currentChecks) {
        // Need to add additional checks
        for (let i = currentChecks + 1; i <= totalCavities; i++) {
            const groupId = `group-${i}`;
            console.log('adding ' + groupId)
            await subInspection.addGroupTest({
                copyFrom: 'group-1',
                scriptId: groupId,
            });
            const properties = await subInspection.group(groupId).getProperties();
            for (let i = 0; i < properties.tests.length; i++) {
                const test = properties.tests[i];
                if (test.type === 'spc') {
                    await subInspection.spc(test.scriptId).updateProperties({
                        testSpecificTrace: [{
                            traceabilityId: await cavityPromise,
                            value: 1
                        }]
                    });
                } else if (test.type === 'passFail') {
                    await subInspection.passFail(test.scriptId).updateProperties({
                        testSpecificTrace: [{
                            traceabilityId: await cavityPromise,
                            value: 1
                        }]
                    });
                }
            }
        }
    } else {
        // Need to remove checks
        for (let i = currentChecks; i > totalCavities; i--) {
            await subInspection.removeTest(`group-${i}`);
        }
    }

    currentChecks = totalCavities;
});