使用D3.js加载本地数据以进行可视化

时间:2012-07-10 10:22:25

标签: javascript json d3.js

我正在开展一个项目,要求我可视化一个相当复杂的数据类型(参见this older question)。简而言之,我有大量数据可以导出为JSON,CSV或其他任意平面格式,尽管如果可能的话我宁愿避免使用XML(请参阅上面链接的问题以获得底层数据的详细说明)。 / p>

我已经开始使用D3进行可视化工作了,到目前为止我编写的布局似乎工作正常我用一些非常简单的数据测试它,我在Javascript中作为数组进行硬编码。我读到D3中关于数据绑定的教程有点令人困惑,因为有些人使用JSON,有些人使用TXT / CSV格式,而有些则使用硬编码数组/矩阵。

在JSON的情况下,我观​​看了一个教程,其中叙述者坚定地建议在Web服务器上托管JSON文件并使用HTTP请求而不是本地文件读取来获取它。我意识到这是由于跨域请求限制,我相信我必须以某种方式解决。此时我不确定如何继续:

  1. D3支持的可视化将出现在一系列HTML报告中,这些报告是作为我编写的分析工具的结果创建的。分析在用户计算机上完成,HTML报告也在客户端本地创建。

  2. 目标用户绝对不懂技术,所以不能指示他们在他们的计算机上运行网络服务器,以便能够通过localhost提供JSON或任何其他类型或资源

  3. 为了记录,我已经尝试运行python SimpleHTTPServer模块来试用它,并且一切正常。然后,我尝试对生成的HTML报告中的数据进行硬编码,然后从我的使用D3的脚本中调用JSON对象,

    //d3.json("mydata.json", function(json){
    d3.json(myjson, function(json){
        nodeData = json.elements;
    ....
    }
    

    失败,因为在这种情况下,我最终发送一个JSON对象,而D3.js期待一个URL。

    我该怎么做才能避免/解决这个问题?

6 个答案:

答案 0 :(得分:2)

要在不使用服务器的情况下加载数据本地文件,请将脚本标记附加到正文,并将源数据分配给您期望的变量或对象元素。在下面的示例中,我从[COUNTRY_ISO3CODE] .js文件加载某个国家/地区的数据。具体而言,阿富汗数据文件可能具有以下格式的内容:

data[AFG] = {"name": "Afghanistan", "estimate": 9.003, ... }

调用文件将具有以下内容:

if (!data[iso3]) { //only load the needed data-script as needed

    // if using jQuery
    $('body').append("<script type='text/javascript' src='jdb/"+ iso3 +".js'></script>")

    //If not using jQuery
    /*var script   = document.createElement("script");
    script.type  = "text/javascript";
    script.src   = "jdb/"+iso3+".js"; //?_="+ (new Date()); URL might have to be randomized to avoid cached data
    document.body.appendChild(script);
    */

    // call the data-handling function only after 
    // the desired data has fully loaded
    // in this case, I check every 100 milliseconds
    var intervalId = setInterval( function () {
        if (data[iso3]) {    //once data is detected, process data
            clearInterval(intervalId); //stop checking for data
            prepData(mainWrapper, iso3)
            drawCharts(mainWrapper, iso3)
        }
    }, 100)
}
else drawCharts(mainWrapper, iso3)

答案 1 :(得分:2)

对于JSON:

var data = JSON.parse(JavascriptStringVariableThatContainsJSON);

对于CSV:

 var data = d3.csv.parseRows(JavascriptStringVariableThatContainsMyCSVdata);

//然后将数据添加到图表并调用enter,如:

 var dataEnter = svg.selectAll("rect").data(data).enter();

答案 2 :(得分:2)

所以你想通过FileReader调用加载本地数据,下面的内容取自Reading local files in JavaScript。但是,基于上面的示例,此代码将图像文件加载到svg而不链接文件,但实际上将栅格数据插入到svg中。并随意用任何其他数据替换栅格数据,只需添加正确的处理...

首先关闭<body>部分中支持的html元素:

<input type="file" id="files" name="files[]" multiple />

然后,您想要将<input ... />元素与<script>部分中的某些代码相关联:

document.getElementById('files').addEventListener('change', handleFileSelect, false);

现在在事件处理代码中读取文件后面的代码(现在在这种情况下我想将本地图像加载到D3JS svg中):

function handleFileSelect(evt) {
    reader = new FileReader();
    reader.onabort = function(e) {alert('File read cancelled');};
    var imageObj = new Image();  //image object to hold the local file contents.

    //and given the asynchronous nature, set up the event so that when the image is loaded, do something with it:
    imageObj.onload = function() {image.datum(imageObj.src).attr("xlink:href", function(d) {return d})};

    //similarly for the file reading:
    reader.onload = function(e) {imageObj.src = reader.result};

    //With all the events set up, lets start reading the file in.
    //the secret sauce is the DataURL
    reader.readAsDataURL(evt.target.files[0]);
}

为了完整性,图像背后的D3JS酱:

var svg = d3.select("body").append("svg");

var image = svg.append("defs")
    .append("pattern")
    .attr("id", "venus")
    .attr('patternUnits', 'userSpaceOnUse')
    .attr("width", 200)
    .attr("height", 200)
    .append("image")
    .attr("width", 200)
    .attr("height", 200);

var image2 = svg.append("rect")
    .attr("x", "0")
    .attr("y", "0")
    .attr("width", 200)
    .attr("height", 200)
    .attr("fill", "url(#venus)");

答案 3 :(得分:1)

如果您每次都在生成HTML,则可以将数据作为JSON放在HTML中,也可以放在可以从HTML引用的.js文件中,可能是通过生成的唯一URL。

答案 4 :(得分:0)

D3有一些很棒的工具可以导入数据并对其进行操作。过去曾经一直为json服务(有时候创建麻烦)我更倾向于服务csv并在javascript / d3中操纵它,但有兴趣看看别人如何回答你的问题。

这是一个简单的例子,在这里显示嵌套json的csv:https://gist.github.com/3053667

还有许多用于处理数据的工具:https://github.com/mbostock/d3/wiki/Arrays

然后有Crossfilter,如果你想切片和骰子。看起来非常值得一试,但我正等着傻瓜指南问世! http://square.github.com/crossfilter/

答案 5 :(得分:0)

d3.json通过ajax调用加载外部json文件 - 示例中的myjson变量已经是一个javascript对象,所以你不需要加载它,只需在你的nodeData中直接使用它分配

nodeData = myjson.elements;