【问题标题】:Create data visualizations using Express and get data from a PostgreSQL database使用 Express 创建数据可视化并从 PostgreSQL 数据库获取数据
【发布时间】:2018-09-22 08:32:43
【问题描述】:

我构建了一个 Node.js 应用程序,它从 Internet 上抓取一些信息并将这些信息保存在 postgreSQL 数据库中。 现在我想使用 D3.js 创建一些可视化。 通常我使用.csv 文件创建可视化,但现在我想从我的数据库中获取数据。

我想使用Express.js。 这是我的代码,它可以工作,但它从 .csv 文件中获取数据,而不是从 db 中获取数据。

app.js

const express = require('express');
var app = express();

const start = async function() {
    console.log('\n(1) Connect to db');
    await postgreSQLlib.connect();

    console.log('\n(02) Create tables if they do not exist');
    await postgreSQLlib.createTables();

    console.log('\n(03) Check if table \'example\' is updated or not');
    if(!await utilFunc.isTableUpdated('example', 6308)) {
        console.log('\n  (04) Download data for coverages');
        await downloader.download();

        console.log('\n  (05) Elaborate data for example before to save on DB');
        await elaborate.elaborate();

        console.log('\n  (06) Saving data on db');
        await saveOnDb.save();
    }   

    console.log('\n(10) D3js visualizations');
    app.set('port', process.env.PORT || 300)
    var server = app.listen(app.get('port'), function() {
        console.log('Listening on PORT: ' + app.get('port'));
    });
    app.use('/',express.static('public/donut')) 

    // I can't disconnect from db if I have to show visualizations, am I right?
    console.log('\n(11) Disconnect');
    await postgreSQLlib.disconnect();
}

start()
.then(function(res) {
    console.log('Done');
})
.catch(function(err) {
    console.log(err);
});

index.html

<!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="utf-8">
       <title>Donut</title>
       <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
       <link rel="stylesheet" type="text/css" href="./donut.css" media="screen"/>
    </head>
    <body>
       <script src="./donut.js"></script>
    </body>
</html>

donut.js

var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(radius - 70);

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.population; });

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

d3.csv("./data.csv", type, function(error, data) {
  if (error) throw error;

  var g = svg.selectAll(".arc")
      .data(pie(data))
    .enter().append("g")
      .attr("class", "arc");

  g.append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color(d.data.age); });

  g.append("text")
      .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
      .attr("dy", ".35em")
      .text(function(d) { return d.data.age; });
});

function type(d) {
  d.population = +d.population;
  return d;
}

data.csv

age,population
<5,2704659
5-13,4499890
14-17,2159981
18-24,3853788
25-44,14106543
45-64,8819342
≥65,612463

我也试试:

const start = async function() {
    //...

    function onRequest(req, res) {
        if(req.method == 'GET' && req.url == '/') {
            var client = new pg.Client(conString);
            client.connect();
            var query = client.query('SELECT * FROM example;');
            query.on('row', function(row, result) {
                result.addRow(row);
            });
            query.on('end', function(result) {
                res.status(200)
                res.json(result.rows);
                client.end();
            });
        }
    }
}

和:

