所以我在我的mac pro中编写了一个带有处理的平行坐标程序。但是,当我尝试运行此程序时,我在屏幕上看不到任何线条。我很困惑,因为该程序在我朋友的基于 Windows 的计算机上运行得很好。我试图在我的“draw()”函数的末尾添加“noLoop()”并且它有效。但我仍然无法弄清楚原因。有谁知道具体原因吗?提前致谢!
FloatTable data;
String dataPath = "cars.csv";
int numRows;
int numCols;
int[] colMin;
int[] colMax;
String[] colNames;
float plotX1, plotY1;
float plotX2, plotY2;
float diffBetweenXCoords;
PFont titleFont;
PFont labelFont;
PFont axisLimitsFont;
color[] axisColor = { #333333, #000000 };
color[] fontAxisColor = { #333333, #FF2222 };
color[] fontLimitsColor = { #555555, #FF2222 };
color triangleColor = #888888;
color[] linesColor = { #ED1317, #1397ED };
int[] axisOrder;
boolean[] axisFlipped;
// Setup
void setup()
{
size(1000, 500);
// Read data
data = new FloatTable(dataPath);
numRows = data.getRowCount();
numCols = data.getColumnCount();
colNames = data.getColumnNames();
colMin = new int[ numCols ];
colMax = new int[ numCols ];
axisOrder = new int[ numCols ];
axisFlipped = new boolean[ numCols ];
for(int col = 0; col < numCols; col++)
{
float maxNumber = data.getColumnMax(col);
float minNumber = data.getColumnMin(col);
colMin[col] = int(floor(minNumber));
colMax[col] = int(ceil(maxNumber));
axisOrder[col] = col;
axisFlipped[col] = false;
}
// Fonts
titleFont = createFont("Verdana", 16);
labelFont = createFont("Verdana Bold", 11);
axisLimitsFont = createFont("Georgia", 11);
// Plot area limits
plotX1 = 30;
plotX2 = width - plotX1;
plotY1 = 60;
plotY2 = height - plotY1;
diffBetweenXCoords = (plotX2 - plotX1) / (numCols - 1);
if(frame != null)
{
frame.setTitle(dataPath);
}
smooth();
}
// Draw
void draw()
{
// Background
background(240);
// Draw the plot area
fill(240);
noStroke();
rect(plotX1, plotY1, plotX2 - plotX1, plotY2 - plotY1);
//drawTitle();
drawAxis();
drawLines();
}
void drawAxis()
{
float xCoordsForAxis = plotX1;
float yAxisLbl = plotY2 + 40;
float yMinLbl = plotY2 + 15;
float yMaxLbl = plotY1 - 7;
float yTriMin = plotY1 - 25;
float yTriMax = plotY1 - 35;
strokeCap(PROJECT);
strokeWeight(1);
stroke(0);
for( int col = 0; col < numCols; col++, xCoordsForAxis += diffBetweenXCoords )
{
int colToDraw = axisOrder[col];
// Draw Axis
stroke(axisColor[0]);
line(xCoordsForAxis, plotY1, xCoordsForAxis, plotY2);
// Label min/max
textAlign(CENTER);
textFont(axisLimitsFont);
fill(fontLimitsColor[0]);
if( axisFlipped[colToDraw])
{
text( colMin[colToDraw], xCoordsForAxis, yMaxLbl);
text( colMax[colToDraw], xCoordsForAxis, yMinLbl);
}
else
{
text( colMin[colToDraw], xCoordsForAxis, yMinLbl);
text( colMax[colToDraw], xCoordsForAxis, yMaxLbl);
}
// Axis label
textFont( labelFont );
fill(fontAxisColor[0]);
text( colNames[colToDraw], xCoordsForAxis, yAxisLbl );
// Triangle
fill(triangleColor);
noStroke();
if( axisFlipped[colToDraw] )
{
triangle(xCoordsForAxis - 3, yTriMax, xCoordsForAxis, yTriMin, xCoordsForAxis + 3, yTriMax);
}
else
{
triangle(xCoordsForAxis - 3, yTriMin, xCoordsForAxis, yTriMax, xCoordsForAxis + 3, yTriMin);
}
}
}
void drawLines()
{
noFill();
strokeWeight(1);
for(int row = 0; row < numRows; row++)
{
beginShape();
for(int column = 0; column < numCols; column++)
{
int colToDraw = axisOrder[column];
if(data.isValid(row, column))
{
float cMax = ( axisFlipped[colToDraw] ? colMin[colToDraw] : colMax[colToDraw] );
float cMin = ( axisFlipped[colToDraw] ? colMax[colToDraw] : colMin[colToDraw] );
float value = data.getFloat(row, colToDraw);
float x = plotX1 + diffBetweenXCoords * colToDraw;
float y = map(value, cMin, cMax, plotY2, plotY1);
//stroke(#5679C1);
if(colToDraw == 0)
{
stroke( lerpColor(linesColor[0], linesColor[1], map(value, cMin, cMax, 0., 1.) ), 150 );
}
vertex(x, y);
}
}
endShape();
}
}
class FloatTable {
int rowCount;
int columnCount;
float[][] data;
String[] rowNames;
String[] columnNames;
FloatTable(String filename) {
String[] rows = loadStrings(filename);
String[] columns = split(rows[0], TAB);
columnNames = subset(columns, 1); // upper-left corner ignored
scrubQuotes(columnNames);
columnCount = columnNames.length;
rowNames = new String[rows.length-1];
data = new float[rows.length-1][];
// start reading at row 1, because the first row was only the column headers
for (int i = 1; i < rows.length; i++) {
if (trim(rows[i]).length() == 0) {
continue; // skip empty rows
}
if (rows[i].startsWith("#")) {
continue; // skip comment lines
}
// split the row on the tabs
String[] pieces = split(rows[i], TAB);
scrubQuotes(pieces);
// copy row title
rowNames[rowCount] = pieces[0];
// copy data into the table starting at pieces[1]
data[rowCount] = parseFloat(subset(pieces, 1));
// increment the number of valid rows found so far
rowCount++;
}
// resize the 'data' array as necessary
data = (float[][]) subset(data, 0, rowCount);
}
void scrubQuotes(String[] array) {
for (int i = 0; i < array.length; i++) {
if (array[i].length() > 2) {
// remove quotes at start and end, if present
if (array[i].startsWith("\"") && array[i].endsWith("\"")) {
array[i] = array[i].substring(1, array[i].length() - 1);
}
}
// make double quotes into single quotes
array[i] = array[i].replaceAll("\"\"", "\"");
}
}
int getRowCount() {
return rowCount;
}
String getRowName(int rowIndex) {
return rowNames[rowIndex];
}
String[] getRowNames() {
return rowNames;
}
// Find a row by its name, returns -1 if no row found.
// This will return the index of the first row with this name.
// A more efficient version of this function would put row names
// into a Hashtable (or HashMap) that would map to an integer for the row.
int getRowIndex(String name) {
for (int i = 0; i < rowCount; i++) {
if (rowNames[i].equals(name)) {
return i;
}
}
//println("No row named '" + name + "' was found");
return -1;
}
// technically, this only returns the number of columns
// in the very first row (which will be most accurate)
int getColumnCount() {
return columnCount;
}
String getColumnName(int colIndex) {
return columnNames[colIndex];
}
String[] getColumnNames() {
return columnNames;
}
float getFloat(int rowIndex, int col) {
// Remove the 'training wheels' section for greater efficiency
// It's included here to provide more useful error messages
// begin training wheels
if ((rowIndex < 0) || (rowIndex >= 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];
}
boolean isValid(int row, int col) {
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;
return !Float.isNaN(data[row][col]);
}
float[] getColumnMinMax(int col) {
float Min = Float.MAX_VALUE;
float Max = -Float.MAX_VALUE;
for (int i = 0; i < rowCount; i++) {
if (!Float.isNaN(data[i][col])) {
if (data[i][col] < Min) {
Min = data[i][col];
}
if (data[i][col] > Max) {
Max = data[i][col];
}
}
}
float[] toRet = { Min, Max };
return toRet;
}
float getColumnMin(int col) {
float m = Float.MAX_VALUE;
for (int i = 0; i < rowCount; i++) {
if (!Float.isNaN(data[i][col])) {
if (data[i][col] < m) {
m = data[i][col];
}
}
}
return m;
}
float getColumnMax(int col) {
float m = -Float.MAX_VALUE;
for (int i = 0; i < rowCount; i++) {
if (isValid(i, col)) {
if (data[i][col] > m) {
m = data[i][col];
}
}
}
return m;
}
float getRowMin(int row) {
float m = Float.MAX_VALUE;
for (int i = 0; i < columnCount; i++) {
if (isValid(row, i)) {
if (data[row][i] < m) {
m = data[row][i];
}
}
}
return m;
}
float getRowMax(int row) {
float m = -Float.MAX_VALUE;
for (int i = 1; i < columnCount; i++) {
if (!Float.isNaN(data[row][i])) {
if (data[row][i] > m) {
m = data[row][i];
}
}
}
return m;
}
float getTableMin() {
float m = Float.MAX_VALUE;
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < columnCount; j++) {
if (isValid(i, j)) {
if (data[i][j] < m) {
m = data[i][j];
}
}
}
}
return m;
}
float getTableMax() {
float m = -Float.MAX_VALUE;
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < columnCount; j++) {
if (isValid(i, j)) {
if (data[i][j] > m) {
m = data[i][j];
}
}
}
}
return m;
}
}
当我尝试绘制点而不是线时,它也有效!事情变得很奇怪:)
以下是我的 .csv 文件中的一些行:
使 mpg 气缸排量 (cu in) 马力 重量 (lb) 加速度 (sec) 年份 原产地
雪佛兰 18 8 307 130 3504 12 70 1
别克 15 8 350 165 3693 11.5 70 1
普利茅斯 18 8 318 150 3436 11 70 1
amc 16 8 304 150 3433 12 70 1
福特 17 8 302 140 3449 10.5 70 1
福特 15 8 429 198 4341 10 70 1
雪佛兰 14 8 454 220 4354 9 70 1
普利茅斯 14 8 440 215 4312 8.5 70 1
庞蒂亚克 14 8 455 225 4425 10 70 1
amc 15 8 390 190 3850 8.5 70 1
闪避 15 8 383 170 3563 10 70 1
普利茅斯 14 8 340 160 3609 8 70 1
雪佛兰 15 8 400 150 3761 9.5 70 1
别克 14 8 455 225 3086 10 70 1
丰田 24 4 113 95 2372 15 70 3
普利茅斯 22 6 198 95 2833 15.5 70 1
amc 18 6 199 97 2774 15.5 70 1
福特 21 6 200 85 2587 16 70 1
达特桑 27 4 97 88 2130 14.5 70 3
大众 26 4 97 46 1835 20.5 70 2
标致 25 4 110 87 2672 17.5 70 2
奥迪 24 4 107 90 2430 14.5 70 2
萨博 25 4 104 95 2375 17.5 70 2
宝马 26 4 121 113 2234 12.5 70 2