AMAPstudio

User Tools


How to add a graph easily

This documentation is for the Capsis modellers. It explains how to implement easily a new graph in Java for their own model.

Extension reminder

Once a new Graph created from one of the examples below, compile it with 'ant compile', then when built successfully, declare it in capsis with 'capsis -se' (i.e. 'search extensions'). To configure a graph, right click on it > configure.

When everything is ok, add all files to svn, then commit.

A distribution graph

Create a subclass of capsis.extension.dataextractor.DEDistribution in an “extension.dataextractor” package, then explicit the following:

  • NAME: the key for the name of the tool (translation, see below))
  • DESCRIPTION: the key for its description
  • AUTHOR: your name
  • VERSION: some String, e.g. “1.0”
  • static matchWith () method: return true only if the tool is compatible with the given referent object. The referent will be the model object connected to the project (e.g. QGModel).
  • implement the abstract methods: give the name of the x Label ; calculate and return the value of the variable which distribution you are interested in.

This is a simple example:

package quergus.extension.dataextractor;
 
import jeeb.lib.util.Translator;
import quergus.model.QGModel;
import quergus.model.QGTree;
import capsis.extension.dataextractor.DEDistribution;
 
/**
 * Trees energy distribution.
 *
 * @author F. de Coligny - April 2012
 */
public class DEEnergyDistribution extends DEDistribution {
 
    static {
        Translator.addBundle("quergus.extension.dataextractor.DEEnergyDistribution");
    }
 
    public static final String NAME = "DEEnergyDistribution";
    public static final String DESCRIPTION = "DEEnergyDistribution.description";
    public static final String AUTHOR = "F. de Coligny";
    public static final String VERSION = "1.0";
 
	public static boolean matchWith (Object referent) {
		return referent instanceof QGModel;
	}
 
	@Override
	protected String getXLabel() {
		return Translator.swap("DEEnergyDistribution.energy");
	}
 
	@Override
	protected Number getValue(Object o) {
		return ((QGTree) o).getTreeLight().getEnergy();
	}
 
}

You must also provide translations for the following keys in a couple of files for english and french.

# quergus/extension/dataextractor/DEEnergyDistribution_en.properties

DEEnergyDistribution = N / Energy classes
DEEnergyDistribution.description = Distribution per energy classes
DEEnergyDistribution.energy = Energy (MJ)
# quergus/extension/dataextractor/DEEnergyDistribution_fr.properties

DEEnergyDistribution = N / Classes d'énergie
DEEnergyDistribution.description = Distribution par classes d'énergie
DEEnergyDistribution.energy = Energie (MJ)

A graph with a single data series over time

Create a subclass of capsis.extension.dataextractor.DETimeY in an “extension.dataextractor” package, then explicit the following:

  • NAME: the key for the name of the tool (translation, see below))
  • DESCRIPTION: the key for its description
  • AUTHOR: your name
  • VERSION: some String, e.g. “1.0”
  • static matchWith () method: return true only if the tool is compatible with the given referent object. The referent will be the model object connected to the project (e.g. MountModel).
  • implement the abstract method: calculate and return the value for the given GScene at the given date.

This is a simple example:

package lsfmgm.extension.dataextractor;
 
import lsfmgm.model.LSFMModel;
import lsfmgm.model.LSFMStand;
import capsis.extension.dataextractor.DETimeY;
import capsis.kernel.GModel;
import capsis.kernel.GScene;
 
/**
 * Species Diversity versus Date.
 *
 * @author Chris Shen of CAF, 21th, Nov, 2009
 */
public class DETimeSpeciesDiversity extends DETimeY {
 
    static {
        Translator.addBundle("lsfmgm.extension.dataextractor.DETimeSpeciesDiversity");
    }
 
    public static final String NAME = "DETimeSpeciesDiversity";
    public static final String DESCRIPTION = "DETimeSpeciesDiversity.description";
    public static final String AUTHOR = "Xiangdong Lei, Ma Wu, Chris Shen";
    public static final String VERSION = "1.1";
 
 
    static public boolean matchWith(Object referent) {
        if (!(referent instanceof LSFMModel)) {return false;}
        return true;
    }
 
