java的地理图表

Posted

技术标签:

【中文标题】java的地理图表【英文标题】:Geo chart for java 【发布时间】:2014-12-26 20:52:39 【问题描述】:

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

类似于 Google 地理图表(但用于 Java)的东西:https://developers.google.com/chart/interactive/docs/gallery/geochart 但在服务器端运行,没有互联网连接。理想情况下,我想对几个按比例突出显示的国家/地区赋予权重。

开源或商业(只要价格不离谱)。

【问题讨论】:

你可以使用 d3js 和 Javas ScriptEngine。 您要查找的输出格式是什么?您是希望它是静态的(即光栅图像)还是需要动态的/​​需要能够编写诸如鼠标悬停等内容的脚本? @SteveSiebert 只是一个静态的,用于包含在将被打印出来的 .pdf 报告中。所以大多数图像格式就足够了 @user 我害怕混合使用 javascript 和 java... 确实有问题 @Atlib 好的,谢谢。让我看看我能想出什么 【参考方案1】:

我找不到一个 java 库来做你正在寻找的东西,所以我研究了一个 SVG 并修改它的样式,并将其转换为图像。我想到这个任务的第一个想法是:Apache Batik。

我选择使用wikimedia 上提供的开源 svg 地图(类似于 Gregor Opheys 的回答),因为它没有做到,所以您不必担心许可问题,它也已经为简单的 CSS 修改做好了准备按国家。 (有关说明,请参阅 SVG cmets)。有一个问题,wikimedia 上的一些图像是由a python script 生成的,这也将 CSS 样式放入元素中。如果您想使用这些 SVG 文件之一,则必须为此处理。

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

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 转换为所需的光栅图像之前将 CSS 添加到 SVG。秘方是SVGStyleElement,在这里你可以看到美国变绿了。对于任何其他国家/地区,您只需使用他们的 2 字母有向图并选择您想要填充的颜色。当然,因为它是 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>

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

【讨论】:

【参考方案2】:

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

【讨论】:

该项目严重缺少网页上的一些屏幕截图/示例【参考方案3】:

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

检查:

http://worldwind.arc.nasa.gov/java/ 和http://goworldwind.org/demos/

http://goworldwind.org/examples/#network(离线模式)

【讨论】:

【参考方案4】:

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

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

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");
    


【讨论】:

最大的问题是手动定义路径/坐标...并使其看起来很漂亮。但这是我倾向于的。我本来希望这项工作已经在某个地方完成了! @AtliB :只需从我链接到的 SVG 中获取路径/坐标。时间允许,我将添加一些代码...... 我没有意识到 .svg 只是一个 xml 文档,在这种情况下定义了所有国家/地区...这很酷【参考方案5】:

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

【讨论】:

相当接近,但它似乎确实依赖于 Google 服务器,因此无法离线运行:developers.google.com/chart/interactive/faq?csw=1#offline【参考方案6】:

我觉得对你更好:

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

来源:gvSIG Wikipedia

【讨论】:

它似乎没有API...似乎是一个桌面应用程序。我需要一个组件,我可以在其中创建图片格式的地图并将其包含在报告中。

以上是关于java的地理图表的主要内容,如果未能解决你的问题,请参考以下文章

Python数据可视化:地理空间图表可视化(基础篇—7)

按国家划分的地理图

Python数据可视化:时间序列图表可视化

Python数据可视化:如何选择合适的图表可视化?

Python数据可视化:如何选择合适的图表可视化?

Echart图表使用