이번 시간에는
GeoTools 및 GeoTools의 Extension 중 하나인 Brewer를 이용하여 Graduated Color Renderer를 생성하는 샘플 코드를 작성해 보도록 하겠습니다.
▣ 학습 내용
- Shapefile DataStore 및 Shapefile 불러오기
- Function 및 ColorBrewer 사용하기
- Style 생성 및 SLD XML로 내보내기
- MapContext 사용하여 지도 보기
▣ Reference
◎
GeoTools Brewer Extension
- http://docs.geotools.org/latest/userguide/extension/brewer/index.html#
◎
Colorbrewer: Color Advice for Maps : http://colorbrewer2.org/
- Colorbrewer에서 사용되는 Palette Name들입니다.
- Diverging: PuOr, BrBG, PRGn, PiYG, RdBu, RdGy, RdYlBu, Spectral, RdYlGn
- Qualitative: Set1, Pastel1, Set2, Pastel2, Dark2, Set3, Paired, Accents,
- Sequential: YlGn, YlGnBu, GnBu, BuGn, PuBuGn, PuBu, BuPu, RdPu, PuRd, OrRd, YlOrRd, YlOrBr, Purples, Blues, Greens, Oranges, Reds, Grays,
◎ Ranged ClassificationFunction
- GeoTools에 지원하는 ClassificationFunction은 다음과 같습니다.
- JenksNaturalBreaksFunction(Jenks), EqualIntervalFunction(EqualInterval), StandardDeviationFunction(StandardDeviation), QuantileFunction(Quantile )
◎ ArcObjects
- ArcObjects에서는 IClassifyGEN과 IClassBreaksRenderer를 이용하여 주제도를 작성할 수 있습니다.
-
IClassBreaksRenderer,
IClassifyGEN
▣ Sample Dataset
-
[Shapefile] Sample Datasets for Spatial Statistics Analysis
▣ Preview
◎ Map
◎ SLD to XML
-
StyledLayerDescriptor
▣ Sample Code
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.TransformerException;
import org.geotools.brewer.color.BrewerPalette;
import org.geotools.brewer.color.ColorBrewer;
import org.geotools.brewer.color.StyleGenerator;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.function.RangedClassifier;
import org.geotools.map.DefaultMapContext;
import org.geotools.map.MapContext;
import org.geotools.styling.FeatureTypeConstraint;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.SLDTransformer;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleFactory;
import org.geotools.styling.StyledLayerDescriptor;
import org.geotools.styling.UserLayer;
import org.geotools.swing.JMapFrame;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Function;
public class ColorBrewerMap {
static FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
static StyleFactory sf = CommonFactoryFinder.getStyleFactory(null);
static final Logger LOGGER = Logging.getLogger(ColorBrewerMap.class);
public static void main(String[] args) throws IOException {
String sourceFolder = "C:/TEMP/spatialstatistics";
DataStore srcDataStore = getShapefileDataStore(sourceFolder);
SimpleFeatureSource srcSfs = srcDataStore.getFeatureSource("seoul_hexagon_1000");
// get featurecollection
SimpleFeatureCollection srcFc = srcSfs.getFeatures(Filter.INCLUDE);
String propertyName = "EVE_CNT";
String functionName = "EqualInterval";
int numClass = 5;
String paletteName = "YlGn";
// prepare classifier
Function function = ff.function(functionName, ff.property(propertyName), ff.literal(numClass));
RangedClassifier classifier = (RangedClassifier) function.evaluate(srcFc);
// prepare ColorBrewer
ColorBrewer colorBrewer = ColorBrewer.instance();
BrewerPalette brewerPalette = colorBrewer.getPalette(paletteName);
Color[] colors = brewerPalette.getColors(classifier.getSize());
// create style
SimpleFeatureType featureType = srcFc.getSchema();
Stroke outline = sf.createStroke(ff.literal(Color.GRAY), ff.literal(1.0f), ff.literal(1.0f));
FeatureTypeStyle fts = StyleGenerator.createFeatureTypeStyle(classifier,
ff.property(propertyName), colors, featureType.getTypeName(),
featureType.getGeometryDescriptor(), StyleGenerator.ELSEMODE_IGNORE,
1.0, outline);
Style style = sf.createStyle();
style.featureTypeStyles().add(fts);
// export sld as XML
printStyleToSLD(style);
// show map
MapContext mapContext = new DefaultMapContext();
mapContext.setTitle(featureType.getTypeName() + "-" + function.getName());
mapContext.addLayer(srcFc, style);
JMapFrame mapFrame = new JMapFrame(mapContext);
mapFrame.setSize(800, 600);
mapFrame.enableStatusBar(true);
mapFrame.enableToolBar(true);
mapFrame.setVisible(true);
}
static void printStyleToSLD(Style style) {
UserLayer layer = sf.createUserLayer();
layer.setLayerFeatureConstraints(new FeatureTypeConstraint[] { null });
layer.setName(style.getName());
layer.addUserStyle(style);
StyledLayerDescriptor sld = sf.createStyledLayerDescriptor();
sld.addStyledLayer(layer);
SLDTransformer styleTransform = new SLDTransformer();
try {
styleTransform.setIndentation(4);
styleTransform.setEncoding(Charset.forName("UTF-8"));
String xml = styleTransform.transform(sld);
System.out.println(xml);
} catch (TransformerException e) {
LOGGER.log(Level.FINER, e.getMessage(), e);
}
}
static DataStore getShapefileDataStore(String folder) throws IOException {
Map<String, Serializable> params = new HashMap<String, Serializable>();
try {
File file = new File(folder);
params.put("url", file.toURI().toURL());
params.put("create spatial index", Boolean.FALSE);
params.put("charset", "CP949"); // or EUC-KR
return DataStoreFinder.getDataStore(params);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
}
▣ 심화학습
◎ Normalization Field 사용
만약 ArcGIS에서처럼 Normalization field를 사용하려면 어떻게 해야 할까요?
Function function = ff.function(functionName, ff.property(propertyName), ff.literal(numClass));
에서 아래와 같이 Normalization field와 Divide를 함께 사용하면 됩니다.
String normalProeprtyName = "GEOM_AREA";
Divide divide = ff.divide(ff.property(propertyName), ff.property(normalProeprtyName));
Function function = ff.function(functionName, divide, ff.literal(numClass));
◎ StyleGenerator.createFeatureTypeStyle () 을 직접 구현해 보기