    @Override
    protected Number getValue(GModel m, GScene stand, int date) {
        return ((LSFMStand) stand).getSpeciesDiversity(); // returns an int or a double
    }
 
}

You must also provide translations for the following keys in a couple of files for english and french.

# lsfmgm/extension/dataextractor/DETimeSpeciesDiversity_en.properties

DETimeSpeciesDiversity = SpeciesDiversity / Time
DETimeSpeciesDiversity.yLabel = SpeciesDiversity
DETimeSpeciesDiversity.description = SpeciesDiversity over time
# lsfmgm/extension/dataextractor/DETimeSpeciesDiversity_fr.properties

DETimeSpeciesDiversity = Diversité des espèces / Temps
DETimeSpeciesDiversity.yLabel = Diversité
DETimeSpeciesDiversity.description = Diversité des espèces en fonction du temps

A graph with several data series over time

Create a subclass of capsis.extension.dataextractor.DETimeYs (with an 's') in an “extension.dataextractor” package, then explicit the following:

  • NAME: the key for the name of the tool (translation, see below))
  • DESCRIPTION: the key for its description
  • AUTHOR: your name
  • VERSION: some String, e.g. “1.0”
  • static matchWith () method: return true only if the tool is compatible with the given referent object. The referent will be the model object connected to the project (e.g. WoudyModel).
  • implement the abstract method called getYAxisVariableNames() to return the names of the various variables you plan to calculate
  • implement the abstract method called getValue(…) to calculate and return the values matching the 'i'th parameter (same order than the getYAxisVariableNames() method upper) for the given GScene at the given date.

This is a simple example:

package woudyfor.extension.dataextractor;
 
import java.util.Iterator;
import java.util.List;
 
import jeeb.lib.util.Translator;
import woudyfor.model.WoudyModel;
import woudyfor.model.WoudyScene;
(...)
import capsis.extension.dataextractor.DETimeYs;
import capsis.kernel.GModel;
import capsis.kernel.GScene;
 
/**
 * A graph Number of seedlings over time
 * 
 * @author Florian Delerue - March 2012
 */
 
public class WoudyTimeSeedlingN extends DETimeYs {
 
    static {
        Translator.addBundle("woudyfor.extension.dataextractor.WoudyGraphs");
    }
 
    public static final String NAME = "WoudyTimeSeedlingN";
    public static final String DESCRIPTION = "WoudyTimeSeedlingN.description";
    public static final String AUTHOR = "Florian Delerue";
    public static final String VERSION = "1.0";
 
 
    static public boolean matchWith(Object referent) {
        // compatible with WoudyModel only
        return referent instanceof WoudyModel; 
    }
 
    @Override
    public String[] getYAxisVariableNames() {
        return new String[] {"mean", "max"}; // the names of the 2 variables
    }
 
    @Override
    protected Number getValue(GModel m, GScene scene, int date, int i) { // value for the 'i'th variable
        WoudyScene ws = (WoudyScene) scene;
 
        if (i <= 0) {
            return getMean (ws);
        } else {
            return getMax (ws);
        }
 
    }
 
    private double getMax (WoudyScene scene) {
        // calculate and return 'max' on the given scene
        (...)
        return max;
    }
 
    private double getMean (WoudyScene scene) { 
        // calculate and return 'mean' on the given scene
        (...)
        return mean;
    }
 
}

You must also provide translations for the following keys in a couple of files for english and french.

# woudyfor/extension/dataextractor/WoudyGraphs_en.properties

WoudyTimeSeedlingN = Number of seedlings / Time
WoudyTimeSeedlingN.description = Number of seedlings over time for non empty cells
WoudyTimeSeedlingN.yLabel = N/m2
# woudyfor/extension/dataextractor/WoudyGraphs_fr.properties