d3.csv("/", type, function(error, data) {
  if(error) { 
    throw error;
  }
  console.log('data:', data);
  ...
}

但它不起作用。

我不会使用 .csv 文件来存储我的数据,但我想使用 db。 我该怎么做?

【问题讨论】:

  • 您可能想问一些更具体的问题How to ask
  • 你不知道出了什么问题。我看到一个奇怪的 CSV 文件。我设法使用 CSV 获得了甜甜圈(清理后)。
  • @ClemensTolboom 我用this example 做甜甜圈。这只是可视化的一个例子。在我的工作中,我将使用其他图表。
  • 如果您有兴趣使用我的回答中的方法,我将 json 解析减少到一行代码。

标签: node.js postgresql express d3.js


【解决方案1】:

我的解决方案要求您安装两个额外的模块:

npm install -save express-handlebars & npm install -save pg-promise

app.js 之后,您可以连接到您的postgresql 服务器并通过handlebar 助手解析数据,这是所有代码。

app.js

const express = require('express');
const exphbs  = require('express-handlebars');
const pgp     = require('pg-promise')(/*options*/);

var app = express();

dbLoad();

function dbLoad() {

  var connect = {
    host: 'localhost',
    port: 5432,
    database: 'postgres',
    user: 'postgres',
    password: 'YourPassword'
  };

  var db = pgp(connect); 

  db.query({
    text: 'SELECT * FROM table1',
    values: [],
    rowMode: 'array'
  })
  .then(data => {
    var arr = [];
    data.forEach(function(d) {
      var i = 0
      arr.push({
        age: d[i], 
        population: d[i + 1]
      })
      i++
    })

    pageLoad(arr); // Function call to load the page

  })
  .catch(reason => {
    console.log(reason)
  });

}

function pageLoad(data) {

  var hbs = exphbs.create({
    helpers: {
      sqlData: function () { return JSON.stringify(data); }
    }
  });

  app.engine('handlebars', hbs.engine);
  app.set('view engine', 'handlebars');

  app.get('/', function (req, res, next) {
    res.render('home', {

      showTitle: true,
    });
  });

  app.listen(3000);

}

这假设您在名为 table1 的服务器上拥有与您的 csv 完全相同的数据结构的数据。

然后您应该在与您的app.js 相同的文件夹中创建一个名为views 的文件夹,并创建一个名为home.handlebars 的文件(这是您的index.html 的替换)

在这个文件中,您需要像 {{sqlData}} 这样调用您的数据并对其进行解析。

home.handlebars

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="//d3js.org/d3.v3.min.js"></script>
<title></title>
</head>
<body>

<div id="chart"></div>

</body>

<script>

var init = JSON.parse("{{sqlData}}".replace(/&quot;/g,'"').replace(/&lt;/,''))

chart(init);

function chart(data) {

  var width = 960,
      height = 500,
      radius = Math.min(width, height) / 2;

  var color = d3.scale.ordinal()
      .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

  var arc = d3.svg.arc()
      .outerRadius(radius - 10)
      .innerRadius(radius - 70);

  var pie = d3.layout.pie()
      .sort(null)
      .value(function(d) { return d.population; });

  var svg = d3.select("#chart").append("svg")
      .attr("width", width)
      .attr("height", height)
    .append("g")
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    var g = svg.selectAll(".arc")
        .data(pie(data))
      .enter().append("g")
        .attr("class", "arc");

    g.append("path")
        .attr("d", arc)
        .style("fill", function(d) { return color(d.data.age); });

    g.append("text")
        .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
        .attr("dy", ".35em")
        .text(function(d) { return d.data.age; });

}

</script>
</html>

应该就是这样。

注意我不是 node.js 方面的专家,如果您担心这样做,这样做可能存在一些严重的安全漏洞,我建议您通过 @ 987654321@ 并通过正确的方法直接从 app.js 获取 json 对象,而无需我在此解决方案中所做的所有 hacky 字符串替换。

编辑:

将字符串替换减少到一行代码:

var init = JSON.parse("{{sqlData}}".replace(/&quot;/g,'"').replace(/&lt;/,''))

【讨论】:

  • 如果我想从脚本文件中拆分home.handlebars文件?我创建了一个保存在视图文件夹中的donut.js 文件。所以我的home.handlebars 文件包含&lt;!DOCTYPE html&gt;&lt;html lang='en'&gt;...&lt;body&gt;&lt;/body&gt;&lt;script src='/donut.js'&gt;&lt;/script&gt;&lt;/html&gt;。当我转到localhost:3000 时,我得到Upload failed for &lt;script&gt; with source "http://localhost:3000/donut.js"
  • @marielle 发布一个新问题,你会从对 nodejs 更有经验的人那里得到更好的帮助
【解决方案2】:

将您的 d3 代码包装到一个函数中,每当您通过 express.js 调用 donut(json) 获取数据 as json 时都会调用该函数

donut.js

function donut(json) {
  ...
  var g = svg.selectAll(".arc")
      .data(pie(json))
    .enter().append("g")
      .attr("class", "arc");

...
}

或使用d3.json从服务器获取json并传入URL,如

...
d3.json(data_url, type, function(error, data) {
  if (error) throw error;

  var g = svg.selectAll(".arc")
    .data(pie(data))
    .enter().append("g")
    .attr("class", "arc");
...

【讨论】:

  • 谢谢。 donut() 函数中的 jsond3.json() 中的 data_url 是什么?我确定要解决我的问题,有一个非常简单的解决方案,但我不明白..
  • 您将 json 保存到数据库中,这样您就可以使用 express 代码通过数据库调用来获取它,或者当您的数据库支持通过 json url 获取它时。顺便说一句,我添加了指向我的答案的链接
  • 我现在觉得有点傻。在我的数据库中,我有一个表而不是 json。我确定我可以以 json 格式“下载”数据,但这是您的意思吗?我如何构建 url?我很困惑
  • 我假设您的意思是您将 csv 保存到数据库中。如果是这样,您可以使用github.com/d3/d3-dsv/blob/master/README.md#csvParse 将其转换为数据结构。如果它是一个数据库,我相信你可以找到一个 Express.js 来获取可用于 d3js 的格式的数据,对吧?
  • 感谢您的回复。数据保存在数据库表中。我当然可以进行查询以获取数据并将其保存在数据结构(例如 json)中。我不能做的是组织代码。考虑到在我的项目中,我使用了多个使用不同数据的图表。我在哪里放置与可视化相关的代码?我如何组织一切?我想看一个我想做的具体例子。但我什么也没找到
猜你喜欢
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
  • 1970-01-01
  • 2018-08-13
  • 2016-12-28
  • 2011-08-09
  • 2017-11-08
相关资源
最近更新 更多