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的地理图表的主要内容,如果未能解决你的问题,请参考以下文章