WoudyTimeSeedlingN = Nombre de plantules / Temps
WoudyTimeSeedlingN.description = Nombre de plantules en fonction du temps pour les cellules occupées
WoudyTimeSeedlingN.yLabel = N/m2

Alignment of labels in the right part of the curves

To align the labels on the curves, see the configuration panel:

Set different colors for the curves (optional)

To set different colors for the curves, you may redefine the getColors () method and return a vector of colors with n = getCurves ().size () - 1 entries. The default graph color (the color on the matching step button in the project manager) can be guessed with getColor (). The example below returns the default color for the mean curve and the red color for the max curve.

	/**
	 * Returns a color per curve: getCurves ().size () - 1.
	 */
	public Vector getColors () {
		// fc-28.11.2013 changed DFCurves into DFColoredCurves, provided this default implementation
		// for getcolors () (no change). Subclasses can redefine this method to return a different
		// color for each curve
		Vector v = new Vector ();
		Color singleColor = getColor (); // see AbstractDataExtractor
		v.add (singleColor); // mean
		v.add (Color.RED); // max
		return v;
	}

Optionally disable some data series

It is possible to add options in the graphs by redefining the setConfigProperties () method. These options may be used to optionally remove some data series by adapting the code below.

All possible configuration possibilities are explained in this doc.

Note: for better result, you may provide translations in english and french for 'mean' and 'max' in the labels files.

    @Override
    public void setConfigProperties() {
        addBooleanProperty("mean", true);
        addBooleanProperty("max", true);
    }
 
    @Override
    protected Number getValue(GModel m, GScene scene, int date, int i) {
        WoudyScene ws = (WoudyScene) scene;
 
        if (i <= 0) {
            return isSet ("mean") ? getMean (ws) : Double.NaN;
        } else {
            return isSet ("max") ? getMax (ws) : Double.NaN;
        }
 
    }

A graph with several data series over time, for one or several trees

This is a simple example:

package heterofor.extension.dataextractor;
 
import heterofor.model.HetModel;
import heterofor.model.HetScene;
import heterofor.model.HetTree;
import jeeb.lib.util.Translator;
import capsis.extension.dataextractor.DETimeYsTrees;
import capsis.kernel.GModel;
import capsis.kernel.GScene;
 
/**
 * A graph 'biomass for 5 compartments' over time for a given list of trees.
 * 
 * @author F. de Coligny, M. Jonard - November 2013
 */
 
public class DETimeBiomass extends DETimeYsTrees {
 
	static {
		Translator.addBundle ("heterofor.extension.dataextractor.DELabels");
	}
 
	public static final String NAME = "DETimeBiomass";
	public static final String DESCRIPTION = "DETimeBiomass.description";
	public static final String AUTHOR = "F. de Coligny, M. Jonard";
	public static final String VERSION = "1.0";
 
	static public boolean matchWith (Object referent) {
		// compatible with HetModel only
		return referent instanceof HetModel;
	}
 
	@Override
	public String[] getYAxisVariableNames () {
		// the names of the variables
		return new String[] {Translator.swap ("leafBiomass"), Translator.swap ("branchBiomass"),
				Translator.swap ("stemBiomass"), Translator.swap ("rootBiomass"), Translator.swap ("fineRootBiomass")}; 
	}
 
	/**
	 * Returns the value for the 'i'th variable of the tree 'treeId'.
	 */
	@Override
	protected Number getValue (GModel m, GScene scene, int treeId, int date, int i) {
		HetScene sc = (HetScene) scene;
 
		HetTree t = (HetTree) sc.getTree (treeId);
 
		if (i <= 0) {
			return t.getLeafBiomass ();
		} else if (i == 1) {
			return t.getBranchBiomass ();
		} else if (i == 2) {
			return t.getStemBiomass ();
		} else if (i == 3) {
			return t.getRootBiomass ();
		} else if (i == 4) {
			return t.getFineRootBiomass ();
		} else {
			return 0;
		}
 
	}
 
}
documentation/howtoaddagrapheasily.txt · Last modified: 2015/06/24 15:24 by coligny