我正在考虑一种新的实现方式,即简单的2D图形矩阵,其中项目的颜色取决于分配给这些项目的各个值。到目前为止,我为此使用了以下架构:
1)提供基于间隔的色标参考(例如20个块),我可以为其指定特定范围的值,例如100-1000。
2)用上述比例尺的颜色链接矩阵项的各个值,因此值100的项将是BLUE
,而值1000的项将是RED
。
这种解决方案的问题在于,我必须从“块”构建我的色标,所以看起来像这样:
这个解决方案还不错,但是我想走得更远,并借助色标实现更准确的value-color
匹配,如下所示:
接下来,上述钻头将没有太大不同。我将把此比例尺“放”到给定范围(例如100-1000)的值之间,并取决于矩阵项的单个值,我将从比例尺中选择适当的颜色并将其分配给给定的项。
但是,我如何绘制这样的比例尺并将其放在特定值范围内,以尝试避免旧解决方案中的ItemValue-To-SpecificColorBlock
匹配问题?
最佳答案
在统计(可视化)中,这称为热图。
为了计算给定值的颜色,并且MIN
即
double hue = Color.BLUE.getHue() + (Color.RED.getHue() - Color.BLUE.getHue()) * (value - MIN) / (MAX - MIN) ;
然后使用色相创建具有完全饱和度和亮度的颜色:
Color color = Color.hsb(hue, 1.0, 1.0);
要创建色阶图像,请创建WritableImage,获取像素编写器,遍历所有像素,然后使用上述公式设置每个像素的颜色,并沿x轴从0到图像的宽度插值。 (如果需要垂直色标,则类似地沿y轴进行插值。)
这是一个绘制色标的示例。您可以使用
getColorForValue(...)
方法计算给定值的颜色,以显示矩阵。import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class HeatMap extends Application {
private final static double MIN = 100 ;
private final static double MAX = 1000 ;
private final static double BLUE_HUE = Color.BLUE.getHue() ;
private final static double RED_HUE = Color.RED.getHue() ;
@Override
public void start(Stage primaryStage) {
Image colorScale = createColorScaleImage(600, 120, Orientation.HORIZONTAL);
ImageView imageView = new ImageView(colorScale);
StackPane root = new StackPane(imageView);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private Color getColorForValue(double value) {
if (value < MIN || value > MAX) {
return Color.BLACK ;
}
double hue = BLUE_HUE + (RED_HUE - BLUE_HUE) * (value - MIN) / (MAX - MIN) ;
return Color.hsb(hue, 1.0, 1.0);
}
private Image createColorScaleImage(int width, int height, Orientation orientation) {
WritableImage image = new WritableImage(width, height);
PixelWriter pixelWriter = image.getPixelWriter();
if (orientation == Orientation.HORIZONTAL) {
for (int x=0; x<width; x++) {
double value = MIN + (MAX - MIN) * x / width;
Color color = getColorForValue(value);
for (int y=0; y<height; y++) {
pixelWriter.setColor(x, y, color);
}
}
} else {
for (int y=0; y<height; y++) {
double value = MAX - (MAX - MIN) * y / height ;
Color color = getColorForValue(value);
for (int x=0; x<width; x++) {
pixelWriter.setColor(x, y, color);
}
}
}
return image ;
}
public static void main(String[] args) {
launch(args);
}
}