java的地理图表

时间:2014-10-30 17:18:16

标签: java graph maps geo

任何人都可以推荐一个Java组件,它可以让您创建漂亮的世界地图图像,突出显示某些国家/地区(基于某些统计信息)。与此图像类似的东西:

World map with highlighted countries

类似于谷歌地理图表(但对于Java):https://developers.google.com/chart/interactive/docs/gallery/geochart 但是在服务器端运行,没有互联网连接。理想情况下,我希望将权重加到一些国家,这些国家会按比例突出显示它们。

无论是开源还是商业(只要它不是价格荒谬的东西)。

6 个答案:

答案 0 :(得分:4)

我无法找到一个java库来做你想要的东西,所以我研究了一个SVG并修改它的风格,并将其转换为图像。我首先想到了这个任务:Apache Batik。

我选择使用wikimedia上提供的开源svg地图(类似于Gregor Opheys的回答),因为它没有成功,所以你不关心许可,它也已经是现成的按国家/地区进行简单的CSS修改(有关说明,请参阅SVG注释)。有一个故障,维基媒体上的一些图像是由a python script生成的,它将CSS样式也放在元素中。如果您想使用其中一个SVG文件,则必须为此处理。

令我高兴的是,有almost a perfect example on the batik wiki,只需要几个调整。我能够通过一个小的语法更改(它们的outfile文件名为.jpg但使用png转码器)生成一个修改后的图像(png),并通过一个小的更改从项目资源而不是磁盘加载svg。下面是我的小改动的示例代码:

public class MapMaker {

    private final static String MAP_FLAT = "BlankMap-World6-Equirectangular.svg";
    private final static String MAP_ROUND = "WorldMap.svg";

    public static void main(String... args) {

        try {
            // make a Document with the base map 
            String parser = XMLResourceDescriptor.getXMLParserClassName();
            SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
            Document doc = f.createDocument("http://example.com/stuff",
                    MapMaker.class.getClassLoader().getResourceAsStream(MAP_ROUND));

            // prepare to modify and transcode the document
            SVGDocument sdoc = (SVGDocument) doc;
            Element svgRoot = sdoc.getDocumentElement();
            PNGTranscoder t = new PNGTranscoder();
            TranscoderInput input = new TranscoderInput(doc);

            // find the existing stylesheet in the document
            NodeList stylesList = doc.getElementsByTagName("style");
            Node styleNode = stylesList.item(0);

            // append another stylesheet after the existing one
            SVGStyleElement style = (SVGStyleElement) doc.createElementNS(SVG_NAMESPACE_URI, "style");
            style.setAttributeNS(null, "type", "text/css");
            style.appendChild(doc.createCDATASection(".us {fill: blue;}"));
            styleNode.getParentNode().appendChild(style);

            // transcode the map
            OutputStream ostream = new FileOutputStream("outblue.jpg");
            TranscoderOutput output = new TranscoderOutput(ostream);
            t.transcode(input, output);
            ostream.close();

            // replace the appended stylesheet with another
            SVGStyleElement oldStyle = style;
            style = (SVGStyleElement) doc.createElementNS(SVG_NAMESPACE_URI, "style");
            style.setAttributeNS(null, "type", "text/css");
            style.appendChild(doc.createCDATASection(".us {fill: green;}"));
            styleNode.getParentNode().replaceChild(style, oldStyle);

            // transcode the revised map
            File outFile = new File(System.getProperty("java.io.tmpdir"), "outgreen.png");
            ostream = new FileOutputStream(outFile);
            output = new TranscoderOutput(ostream);
            t.transcode(input, output);
            ostream.close();
            System.out.println("Out File: " + outFile);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

正如我所提到的,它的工作方式是在将SVG转换为您需要的光栅图像之前将其添加到SVG。秘密酱是SVGStyleElement,在这里你可以看到美国变绿了。对于任何其他国家/地区,您只需使用他们的双字母有向图并选择您想要填充的颜色。当然,既然它是CSS,你也可以做一些事情,比如改变边框颜色或使用背景图片而不是颜色,这样你就有了很大的灵活性。

我确实必须使用依赖项,所以为了让你超越这个障碍,我将包含我的maven依赖项:

<dependencies>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-parser</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-css</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-svg-dom</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-transcoder</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-rasterizer</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-codec</artifactId>
        <version>1.7</version>
    </dependency>
</dependencies>

如果你使用不同的构建管理器,请告诉我,我可以转储传递依赖树。

答案 1 :(得分:2)

看看GeoTools,它可能有你需要的东西。

答案 2 :(得分:2)

没有使用它并且不确定它是否适合您的需求,但您可以查看 Nasa WorldWind 。它具有SDK,似乎可以使用离线模式。

检查:

答案 3 :(得分:1)

好吧,你可以为此制作一个GWT应用程序。 GWT(Google Web ToolKit)是一个基于Java的应用程序制作平台。它提供了与您在Google Charts javascript API中看到的相同类型的可视化API,但是在java代码中。请查看基于Java的Chart API的此链接以及Java代码http://gwt-charts.appspot.com/#geochart中的地理图表的实例。希望这会有所帮助:)

答案 4 :(得分:1)

首先,您可以轻松地使用SVG世界地图滚动组件或更像自己的功能 (例如this)。 将java.util.Map国家/地区名称保留为SVG源中给出的路径元素。 您的函数将采用一组国家/地区名称,并基本上将字符串的svg作为字符串返回。如果路径的id与集合中的id匹配,您将添加具有所需颜色的填充属性...

这是代码。您需要下载this并将其作为world.svg放在同一文件夹中。然后传入您想要突出显示为参数的国家/地区。程序将编写一个文件out.svg,您可以在浏览器中打开(我使用的是Firefox)。我希望它成功。我只是尝试从日食中运行它......

package com.examples.firstbundle;


import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

public class SVGMap {
    private static String prefix = "";
    private static String postfix = "";
    private static Map<String, String> worldMap = new TreeMap<String, String>();

    private final static String pathFormat = "<path id=\"{0}\" d=\"{1}\" fill=\"{2}\" />"; 
    static {

        try {
            List<String> lines = Files.readAllLines(FileSystems.getDefault().getPath("world.svg"), StandardCharsets.UTF_8);

            boolean pathstarted = false;
            for(String line : lines) {
                if(isPath(line)) {
                    pathstarted = true;
                    worldMap.put(getCountry(line), getPath(line));
                } else {
                    if(!pathstarted) {
                        prefix += line;
                    }
                    else {
                        postfix += line;
                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        Set<String> countries = new TreeSet<String>();
        for(String country : args) {
            countries.add(country);
        }
        FileOutputStream fileOutputStream = new FileOutputStream("out.svg");
        OutputStreamWriter out = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);

        out.append(prefix);
        for(String country : worldMap.keySet()) {
            out.append(MessageFormat.format(pathFormat, country, worldMap.get(country), countries.contains(country) ? "tomato" : "grey"));
        }
        out.append(postfix);
        out.flush();
        out.close();
    }

    private static String getPath(String line) {
        String part = line.split("=")[2];
        String path = part.split("\"")[1];
        return path;
    }

    private static String getCountry(String line) {
        String part = line.split("=")[1];
        String country = part.split("\"")[1];
        return country;
    }

    private static boolean isPath(String line) {
        return line.startsWith("<path");
    }

}

答案 5 :(得分:0)

我觉得你更好:

  

gvSIG以其用户友好的界面而闻名   访问最常见的格式,包括矢量和光栅格式。它   具有广泛的工具,可以与地理一样工作   信息(查询工具,布局创建,地理处理,网络,   等)

来源:gvSIG Wikipedia

相关问题