[Schmitzm-commits] r815 - in trunk/src/schmitzm: jfree/feature/style xml
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Fri Apr 23 15:27:05 CEST 2010
Author: mojays
Date: 2010-04-23 15:27:03 +0200 (Fri, 23 Apr 2010)
New Revision: 815
Modified:
trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java
trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java
trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java
trunk/src/schmitzm/xml/XMLUtil.java
Log:
FeatureChartStyle extended with "series attribute", which is used to group the features to series.
Series attribute integrated in XML-ChartStyle.
Modified: trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java 2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java 2010-04-23 13:27:03 UTC (rev 815)
@@ -29,6 +29,7 @@
******************************************************************************/
package schmitzm.jfree.feature.style;
+import java.util.HashSet;
import java.util.Set;
import org.geotools.feature.FeatureCollection;
@@ -416,6 +417,88 @@
}
/**
+ * Defines the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ * @param attrName feature attribute name
+ */
+ @Override
+ public void setSeriesAttributeName(String attrName) {
+ dummyFeatureChartStyle.setSeriesAttributeName(attrName);
+ }
+
+ /**
+ * Returns the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ */
+ @Override
+ public String getSeriesAttributeName() {
+ return dummyFeatureChartStyle.getSeriesAttributeName();
+ }
+
+ /**
+ * Sets the values, which are interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValues the "No Data" values
+ */
+ @Override
+ public void setSeriesAttributeNoDataValues(Set<Object> noDataValues) {
+ dummyFeatureChartStyle.setSeriesAttributeNoDataValues(noDataValues);
+ }
+
+ /**
+ * Returns the values, which are interpreted as "No Data" for the
+ * series attribute.
+ */
+ @Override
+ public Set<Object> getSeriesAttributeNoDataValues() {
+ return dummyFeatureChartStyle.getSeriesAttributeNoDataValues();
+ }
+
+ /**
+ * Sets a value, which is interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValue the "No Data" value
+ */
+ @Override
+ public void addSeriesAttributeNoDataValue(Object noDataValue) {
+ dummyFeatureChartStyle.addSeriesAttributeNoDataValue(noDataValue);
+ }
+
+ /**
+ * Removes a "No Data" value for the series attribute.
+ * @param noDataValue the "No Data" value to remove
+ * @return {@code false} if the value was not an "No Data" value
+ */
+ @Override
+ public boolean removeSeriesAttributeNoDataValue(Object noDataValue) {
+ return dummyFeatureChartStyle.removeSeriesAttributeNoDataValue(noDataValue);
+ }
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute.
+ * @param value an attribute value
+ */
+ @Override
+ public boolean isSeriesAttributeNoDataValue(Object value) {
+ return dummyFeatureChartStyle.isSeriesAttributeNoDataValue(value);
+ }
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute. In this case this method returns {@code null}, otherwise the
+ * value itself.
+ * @param value an attribute value
+ * @return {@code null} if the given value is one of the "No data" values
+ */
+ @Override
+ public <T> T filterSeriesAttributeNoDataValue(T value) {
+ return dummyFeatureChartStyle.filterSeriesAttributeNoDataValue(value);
+ }
+
+ /**
* Creates an appropriate {@link Dataset} for the attributes defined
* by this style (according to the attributes types in the given
* {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.
Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java 2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java 2010-04-23 13:27:03 UTC (rev 815)
@@ -277,7 +277,6 @@
*/
public boolean isWeightAttributeNoDataValue(int idx, Object value);
-
/**
* Checks whether the given value is one of the "No data" values for the
* attribute. In this case this method returns {@code null}, otherwise the
@@ -289,6 +288,65 @@
public <T> T filterWeightAttributeNoDataValue(int idx, T value);
/**
+ * Defines the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ * @param attrName feature attribute name
+ */
+ public void setSeriesAttributeName(String attrName);
+
+ /**
+ * Returns the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ */
+ public String getSeriesAttributeName();
+
+ /**
+ * Sets the values, which are interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValues the "No Data" values
+ */
+ public void setSeriesAttributeNoDataValues(Set<Object> noDataValues);
+
+ /**
+ * Returns the values, which are interpreted as "No Data" for the
+ * series attribute.
+ */
+ public Set<Object> getSeriesAttributeNoDataValues();
+
+ /**
+ * Sets a value, which is interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValue the "No Data" value
+ */
+ public void addSeriesAttributeNoDataValue(Object noDataValue);
+
+ /**
+ * Removes a "No Data" value for the series attribute.
+ * @param noDataValue the "No Data" value to remove
+ * @return {@code false} if the value was not an "No Data" value
+ */
+ public boolean removeSeriesAttributeNoDataValue(Object noDataValue);
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute.
+ * @param value an attribute value
+ */
+ public boolean isSeriesAttributeNoDataValue(Object value);
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute. In this case this method returns {@code null}, otherwise the
+ * value itself.
+ * @param value an attribute value
+ * @return {@code null} if the given value is one of the "No data" values
+ */
+ public <T> T filterSeriesAttributeNoDataValue(T value);
+
+
+ /**
* Creates a chart according to the given
* @param fc a feature collection
* @exception UnsupportedOperationException if the style can not be applied to
@@ -364,7 +422,18 @@
/** Holds the "No Data" values for each weight attribute. */
protected Map<Integer, Set<Object>> weightAttrNoDataValues = new HashMap<Integer, Set<Object>>();
+
/**
+ * Holds the attribute name of the series attribute, whose values are
+ * used to define groups. For each group a series is created in the
+ * dataset.
+ */
+ protected String seriesAttrName = null;
+
+ /** Holds the "No Data" values for the series attribute. */
+ protected Set<Object> seriesAttrNoDataValues = new HashSet<Object>();
+
+ /**
* Creates a new dummy. This constructor is protected so that only derived
* classes can instantiate a dummy! There is no limit for the number of
* attributes which can be defined by the style.
@@ -845,6 +914,101 @@
}
/**
+ * Defines the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ * @param attrName feature attribute name
+ */
+ @Override
+ public void setSeriesAttributeName(String attrName) {
+ this.seriesAttrName = attrName;
+ }
+
+ /**
+ * Returns the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ */
+ @Override
+ public String getSeriesAttributeName() {
+ return seriesAttrName;
+ }
+
+ /**
+ * Sets the values, which are interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValues the "No Data" values
+ */
+ @Override
+ public void setSeriesAttributeNoDataValues(Set<Object> noDataValues) {
+ seriesAttrNoDataValues = noDataValues;
+ }
+
+ /**
+ * Returns the values, which are interpreted as "No Data" for the
+ * series attribute.
+ */
+ @Override
+ public Set<Object> getSeriesAttributeNoDataValues() {
+ return this.seriesAttrNoDataValues;
+ }
+
+ /**
+ * Sets a value, which is interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValue the "No Data" value
+ */
+ @Override
+ public void addSeriesAttributeNoDataValue(Object noDataValue) {
+ Set<Object> noDataValues = getSeriesAttributeNoDataValues();
+ if (noDataValues == null) {
+ noDataValues = new HashSet<Object>();
+ setSeriesAttributeNoDataValues(noDataValues);
+ }
+ noDataValues.add(noDataValue);
+ }
+
+ /**
+ * Removes a "No Data" value for the series attribute.
+ * @param noDataValue the "No Data" value to remove
+ * @return {@code false} if the value was not an "No Data" value
+ */
+ @Override
+ public boolean removeSeriesAttributeNoDataValue(Object noDataValue) {
+ Set<Object> noDataValues = getSeriesAttributeNoDataValues();
+ if (noDataValues == null)
+ return false;
+ return noDataValues.remove(noDataValue);
+ }
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute.
+ * @param value an attribute value
+ */
+ @Override
+ public boolean isSeriesAttributeNoDataValue(Object value) {
+ Set<Object> noDataValues = getSeriesAttributeNoDataValues();
+ if (noDataValues == null)
+ return false;
+ return noDataValues.contains(value);
+ }
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute. In this case this method returns {@code null}, otherwise the
+ * value itself.
+ * @param value an attribute value
+ * @return {@code null} if the given value is one of the "No data" values
+ */
+ @Override
+ public <T> T filterSeriesAttributeNoDataValue(T value) {
+ if (isSeriesAttributeNoDataValue(value))
+ return null;
+ return value;
+ }
+
+ /**
* Does nothing, but always throws a {@link UnsupportedOperationException},
* because the dummy can not provide this functionality.
*/
Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java 2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java 2010-04-23 13:27:03 UTC (rev 815)
@@ -29,7 +29,10 @@
******************************************************************************/
package schmitzm.jfree.feature.style;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
import org.geotools.feature.FeatureCollection;
import org.jdom.Element;
@@ -39,6 +42,7 @@
import schmitzm.jfree.chart.style.ChartStyleXMLFactory;
import schmitzm.jfree.chart.style.ChartType;
import schmitzm.jfree.feature.AggregationFunction;
+import schmitzm.lang.LangUtil;
import schmitzm.xml.XMLUtil;
/**
@@ -85,23 +89,41 @@
chartStyle.setAttributeNormalized(0, XMLUtil.getBooleanAttribute(domainAttrElem, "normalize", false));
chartStyle.setSortDomainAxis(XMLUtil.getBooleanAttribute(domainAttrElem, "sort", false));
chartStyle.setForceCategories(XMLUtil.getBooleanAttribute(domainAttrElem, "forceCategories", false));
+ Set<Object> nullAliases = XMLUtil.getSetAttribute(domainAttrElem, "nullAliases");
+ if (nullAliases != null)
+ chartStyle.setNoDataValues(0, nullAliases);
// Read all range attribute definitions
int rangeAttrNo = 0;
- for (Element featureAttrElem : (List<Element>)featureElement.getChildren("rangeAttr") ) {
- String featureAttrName = XMLUtil.getAttribute(featureAttrElem, "name");
+ for (Element rangeAttrElem : (List<Element>)featureElement.getChildren("rangeAttr") ) {
+ String featureAttrName = XMLUtil.getAttribute(rangeAttrElem, "name");
if ( featureAttrName == null )
throw new UnsupportedOperationException("Attribute 'name' necessary for <rangeAttr> element of FeatureChartStyle!");
// Apply attributes to style
rangeAttrNo++;
chartStyle.setAttributeName(rangeAttrNo, featureAttrName);
- chartStyle.setAttributeNormalized(rangeAttrNo, XMLUtil.getBooleanAttribute(domainAttrElem, "normalize", false));
- String aggrFuncStr = XMLUtil.getAttribute(domainAttrElem, "function", (String)null);
+ chartStyle.setAttributeNormalized(rangeAttrNo, XMLUtil.getBooleanAttribute(rangeAttrElem, "normalize", false));
+ String aggrFuncStr = XMLUtil.getAttribute(rangeAttrElem, "function", (String)null);
if ( aggrFuncStr != null )
chartStyle.setAttributeAggregation(rangeAttrNo, AggregationFunction.valueOf(aggrFuncStr) );
+ nullAliases = XMLUtil.getSetAttribute(rangeAttrElem, "nullAliases");
+ if (nullAliases != null)
+ chartStyle.setNoDataValues(rangeAttrNo, nullAliases);
}
- }
+ // Read (optional) series attribute (its values defines the series groups)
+ Element seriesAttrElem = featureElement.getChild("seriesAttr");
+ if ( seriesAttrElem != null ) {
+ String seriesAttrName = XMLUtil.getAttribute(seriesAttrElem, "name");
+ if ( seriesAttrName == null )
+ throw new UnsupportedOperationException("Attribute 'name' necessary for <seriesAttr> element of FeatureChartStyle!");
+ chartStyle.setSeriesAttributeName(seriesAttrName);
+ nullAliases = XMLUtil.getSetAttribute(seriesAttrElem, "nullAliases");
+ if (nullAliases != null)
+ chartStyle.setSeriesAttributeNoDataValues(nullAliases);
+ }
+}
+
/**
* Creates a default style for a chart type.
* @param id a (unique) ID for the style
@@ -139,6 +161,7 @@
addChildToElement(attrElem, "domainAttr", false,
"name", style.getAttributeName(0),
"normalize", style.isAttributeNormalized(0),
+ "nullAliases", XMLUtil.convertSetToSeparatedString(style.getSeriesAttributeNoDataValues()),
"sort", style.isSortDomainAxis(),
"forceCategories", style.isForceCategories()
);
@@ -148,9 +171,17 @@
addChildToElement(attrElem, "rangeAttr", false,
"name", style.getAttributeName(i),
"normalize", style.isAttributeNormalized(i),
+ "nullAliases", XMLUtil.convertSetToSeparatedString(style.getNoDataValues(i)),
"function", style.getAttributeAggregation(i)
);
+ // Series attribute definition
+ if ( style.getSeriesAttributeName() != null )
+ addChildToElement(attrElem, "seriesAttr", false,
+ "name", style.getSeriesAttributeName(),
+ "nullAliases", XMLUtil.convertSetToSeparatedString(style.getSeriesAttributeNoDataValues())
+ );
+
return root;
}
}
Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java 2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java 2010-04-23 13:27:03 UTC (rev 815)
@@ -657,7 +657,16 @@
catValue);
if (catValue == null)
continue;
-
+
+ // If grouping series attribute is used, filter out
+ // its no data values
+ Object seriesID = null;
+ if ( chartStyle.getSeriesAttributeName() != null ) {
+ seriesID = determineSeriesAttributeValueFromFeature(f, chartStyle);
+ if ( seriesID == null )
+ continue;
+ }
+
// Determine the Y values and fill the dataset
for (int attrIdx = 1; attrIdx < attrCount; attrIdx++) {
Double yValue = determineRangeValueFromFeature(
@@ -676,6 +685,10 @@
if (chartStyle.getAttributeAggregation(attrIdx) == null) {
// Add data to dataset
String yAttrName = chartStyle.getAttributeName(attrIdx);
+ // If grouping series attribute is used, add its value
+ // to the series ID
+ if ( seriesID != null )
+ yAttrName = yAttrName + "_" + seriesID.toString();
dataset.addValue(yValue, yAttrName, catValue);
// Mapping between FID and data index in series
mapping.setMapping(f.getID(), yAttrName, catValue);
@@ -906,7 +919,25 @@
return yValue.doubleValue();
}
+
/**
+ * Determines the value from the series attribute of a feature and transforms it
+ * according to the (optional) no data values.
+ * @param feature a feature
+ * @param chartStyle the chart style
+ * @return {@code null} if the feature must be ignored because of an invalid
+ * (null) value
+ */
+ private static Object determineSeriesAttributeValueFromFeature(SimpleFeature feature,
+ FeatureChartStyle chartStyle) {
+ String seriesAttrName = chartStyle.getSeriesAttributeName();
+ Object seriesAttrValue = feature.getAttribute(seriesAttrName);
+ // Filter out NoDataValues
+ seriesAttrValue = chartStyle.filterSeriesAttributeNoDataValue(seriesAttrValue);
+ return seriesAttrValue;
+ }
+
+ /**
* Transforms
* @param func
* @param value
Modified: trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java 2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java 2010-04-23 13:27:03 UTC (rev 815)
@@ -429,6 +429,88 @@
}
/**
+ * Defines the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ * @param attrName feature attribute name
+ */
+ @Override
+ public void setSeriesAttributeName(String attrName) {
+ dummyFeatureChartStyle.setSeriesAttributeName(attrName);
+ }
+
+ /**
+ * Returns the attribute whose values are used to define
+ * groups. For each group value a series is created in the chart
+ * dataset.
+ */
+ @Override
+ public String getSeriesAttributeName() {
+ return dummyFeatureChartStyle.getSeriesAttributeName();
+ }
+
+ /**
+ * Sets the values, which are interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValues the "No Data" values
+ */
+ @Override
+ public void setSeriesAttributeNoDataValues(Set<Object> noDataValues) {
+ dummyFeatureChartStyle.setSeriesAttributeNoDataValues(noDataValues);
+ }
+
+ /**
+ * Returns the values, which are interpreted as "No Data" for the
+ * series attribute.
+ */
+ @Override
+ public Set<Object> getSeriesAttributeNoDataValues() {
+ return dummyFeatureChartStyle.getSeriesAttributeNoDataValues();
+ }
+
+ /**
+ * Sets a value, which is interpreted as "No Data" for the
+ * series attribute.
+ * @param noDataValue the "No Data" value
+ */
+ @Override
+ public void addSeriesAttributeNoDataValue(Object noDataValue) {
+ dummyFeatureChartStyle.addSeriesAttributeNoDataValue(noDataValue);
+ }
+
+ /**
+ * Removes a "No Data" value for the series attribute.
+ * @param noDataValue the "No Data" value to remove
+ * @return {@code false} if the value was not an "No Data" value
+ */
+ @Override
+ public boolean removeSeriesAttributeNoDataValue(Object noDataValue) {
+ return dummyFeatureChartStyle.removeSeriesAttributeNoDataValue(noDataValue);
+ }
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute.
+ * @param value an attribute value
+ */
+ @Override
+ public boolean isSeriesAttributeNoDataValue(Object value) {
+ return dummyFeatureChartStyle.isSeriesAttributeNoDataValue(value);
+ }
+
+ /**
+ * Checks whether the given value is one of the "No data" values for the
+ * series attribute. In this case this method returns {@code null}, otherwise the
+ * value itself.
+ * @param value an attribute value
+ * @return {@code null} if the given value is one of the "No data" values
+ */
+ @Override
+ public <T> T filterSeriesAttributeNoDataValue(T value) {
+ return dummyFeatureChartStyle.filterSeriesAttributeNoDataValue(value);
+ }
+
+ /**
* Creates an appropriate {@link Dataset} for the attributes defined
* by this style (according to the attributes types in the given
* {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.
Modified: trunk/src/schmitzm/xml/XMLUtil.java
===================================================================
--- trunk/src/schmitzm/xml/XMLUtil.java 2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/xml/XMLUtil.java 2010-04-23 13:27:03 UTC (rev 815)
@@ -30,6 +30,9 @@
package schmitzm.xml;
import java.awt.Color;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
import org.apache.log4j.Logger;
import org.jdom.Element;
@@ -37,6 +40,7 @@
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
+import schmitzm.lang.LangUtil;
import schmitzm.swing.SwingUtil;
import skrueger.i8n.Translation;
@@ -156,8 +160,52 @@
return defValue[0];
return null;
}
+
+ /**
+ * Gets a string-separated attribute value from element as {@code Set<String>}.
+ * @param element element where the attribute is determined from
+ * @param attrName name of the attribute
+ * @param defValue optional default value returned if attribute is not found (or empty)
+ * @return {@code null} if {@code element} is {@code null} or attribute is not
+ * specified in element
+ */
+ public static Set<Object> getSetAttribute(Element element, String attrName, Set<Object>... defValue) {
+ String value = getAttribute(element, attrName);
+ if ( value != null )
+ return convertSeparatedStringToSet(value);
+ if ( defValue.length > 0 )
+ return defValue[0];
+ return null;
+ }
/**
+ * Parses a semicolon-separated string and stores its elements in
+ * a set.
+ * @param objectString the semicolon-separated string of objects
+ * @return an empty set if the string is empty
+ */
+ public static Set<Object> convertSeparatedStringToSet(String objectString) {
+ Set<Object> objects = new HashSet<Object>();
+ StringTokenizer st = new StringTokenizer(objectString,";\n");
+ for (;st.hasMoreTokens();)
+ objects.add( st.nextToken() );
+ return objects;
+ }
+
+ /**
+ * Creates a semicolon-separated string of the elements of a set.
+ * @param objects the objects which are transformed to string and
+ * concatenated
+ * @return {@code null} if the set is empty or {@code null}
+ */
+ public static String convertSetToSeparatedString(Set<Object> objects) {
+ if ( objects == null || objects.isEmpty() )
+ return null;
+ return LangUtil.stringConcatWithSep(";", objects.toArray());
+ }
+
+
+ /**
* Sets an attribute value. The {@code .toString()} method is used
* to convert the object value to string.<br>
* Exceptions:
More information about the Schmitzm-commits
mailing list