How to render a graph as image in node

丶灬走出姿态 提交于 2019-12-10 12:58:14

问题


I want to render a stacked bar graph in image format on the server.

The intended use is to push to a service like twitter that doesn't support SVG. As well as the code being being deployable to services like Heroku

I've already tried Plotly (their node package is horribly out of date and their API docs poor). I've also looked at Google Graph, Chart.js and AnyChart but they do not support rendering images far as I can see


回答1:


You can accomplish this with Vega

Vega is a visualization grammar, a declarative format for creating, saving, and sharing interactive visualization designs. With Vega you can describe data visualizations in a JSON format, and generate interactive views using either HTML5 Canvas or SVG.

For example, using the stacked bar chart example spec you can render the chart to PNG file with the following code:

// START vega-demo.js
var vega = require('vega')
var fs = require('fs')

var stackedBarChartSpec = require('./stacked-bar-chart.spec.json');

// create a new view instance for a given Vega JSON spec
var view = new vega
  .View(vega.parse(stackedBarChartSpec))
  .renderer('none')
  .initialize();

// generate static PNG file from chart
view
  .toCanvas()
  .then(function (canvas) {
    // process node-canvas instance for example, generate a PNG stream to write var
    // stream = canvas.createPNGStream();
    console.log('Writing PNG to file...')
    fs.writeFile('stackedBarChart.png', canvas.toBuffer())
  })
  .catch(function (err) {
    console.log("Error writing PNG to file:")
    console.error(err)
  });
// END vega-demo.js

// START stacked-bar-chart.spec.json 
{
  "$schema": "https://vega.github.io/schema/vega/v3.0.json",
  "width": 500,
  "height": 200,
  "padding": 5,

  "data": [
    {
      "name": "table",
      "values": [
        {"x": 0, "y": 28, "c":0}, {"x": 0, "y": 55, "c":1},
        {"x": 1, "y": 43, "c":0}, {"x": 1, "y": 91, "c":1},
        {"x": 2, "y": 81, "c":0}, {"x": 2, "y": 53, "c":1},
        {"x": 3, "y": 19, "c":0}, {"x": 3, "y": 87, "c":1},
        {"x": 4, "y": 52, "c":0}, {"x": 4, "y": 48, "c":1},
        {"x": 5, "y": 24, "c":0}, {"x": 5, "y": 49, "c":1},
        {"x": 6, "y": 87, "c":0}, {"x": 6, "y": 66, "c":1},
        {"x": 7, "y": 17, "c":0}, {"x": 7, "y": 27, "c":1},
        {"x": 8, "y": 68, "c":0}, {"x": 8, "y": 16, "c":1},
        {"x": 9, "y": 49, "c":0}, {"x": 9, "y": 15, "c":1}
      ],
      "transform": [
        {
          "type": "stack",
          "groupby": ["x"],
          "sort": {"field": "c"},
          "field": "y"
        }
      ]
    }
  ],

  "scales": [
    {
      "name": "x",
      "type": "band",
      "range": "width",
      "domain": {"data": "table", "field": "x"}
    },
    {
      "name": "y",
      "type": "linear",
      "range": "height",
      "nice": true, "zero": true,
      "domain": {"data": "table", "field": "y1"}
    },
    {
      "name": "color",
      "type": "ordinal",
      "range": "category",
      "domain": {"data": "table", "field": "c"}
    }
  ],

  "axes": [
    {"orient": "bottom", "scale": "x", "zindex": 1},
    {"orient": "left", "scale": "y", "zindex": 1}
  ],

  "marks": [
    {
      "type": "rect",
      "from": {"data": "table"},
      "encode": {
        "enter": {
          "x": {"scale": "x", "field": "x"},
          "width": {"scale": "x", "band": 1, "offset": -1},
          "y": {"scale": "y", "field": "y0"},
          "y2": {"scale": "y", "field": "y1"},
          "fill": {"scale": "color", "field": "c"}
        },
        "update": {
          "fillOpacity": {"value": 1}
        },
        "hover": {
          "fillOpacity": {"value": 0.5}
        }
      }
    }
  ]
}
// END stacked-bar-chart.spec.json

Will output PNG file:




回答2:


I capture charts, visualizations and reports under Node.js using the Nightmare headless browser.

Using Nightmare allows you to use any of the wide variety of browser-based visualization frameworks under Node.js, including C3 and D3 which are both awesome.

I've actually created a npm module called c3-chart-maker that wraps up Nightmare and allows you to render a chart under Node.js by feeding it some data and a C3 chart definition.

Install it like this:

npm install --save c3-chart-maker

Use it like this:

const c3ChartMaker = require('c3-chart-maker');

const yourData = ... your data ...
const chartDefinition = { ... c3 chart definition ... }
const outputFilePath = "your-chart-output-file.png";

c3ChartMaker(yourData, chartDefinition, outputFilePath)
    .then(() => { 
        console.log('Done');
    })
    .catch(err => {
        console.error(err);
    });

Please check out the C3 example gallery for examples of charts and to see what a C3 chart definition looks like.

You can also use Nightmare manually to be able to capture any web page or browser-based visualization.

To install Nightmare:

npm install --save nightmare

Here's an example that can capture a web page:

const Nightmare = require('nightmare');

// This is the web page to capture.
// It can also be a local web server! 
// Or serve from the file system using file://
const urlToCapture = "http://my-visualization.com"; 
const outputFilePath = "your-chart-output-file.png";

const nightmare = new Nightmare(); // Create Nightmare instance.
nightmare.goto(urlToCapture) // Point the browser at the requested web page.
        .wait("svg") // Wait until the specified HTML element appears on the screen. 
        .screenshot(outputImagePath) // Capture a screenshot to an image file.
        .end() // End the Nightmare session. Any queued operations are completed and the headless browser is terminated.
        .then(() => {
            console.log("Done!");
        })
        .catch(err => {
            console.error(err);
        });

I've written more extensively about this on my blog.

I've also dedicated a whole chapter to this in my book Data Wrangling with JavaScript.



来源:https://stackoverflow.com/questions/44543729/how-to-render-a-graph-as-image-in-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!