See How to add a graph easily to create a graph. This documentation deals about the configuration of graphs, with configuration properties.
To analyse a simulation under Capsis, it is possible to open graphs. The graphs compatible with the current simulation are available in the lateral Selector of Capsis' main frame. Double clicking on the name of a graph opens it, synchronised on the current simulation step.
The Capsis graphs accept several data series from different simulation steps. To add a data series from another step, click on the step (becomes 'current'), then right click on the graph > Add <name of the current step> (or Ctrl+click on the graph for a shortcut).
These graphs are often configurable. To open the configuration dialog, right click on the graph > Configure (or double click on the graph for a shortcut).
The first tab in the configuration dialog is for common configuration. This means the changes in this panel will be applied to all the data series in the graph. E.g. if 'Per hectare' is chosen, all the data series will be recalculated per hectare.
On the individual tab, the user may configure the data series separately. On this example, 2 data series coming from the same simulation step have been added (Ctrl+Click on the graph). These 2 data series can be configured separately.
Note: the third tab is proposed to configure the renderer (showing the data).
See below for an explanation of the various available configuration properties.
The Capsis graphs are internally based on data extractors, they explore the simulation steps to build data series to be rendered in the user interface.
A data extractor has a name, e.g. 'Basal area / Time', it produces one or several data series relative to a referent simulation step (can be all steps from the root step to this referent step to check the evolution). One or several data extractors are grouped and displayed in a single graph (a data renderer). The data renderers can be switched to have the data series shown in an histogram, in a table, etc.
New data extractors can be created in Capsis by following the related docs. In a data extractor, the configuration properties must be declared in the setConfigProperties ()
method.
/** * This method is called by superclass DataExtractor. */ public void setConfigProperties() { // Choose configuration properties addConfigProperty(PaleoDataExtractor.TREE_GROUP); addConfigProperty(PaleoDataExtractor.I_TREE_GROUP); addConfigProperty(PaleoDataExtractor.STATUS); addDoubleProperty("classWidthInM", 5d); addDoubleProperty("minThresholdInM", 0d); addBooleanProperty("perHectare"); addBooleanProperty("displayClassNames", false); addBooleanProperty("roundN"); addBooleanProperty("centerClasses"); }
A boolean property can be added with addBooleanProperties (propertyName, defaultValue);
propertyName
is a String, e.g. “perHectare”
defaultValue
is the value the property will have at first opening, e.g. true
Note: a translation is expected in french/english in a pair of translation files (ending with _fr
and _en.properties
). Here, we consider perHectare
is translated into Per hectare
in the english file. These translations are used when preparing the widgets on the user interface.
The user can change the value by clicking on the check box. If other opened graphs or other data series in the same graphs have the same option, the user can propagate his choice to them by clicking on the propagation button on the right before validating the dialog (here, all the data series in all opened graphs would immediately go per hectare).
The value of the property can be checked with isSet(propertyName)
. It is checked in the methods responsible of the data series creation (or update if the configuration changed). The standard method for this in the data extractors is called doExtraction ()
, generally containing a loop to gather the data and store them in lists. Some other data extractors rely on a method called getValue(…)
(see the doc cited at the top of this page).
E.g. in DEHeightClassN
… N / Height classes
// in setConfigProperties ()... addBooleanProperty("perHectare"); // in doExtraction ()... // per Ha computation double coefHa = 1; if (isSet("perHectare")) coefHa = 10000 / getSceneArea(step.getScene()); // Then multiply all values of the data series by coefHa...
A combo property can be added with addComboProperty (propertyName, listOfStrings);
propertyName
is a StringlistOfStrings
is a list with the candidate options to be listed in the combo box to let the user choose one of them. By convention, the one in first position will be the current selection. If the user changes the selection, the new selected option will be moved in first position in the list.The property name and all options are to be translated in the pair of translation files for french/english.
The user can choose the value for each combo property by using the matching combo box widget.
To get the selected value in the extractor code (doExtraction()
, getValue()
), use getComboProperty(propertyName)
Example code: DEIntertype
… Spatial : Intertype L12(r ) function
// in setConfigProperties ()... LinkedList c = new LinkedList(grouperNames); addComboProperty("Type 1", c); LinkedList c2 = new LinkedList(grouperNames); addComboProperty("Type 2", c2); // in doExtraction ()... Grouper g1 = gm.getGrouper(getComboProperty("Type 1"));
A radio property can be added in a graph with addRadioProperty (String[] candidateOptions);
candidateOptions
is an array of Strings containing all the exclusive options to be proposed to the user in radio buttons. The user will select one option among them.All the option names are to be translated in the pair of translation files for french/english.
To get the user choice in the extractor source code, use the same method than for a boolean property : isSet(optionName)
, it will return true for the selected option and false for the others.
E.g. in the GymnoTimeWoodType
… Basal area / Time / Wood Type
class:
// in setConfigProperties ()... addRadioProperty(new String[] { "normal", "hectare", "percent" }); (...) // lower, in doExtraction ()... total = (juvenileSum + matureSum + sapSum) * coef; if (isSet("percent")) coef = 1d / total; (...)
An int property can be added in a graph with addIntProperty(propertyName, defaultValue);
propertyName
is a StringdefaultValue
is an integer, it will be proposed to the user at first configuration time (then the value chosen by the user will be kept in the etc/extension.setting file and reproposed at next configuration time)The property name is to be translated in a pair of french/english files.
To get the value chosen by the user in the source code of the graph, use the method getIntProperty(propertyName)
E.g. in DETimeClassN
… N / Age classes
// in setConfigProperties ()... addIntProperty("DEAgeClassN.classWidthInYears", 5); // in doExtraction... int classWidth = getIntProperty("DEAgeClassN.classWidthInYears");
A double property is added in a graph with addDoubleProperty(propertyName, defaultValue);
propertyName
is a StringdefaultValue
is a decimal number (type double)The property name is to be translated in a pair of french/english files.
To get the value chosen by the user, use the method getDoubleValue (propertyName)
E.g. in DEDbhClassN
… N / Diameter classes
// in setConfigProperties ()... addDoubleProperty("classWidthInCm", 5d); // in doExtraction ()... double classWidth = getDoubleProperty("classWidthInCm");
A string property can be added in a graph with addStringProperty(propertyName, defaultValue);
propertyName
is a String defaultValue
is also a stringThe property name is to be translated in a pair of french/english files.
To get the String chosen by the user, use the method getStringProperty(propertyName);
E.g. in ModisVolumeTable
… Volume and income
// in setConfigProperties () (the string here is an encoded suite of numbers)... addStringProperty("limits", "45 (35) 15 (20) 12 (14) 8 (7) 5"); // optional: in additionalChecks (): get the string, check the format // is correct, else tell the user with MessageDialog and return false... /** * Called by multi configuration panel on Ok, just after checksAreOk () (dealing * with general checks), here we can see it the user limits are in an expected form. */ @Override public boolean additionalChecks() { // Checking encoded limits String encodedLimits = getStringProperty("limits"); try { // The method below throws an exception if trouble ModisVolumeAndIncomeInterpretor.decodeLimitsProperty(encodedLimits); } catch (Exception e) { MessageDialog.print(this, e.getMessage()); return false; } return true; } // in doExtraction (), get the property and use it to build the data series... String encodedLimits = getStringProperty("limits"); (...) makeTable("Living trees", stand.getTrees(), mp, encodedLimits);
A set property can be added in a graph with addSetProperty(propertyName, possibleValues, selectedValues);
propertyName
is a StringpossibleValues
is a String[]: the set of available options for this propertyselectedValues
is a String[]: the set of selected options (a subset of the possibleValues)Note: we use 'set' instead of 'list' because the sets in Java do not contain duplicates and this is what is expected here, i.e. the possible values can not contain the same option twice.
The property name and all option names are to be translated in a pair of french/english files.
To get the set of selected options chosen by the user, use getSetProperty(propertyName);
E.g. in DEAlleleFrequencies2
… Genetics: Allele frequency / Locus (2018)
// in setConfigProperties ()... // Which loci do we want to see (here, all the possible values are selected) addSetProperty("DEAlleleFrequencies2.locusNames", possibleValues, possibleValues); // optional, if the property possible values must be updated, e.g. because // user chose to restrict to a group... /** * Called when a group is set or changed. */ public void grouperChanged(String grouperName) { // cp - 30.11.2004 (...) // Changing groups: there may be two species in the scene, update // the locusNames String[] locusNames = findLocusNames(gee); updateSetProperty("DEAlleleFrequencies2.locusNames", locusNames); (...) } // in doExtraction ()... // Get the user chosen loci List loci = getSetProperty("DEAlleleFrequencies2.locusNames");
The grouping system of Capsis can be activated in the graphs to restrict them to some individuals belonging to a given group.
If activated at the common level, all the data series in the graph will be restricted to the given group. If tuned at the individual level, data series based on different groups will become comparable in the same graph.
A group property can be added with addGroupProperty (type, target);
type
is an instance of GroupableType (tells about the targeted individuals, e.g. alive trees)target
is either ConfigurableExtractor.COMMON or INDIVIDUALNote: it is possible to activate the group feature at both common and individual levels. If user selects both, he will be told that one only can be chosen at at time.
The user can activate the feature, choose the group and optionaly choose to use the complementary. He also can create a new group on the fly to be added to the current list of available groups (then saved and restored).
To apply the group in doExtraction ()
, use doFilter (inputList)
, this will return all the inputList if no group has been set by the user, else the individuals in inputList which are part of the group.
E.g. DETimeG
… Basal area / Time
// in setConfigProperties ()... // group multiconfiguration (common) // note: addGroupProperty(TreeList.GROUP_ALIVE_TREE, COMMON) should be preferred addConfigProperty(PaleoDataExtractor.TREE_GROUP); // group individual configuration // note: addGroupProperty(TreeList.GROUP_ALIVE_TREE, INDIVIDUAL) should be preferred addConfigProperty(PaleoDataExtractor.I_TREE_GROUP); // in doExtraction ()... (...) Collection trees = doFilter(stand); value = ((GProvider) methodProvider).getG(stand, trees) * coefHa; (...)
It is possible to add a specific (i.e. customized) configuration property.
In EcoAF (agroforestry), the scene contains several parcels. The parcels are laid out with tree lines (several species) by the user during the initialisation stage. Afterwards, it is possible to open graphs to check the resulting scene, e.g. the diameter distributions. These diameter distibutions can be configured with a configuration property specific to EcoAF.
E.g. to show a specific parcel, it is possible in the Individual tab to open the EcoAF configuration property to restrict the graph to a given parcel.
A specific property can be added in a graph with:
addSpecificProperty(propertyName, specificProperty)
addSpecificProperty(propertyName, extractor, specificProperty)
Where
propertyName
is a StringspecificProperty
is an instance of DESpecificProperty (a subclass)extractor
is the extractor to be configured (subclass of ConfigurableExtractor) in the case of an individual propertyAll the labels to be shown on the user interface are to be translated in a pair of french/english files.
To get the result of the user configuration, use
These two methods return the DESpecificProperty
object sent at the time of addSpecificProperty ()
call, the internal configuration can be used in doExtraction ()
or getValue ()
to tune the data series extraction (in this example, keep only data for Parcel 2).
In this example, the filter is a pair of classes: EcoafFilter
(the filter extending DESpecificProperty) and its configuration dialog for user interaction, EcoafFilterDialog
.
E.g. EcoafDbhClassN
… N / Dbh classes (Ecoaf)
// in setConfigProperties ()... @Override public void setConfigProperties() { EcoafScene scene = (EcoafScene) step.getScene(); String[] graphType = { "EcoafDbhClassN.perSpecies", "EcoafDbhClassN.perPosition" }; addRadioProperty(graphType); addDoubleProperty("EcoafDbhClassN.minThreshold", 0); addDoubleProperty("EcoafDbhClassN.classWidth", 10); // addSpecificProperty("Shared.ecoafFilter", new EcoafFilter()); // common configuration // We use the individual configuration level, if several distributions in the graph, // it will be possible to configure them separately, e.g. on different parcels addSpecificProperty("Shared.ecoafFilter", this, new EcoafFilter()); // individual configuration } // in doExtraction ()... (...) EcoafFilter ecoafFilter = (EcoafFilter) getSpecificProperty("Shared.ecoafFilter", this); // The extractor may have been synchronized on another simulation step, the // filters must be updated ecoafFilter.update(scene); List<EcoafTree> trees = ecoafFilter.getSelectedTrees(scene); (...)
If the connected model manages individuals, it is possible to activate the TREE_IDS configuration property.
To activate it, use addConfigProperty(PaleoDataExtractor.TREE_IDS);
To get the selected individual ids (generally tree ids), use getTreeIds()
E.g. in DETimeH
… Height / Time
This configuration property is compatible only with the TreeList
class. This class is a superclass for many Capsis modules managing trees as individuals in their scene object. TreeList proposes a feature to keep individual which are removed from the alive tree list: they can be put in a list under a chosen status. Standard status are “dead” and “cut”. Other status may be used in some modules to keep track of disappearing trees, they are generally managed in the model processEvolutionLoop ().
If status can be found, a list of the possible values are proposed to the user who can choose one or several to be considered and trees with other status will be ignored in the graph.
The status config property can be activated with addConfigProperty(PaleoDataExtractor.STATUS);
To get the result, use the same method than for the groups: doFilter (inputList)
It may be needed to sometimes disable a property added in setConfigProperties ()
, it can be done with setPropertyEnabled (propertyName, booleanValue)
at the end of setConfigProperties ()
or in init ()
.
E.g. DETimeDbh
… Diameter / Time
is a standard extractor compatible with many models dealing with a list of trees having a dbh. Some of them have additional features and other data can sometimes be plotted in the graph along with the dbh evolution over time.
To see what features can be added, the methodProvider of the module is asked: 'can you return Dg ?', 'can you return Ddom ?'…
The non available properties will be set disabled after their declaration and the matching checkBoxes will be shown desactivated.
// in setConfigProperties ()... public void setConfigProperties() { checkMethodProvider(step.getProject().getModel().getMethodProvider()); // Choose configuration properties addConfigProperty(PaleoDataExtractor.TREE_IDS); addBooleanProperty("showDg"); addBooleanProperty("showDdom"); addBooleanProperty("showDamapsim"); addBooleanProperty("showDgamapsim"); addBooleanProperty("showDm"); addBooleanProperty("showDmedian"); addBooleanProperty("showDbhStandardDeviation"); addBooleanProperty("showDmin"); addBooleanProperty("showDmax"); addBooleanProperty("incrementInsteadOfValue"); // TL - december 2017 addBooleanProperty("incrementPerYear"); // PhD 2009-04-16 // According to module capabiblities, disable some configProperties setPropertyEnabled("showDg", availableDg); setPropertyEnabled("showDdom", availableDdom); setPropertyEnabled("showDamapsim", availableDamapsim); setPropertyEnabled("showDgamapsim", availableDgamapsim); setPropertyEnabled("showDm", availableDm); setPropertyEnabled("showDmedian", availableDmedian); setPropertyEnabled("showDbhStandardDeviation", availableDbhStandardDeviation); setPropertyEnabled("showDmin", availableDmin); setPropertyEnabled("showDmax", availableDmax); setPropertyEnabled("incrementInsteadOfValue", true); // TL-december 2017 setPropertyEnabled("incrementPerYear", true); // PhD 2009-04-16 }
Sometimes, the user entry does not need to be checked because an error is not possible, e.g. clicking on a checkBox, choosing an option in a comboBox. But sometimes, the user is expected to enter a certain type of answer (e.g. in a textField) and a check is needed to tell him if a correction is needed.
Two levels of checks are provided and called when user validates the config panel:
The checksAreOk ()
method is specific to each type of config property, it is responsible for checking types. For example, if a textField is expected to contain an integer, the check will be done in this method. This method is proposed in AbstractConfigurationProperty
, it is abstract and must be redefined in all subclasses.
When no type check is needed, it returns true directly (e.g. BooleanPropertyManager
/ checkBox).
When needed, it runs the check and if the check fails, it tells the user with MessageDialog
and returns false. The user will have to change its entry to comply to the expected type or format.
E.g. in IntPropertyManager
, the checksAreOk () method below checks all the intProperties textFields found in the extractor (if any was added in setConfigProperties ()
). These are only common properties. In case of trouble, a message is sent to the user and false is returned.
@Override public boolean checksAreOk() { // Check intProperties type (must be int) Iterator keys = intPropertiesTextFields.keySet().iterator(); Iterator values = intPropertiesTextFields.values().iterator(); while (keys.hasNext() && values.hasNext()) { String propertyName = (String) keys.next(); JTextField f = (JTextField) values.next(); if (extractor.isIndividualProperty(propertyName)) continue; String value = f.getText(); try { new Integer(value); } catch (Exception e) { // Trouble, tell user and return false MessageDialog.print(this, Translator.swap(propertyName) + " " + Translator.swap("DataExtractor.mustBeAnInteger")); return false; } } return true; }
The second level of checks () can be run in the additionalChecks ()
of the ConfigurableDataExtractor. This method is called after all the checkAreOk () methods were called and at this time it is possible to use all the methods to get the user choices like getIntProperty (propertyName)
, etc.
Here, it is possible to check if the various config properties are compatible together. E.g. if the user has asked for a min
and a max
value, a check than min if strictly lower than max should be run and the user told if this is not the case.
A default implementation of additionalChecks () is provided in ConfigurableExtractor, as these checks are less frequent, it returns true. It is possible to override if needed.
By default, the configuration properties are presented to the user in the configuration panel grouped type by type: group properties, boolean properties, etc.
An option makes it possible to keep the order they are declared in setConfigProperties ()
. After having declared the properties, just add setPropertyDeclarationOrderKept()
Please note some properties will not be concerned by this option, e.g. the group features if activated will always displayed at the top of the panel.