docs: private void renderMatrix(Graphics2D g2, double fontSize) {
  		int numCategories = confusion.getNumRows();
  
  		Font fontNumber = new Font("Serif", Font.BOLD, (int)(0.6*fontSize + 0.5));
  		g2.setFont(fontNumber);
  		FontMetrics metrics = g2.getFontMetrics(fontNumber);
  		for (int i = 0; i < numCategories; i++) {
  			int y0 = i*gridHeight/numCategories;
  			int y1 = (i+1)*gridHeight/numCategories;
  
  			for (int j = 0; j < numCategories; j++) {
  				int x0 = j*gridWidth/numCategories;
  				int x1 = (j+1)*gridWidth/numCategories;
  
  				double value = confusion.unsafe_get(i,j);
  
  				int red,green,blue;
  				if( gray ) {
  					red = green = blue = (int)(255*(1.0-value));
  				} else {
  					green = 0;
  					red = (int)(255*value);
  					blue = (int)(255*(1.0-value));
  				}
  				g2.setColor(new Color(red, green, blue));
  
  				g2.fillRect(x0,y0,x1-x0,y1-y0);
  
  				// Render numbers inside the squares.  Pick a color so that the number is visible no matter what
  				// the color of the square is
  				if( showNumbers && (showZeros || value != 0 )) {
  					int a = (red+green+blue)/3;
  
  					String text = ""+(int)(value*100.0+0.5);
  					Rectangle2D r = metrics.getStringBounds(text,null);
  
  					float adjX = (float)(r.getX()*2 + r.getWidth())/2.0f;
  					float adjY = (float)(r.getY()*2 + r.getHeight())/2.0f;
  
  					float x = ((x1+x0)/2f-adjX);
  					float y = ((y1+y0)/2f-adjY);
  
  					int gray = a > 127 ? 0 : 255;
  
  					g2.setColor(new Color(gray,gray,gray));
  					g2.drawString(text,x,y);
  				}
  			}
  		}
  	}