question

Jeremy R avatar image
1 Like"
Jeremy R asked Phil BoBo edited

​Cleaning up orphaned Statistics objects

I have noticed that in my Model's tree, the Statistics folder is polluted with unused Statistics objects.
These appear to correspond to every graph we have ever created in the model, including graphs that have been deleted and graphs that were on dashboards which have been deleted.

Looking through the Statistics objects themselves, there doesn't appear to be any way to distinguish which Statistics objects are used and which are not from the objects' properties. The only way I can see to determine this is by manually going through every dashboard and identifying which Statistics objects are actually used on it.

Is there some way to remove all unused Statistics objects from the model?

It's mostly an issue because I'm trying to eradicate a particular term from my model, and when searching for uses of it I'm getting a bunch of Statistics object using that term, which appear to simply be false positives since they're ostensibly unused. I don't want to rename objects directly from the tree, so I'm mostly just stuck with the names they had when they were deleted.

FlexSim 18.2.3
statisticstree
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

1 Answer

Jordan Johnson avatar image
2 Likes"
Jordan Johnson answered Phil BoBo edited

You can close all your dashboards, then run this script:

treenode statisticsFolder = Model.find("Tools/Statistics");
Array usedStatsObjects;
var dashboards = Model.find("Tools/Dashboards").subnodes;
for (int d = 1; d <= dashboards.length; d++) {
	var widgets = dashboards[d].subnodes;
	for (int w = 1; w <= widgets.length; w++) {
		Object widget = widgets[w];
		treenode saver = widget.attrs.find("saver");
		treenode storedNode = widget.attrs.find("stored");
		if (saver && saver.value == "DashboardWebStatGraph" && storedNode) {
			var storedLinks = storedNode.subnodes;
			for (int s = 1; s <= storedLinks.length; s++) {
				treenode linkedNode = storedLinks[s].find("+/~");
				if (linkedNode && linkedNode.up == statisticsFolder) {
					usedStatsObjects.push(linkedNode);
				}
			}
		}
	}
}
var statsObjects = statisticsFolder.subnodes;
for (int i = 1; i <= statsObjects.length; i++) {
	treenode statsObject = statsObjects[i];
	if (usedStatsObjects.indexOf(statsObject) <= 0) {
		print(statsObject);
		// statsObject.destroy();
	}
}

The script looks for any Statistics Object that isn't linked to a dashboard chart. Note that the script currently just prints those charts to the Output Console. You will need to change it to actually destroy the orphaned charts.

· 4
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Jeremy R avatar image Jeremy R commented ·

@jordan.johnson I'm not sure why, but almost none of the WebStatGraph subnodes of my Dashboards have the "stored" subnode. Instead, the path to the corresponding Statistics object seems to be stored in "viewfocus".

Replacing the If block in the For loop in your code with the following made it work for me.

treenode viewfocusNode = widget.attrs.find("viewfocus");
if (saver && saver.value == "DashboardWebStatGraph" && viewfocusNode) {
	treenode linkedNode = viewfocusNode.value;
	if (linkedNode && linkedNode.up == statisticsFolder) {
		usedStatsObjects.push(linkedNode);
	}
}
0 Likes 0 ·
Jeremy R avatar image Jeremy R commented ·

Also, in my tree, I appear to have quite a few duplicated nodes in the Statistics folder (i.e. it contains two Statistics objects with the exact same name). Because they both have the same name, they both seem to be recognised as being used on a Dashboard, even though only one of them is.

I suspect these duplicated nodes emerged as a result of our model being version controlled using Git.

0 Likes 0 ·
Jeremy R avatar image Jeremy R Jeremy R commented ·

Running the script multiple times seemed to fix this issue. It seems like nodes that appeared in the Statistics folder multiple times only had a single instance removed when running the script, but running it several times (until no more nodes were deleted from the folder) worked perfectly.

0 Likes 0 ·
Phil BoBo avatar image Phil BoBo ♦♦ Jeremy R commented ·

Jordan script that destroys objects seems to have a logical error.

This will only destroy half of the objects, because as you delete the first object, the second takes its place as the first object and the loop moves on to the second object (which was the third before you deleted the first).

var objs = statisticsFolder.subnodes;
for (int i = 1; i <= objs.length; i++) {
	treenode obj = objs[i];
	obj.destroy();
}

When deleting objects with a for() loop, you should start at the end instead of the beginning:

for (int i = objs.length; i >= 0; i--)

Perhaps that might explain some issues you are having and why you needed to run the script multiple times.

3 Likes 3 ·