基于Processing的数据可视化

2023-06-05,,

虽然数据可视化领域有很多成熟、界面友好、功能强大的软件产品(例如Tableau、VIDI、NodeXL等),但是借助Processing我们可以基于Java语言框架进行丰富多元的可视化编程,熟悉了Processing也可以说是上一学期Topics课程的最大收获,以另一种方式将数据重新组织、统计并以可视化界面展现出来。今天再看其他资料时碰巧看到XX对Processing的支持,颇感亲切,所以决定把上学期Topics的作业过程记录下来。

可视化内容是从Databank下载的217个国家、6个地区的7项统计数据。要求从通过数据可视化看出每个指标的变化趋势、所选不同国家之间的对比情况、不同时间段数据变化、不同地区所包含国家的统计数据对比等。

– Electricity production (kWh)
– Electricity production from renewable sources (kWh)
– Electric power consumption (kWh)
– Electric power consumption (kWh per capita)
– CO2 emissions (metric tons per capita)
– CO2 emissions (kt)
– Population, total

数据文件如下:

最终可视化结果如下:

源码如下:

 import processing.core.*;
import processing.data.*;
import processing.event.*;
import processing.opengl.*; import controlP5.*;
import java.lang.Math; import java.util.HashMap;
import java.util.ArrayList;
import java.io.File;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException; public class TCS1 extends PApplet { ControlP5 cp5; FloatTable data, dataRegion;
float dataMin, dataMax;
float volumnMax; float plotX1, plotY1;
float plotX2, plotY2;
float labelX, labelY; int yearMin, yearMax;
int[] years;
int yearInterval = 3; int showRow = 6;
int showRegionRow = 0; int yearStartCol = 8; //Integrator[] interpolators; PFont plotFont;
DropdownList dropCountry, dropCate, dropRegion; boolean isNormalOn = true;
boolean isGroupOn = false;
boolean isCompareOn = false; int groupMode = 1;
static final int GROUP_MODE_REGIONS = 1;
static final int GROUP_MODE_DECADES = 2; IntList listCompare = new IntList();
int[][] compareColors = new int[300][3];
int cateCompare = 0; int[] decadeYearIndex = new int[4];
String[] decadeYearStr = new String[4]; public void setup() {
size(1200, 750); cp5 = new ControlP5(this);
data = new FloatTable("data.tsv");
dataRegion = new FloatTable("region.tsv"); years = PApplet.parseInt(data.getColumnNames()); yearMin = years[yearStartCol];
yearMax = years[years.length - 1]; //init decade year
for (int i=7; i>3; i--) {
decadeYearStr[7-i] = data.getColumnNames()[i];
decadeYearIndex[7-i] = 7-i;
} interpolators = new Integrator[data.getColumnCount()];
for(int col=yearStartCol; col=weishu; i--) {
maxStr += "0";
eachStr += "0";
}
eachStr += "0" + firstNum;
maxStr += firstNum + "";
}
else {
for (int i=-1; i>=weishu+1; i--) {
maxStr += "0";
eachStr += "0";
}
eachStr += "0" + firstNum;
maxStr += firstNum + "";
}
}
else if (weishu == 0) {
if (firstNum != 10) {
maxStr = "0."+firstNum;
eachStr = "0.0" + firstNum;
}
else {
maxStr = firstNum / 10 + "";
eachStr = "0." + firstNum / 10;
}
}
else if (weishu == 1) {
if (firstNum != 10) {
maxStr = firstNum + "";
eachStr = "0." + firstNum;
}
else {
maxStr = firstNum + "";
eachStr = firstNum / 10 + "";
}
}
else {
maxStr += firstNum + "";
eachStr += firstNum + "";
for (int i=1; i= 10) {
if (weishu == 0) {
volumnNumbers[i] = currentFirstNum / 100 + "";
}
else {
volumnNumbers[i] = currentFirstNum / pow(10, 2-weishu) + "";
}
}
else if (PApplet.parseFloat(currentFirstNum) / 10 >= 1) {
volumnNumbers[i] += "0.";
for (int j=-1; j>weishu-1;j--) {
volumnNumbers[i] += "0";
}
volumnNumbers[i] += currentFirstNum;
}
else {
volumnNumbers[i] += "0.";
for (int j=-1; j>weishu-2;j--) {
volumnNumbers[i] += "0";
}
volumnNumbers[i] += currentFirstNum;
}
}
else if (weishu == 1) {
if (PApplet.parseFloat(currentFirstNum) / 10 >= 1) { volumnNumbers[i] = (currentFirstNum / 10) + "." + (currentFirstNum - ((currentFirstNum / 10) * 10));
}
else {
volumnNumbers[i] = "0."+currentFirstNum;
}
}
else {
volumnNumbers[i] = currentFirstNum + "";
for (int j=0; j 0) {
if (v > 100) {
return String.format("%.0f", v);
}
else if (v > 10) {
return String.format("%.2f", v);
}
else if (v > 1) {
return String.format("%.3f", v);
}
else {
return String.format("%.4f", v);
}
}
return "";
} public void drawDataPoints(int row) {
for (int col=yearStartCol; col3; col--) {
if (data.isValid(row, col)) {
float value = data.getFloat(row, col);
System.out.println(value);
float x = map(decadeYearIndex[7-col], -0.7f, 3.7f, plotX1, plotX2);
float y = map(value, 0, volumnMax, plotY2, plotY1); rect(x-(recWidth / 2), y, recWidth, plotY2 - y); text(value, x, y - 20);
}
}
} public void drawDataLine(int row) {
beginShape();
//stroke(23, 23, 23);
for (int col=yearStartCol; col= data.length)) {
throw new RuntimeException("There is no row " + rowIndex);
}
if ((col < 0) || (col >= data[rowIndex].length)) {
throw new RuntimeException("Row " + rowIndex + " does not have a column " + col);
}
// end training wheels return data[rowIndex][col];
} public boolean isValid(int row, int col) {
//System.out.println("data[6].length" + data[6].length);
if (row < 0) return false;
if (row >= rowCount) return false;
//if (col >= columnCount) return false;
if (col >= data[row].length) return false;
if (col < 0) return false;
if(data[row][col] == 0) return false;
return !Float.isNaN(data[row][col]);
} public float getColumnMin(int col) {
float m = Float.MAX_VALUE;
for (int row = 0; row < rowCount; row++) {
if (isValid(row, col)) {
if (data[row][col] < m) {
m = data[row][col];
}
}
}
return m;
} public float getColumnMax(int col) {
float m = -Float.MAX_VALUE;
for (int row = 0; row < rowCount; row++) {
if (isValid(row, col)) {
if (data[row][col] > m) {
m = data[row][col];
}
}
}
return m;
} public float getRowMin(int row) {
float m = Float.MAX_VALUE;
for (int col = 0; col < columnCount; col++) {
if (isValid(row, col)) {
if (data[row][col] < m) {
m = data[row][col];
}
}
}
return m;
} public float getRowMax(int row) {
float m = -Float.MAX_VALUE;
for (int col = 0; col < columnCount; col++) {
if (isValid(row, col)) {
if (data[row][col] > m) {
m = data[row][col];
}
}
}
return m;
} public float getTableMin() {
float m = Float.MAX_VALUE;
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
if (isValid(row, col)) {
if (data[row][col] < m) {
m = data[row][col];
}
}
}
}
return m;
} public float getTableMax() {
float m = -Float.MAX_VALUE;
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
if (isValid(row, col)) {
if (data[row][col] > m) {
m = data[row][col];
}
}
}
}
return m;
} public boolean hasData(int row, int startCol) {
boolean hasData = false;
for (int col = startCol; col < columnCount; col++) {
//System.out.println("row="+row+" col="+col+" isValid="+isValid(row, col));
if (isValid(row, col)) {
hasData = true;
break;
}
}
return hasData;
} public float getRowMin(int row, int startCol) {
float m = Float.MAX_VALUE;
for (int col = startCol; col < columnCount; col++) { //System.out.println("row="+row+" col="+col+" isValid="+isValid(row, col));
if (isValid(row, col)) {
if (data[row][col] < m) {
m = data[row][col];
}
}
}
return m;
} public float getRowMax(int row, int startCol) {
float m = -Float.MAX_VALUE;
for (int col = startCol; col < columnCount; col++) {
//System.out.println("row="+row+" col="+col+" isValid="+isValid(row, col));
if (isValid(row, col)) {
if (data[row][col] > m) {
m = data[row][col];
}
}
}
return m;
} public float getRowMin(int row, int startCol, int endCol) {
float m = Float.MAX_VALUE;
for (int col = startCol; col < endCol + 1; col++) { //System.out.println("row="+row+" col="+col+" isValid="+isValid(row, col));
if (isValid(row, col)) {
if (data[row][col] < m) {
m = data[row][col];
}
}
}
return m;
} public float getRowMax(int row, int startCol, int endCol) {
float m = -Float.MAX_VALUE;
for (int col = startCol; col < endCol + 1; col++) {
//System.out.println("row="+row+" col="+col+" isValid="+isValid(row, col));
if (isValid(row, col)) {
if (data[row][col] > m) {
m = data[row][col];
}
}
}
return m;
}
}
class Integrator { final float DAMPING = 0.5f;
final float ATTRACTION = 0.2f; float value;
float vel;
float accel;
float force;
float mass = 1; float damping = DAMPING;
float attraction = ATTRACTION;
boolean targeting;
float target; Integrator() { } Integrator(float value) {
this.value = value;
} Integrator(float value, float damping, float attraction) {
this.value = value;
this.damping = damping;
this.attraction = attraction;
} public void set(float v) {
value = v;
} public void update() {
if (targeting) {
force += attraction * (target - value);
} accel = force / mass;
vel = (vel + accel) * damping;
value += vel; force = 0;
} public void target(float t) {
targeting = true;
target = t;
} public void noTarget() {
targeting = false;
}
}
static public void main(String[] passedArgs) {
String[] appletArgs = new String[] { "TCS1" };
if (passedArgs != null) {
PApplet.main(concat(appletArgs, passedArgs));
} else {
PApplet.main(appletArgs);
}
}
}

基于Processing的数据可视化的相关教程结束。

《基于Processing的数据可视化.doc》

下载本文的Word格式文档,以方便收藏与打印。