1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
|
#ifndef HEAT_MAP_H
#define HEAT_MAP_H
#include <cairomm/surface.h>
#include <cairomm/context.h>
#include <sigc++/signal.h>
#include "colormap.h"
#include "colorscale.h"
#include "imageinterface.h"
#include "plotbase.h"
#include "title.h"
enum class RangeLimit { Extreme, Winsorized, Specified };
struct RangeConfiguration {
RangeLimit minimum;
RangeLimit maximum;
double specified_min = 0.0;
double specified_max = 1.0;
};
inline RangeConfiguration WinsorizedRange() {
return RangeConfiguration{RangeLimit::Winsorized, RangeLimit::Winsorized};
}
inline RangeConfiguration FullRange() {
return RangeConfiguration{RangeLimit::Winsorized, RangeLimit::Winsorized};
}
class HeatMap : public PlotBase {
public:
HeatMap();
void Clear();
void Invalidate() { _isImageInvalidated = true; }
ColorMap::Type GetColorMap() const { return _colorMap; }
void SetColorMap(ColorMap::Type colorMap) {
_colorMap = colorMap;
_isImageInvalidated = true;
}
const ImageInterface& Image() const { return *_image; }
void SetImage(std::unique_ptr<ImageInterface> image) {
_image = std::move(image);
_isImageInvalidated = true;
}
bool HasImage() const { return _image != nullptr; }
void SetZRange(const RangeConfiguration& range) {
_zRange = range;
_isImageInvalidated = true;
}
const RangeConfiguration& ZRange() const { return _zRange; }
std::array<size_t, 2> ImageXRange() const;
std::array<size_t, 2> ImageYRange() const;
/**
* For very large images (>30K), the data will be downsampled before
* being drawn on the imagesurface. This is because image surfaces
* have a limited size. These two functions return the factor by which
* the image was downsampled. This is particularly important when implementing
* @ref SignalDrawImage().
* @{
*/
size_t ImageToSurfaceXFactor() const;
size_t ImageToSurfaceYFactor() const;
/** @} */
void SetLogXScale(bool logXScale) {
_logXScale = logXScale;
_isImageInvalidated = true;
}
bool LogXScale() const { return _logXScale; }
void SetLogYScale(bool logYScale) {
_logYScale = logYScale;
_isImageInvalidated = true;
}
bool LogYScale() const { return _logYScale; }
void SetLogZScale(bool logZScale) {
_logZScale = logZScale;
_isImageInvalidated = true;
}
bool LogZScale() const { return _logZScale; }
void SetXAxisType(AxisType axisType) {
_xAxisType = axisType;
_isImageInvalidated = true;
}
AxisType XAxisType() const { return _xAxisType; }
double Max() const { return _zRange.specified_max; }
double Min() const { return _zRange.specified_min; }
void SetMax(double max) {
_zRange.specified_max = max;
_isImageInvalidated = true;
}
void SetMin(double min) {
_zRange.specified_min = min;
_isImageInvalidated = true;
}
void SavePdf(const std::string& filename, size_t width,
size_t height) final override;
void SaveSvg(const std::string& filename, size_t width,
size_t height) final override;
void SavePng(const std::string& filename, size_t width,
size_t height) final override;
bool ShowTitle() const { return _showTitle; }
void SetShowTitle(bool showTitle) {
_showTitle = showTitle;
_isImageInvalidated = true;
}
bool ShowXAxis() const { return _showXAxis; }
void SetShowXAxis(bool showXAxis) {
_showXAxis = showXAxis;
_isImageInvalidated = true;
}
bool ShowYAxis() const { return _showYAxis; }
void SetShowYAxis(bool showYAxis) {
_showYAxis = showYAxis;
_isImageInvalidated = true;
}
void SetShowX2Axis(bool showX2Axis) {
_showX2Axis = showX2Axis;
_isImageInvalidated = true;
}
void SetShowY2Axis(bool showY2Axis) {
_showY2Axis = showY2Axis;
_isImageInvalidated = true;
}
bool ShowColorScale() const { return _showColorScale; }
void SetShowColorScale(bool showColorScale) {
_showColorScale = showColorScale;
_isImageInvalidated = true;
}
bool ShowXAxisDescription() const { return _showXAxisDescription; }
void SetShowXAxisDescription(bool showXAxisDescription) {
_showXAxisDescription = showXAxisDescription;
_isImageInvalidated = true;
}
bool ShowYAxisDescription() const { return _showYAxisDescription; }
void SetShowYAxisDescription(bool showYAxisDescription) {
_showYAxisDescription = showYAxisDescription;
_isImageInvalidated = true;
}
bool ShowZAxisDescription() const { return _showZAxisDescription; }
void SetShowZAxisDescription(bool showZAxisDescription) {
_showZAxisDescription = showZAxisDescription;
_isImageInvalidated = true;
}
void SetCairoFilter(Cairo::Filter filter) {
_cairoFilter = filter;
_isImageInvalidated = true;
}
Cairo::Filter CairoFilter() const { return _cairoFilter; }
const std::string& TitleText() const { return _titleText; }
void SetTitleText(const std::string& title) {
_titleText = title;
_isImageInvalidated = true;
}
const std::string& XAxisDescription() const { return _xAxisDescription; }
void SetXAxisDescription(const std::string& description) {
_xAxisDescription = description;
_isImageInvalidated = true;
}
const std::string& YAxisDescription() const { return _yAxisDescription; }
void SetYAxisDescription(const std::string& description) {
_yAxisDescription = description;
_isImageInvalidated = true;
}
const std::string& ZAxisDescription() const { return _zAxisDescription; }
void SetZAxisDescription(const std::string& description) {
_zAxisDescription = description;
_isImageInvalidated = true;
}
bool ConvertToPlot(double screenX, double screenY, double& posX,
double& posY) const final override;
bool ConvertToScreen(double posX, double posY, double& screenX,
double& screenY) const final override;
bool UnitToImage(double posX, double posY, size_t& x, size_t& y) const;
void ImageToUnit(size_t x, size_t y, double& posX, double& posY) const;
void SetXAxisMin(double xAxisMin) { _xAxisMin = xAxisMin; }
void SetXAxisMax(double xAxisMax) { _xAxisMax = xAxisMax; }
void SetYAxisMin(double yAxisMin) { _yAxisMin = yAxisMin; }
void SetYAxisMax(double yAxisMax) { _yAxisMax = yAxisMax; }
void SetX2AxisMin(double x2AxisMin) { _x2AxisMin = x2AxisMin; }
void SetX2AxisMax(double x2AxisMax) { _x2AxisMax = x2AxisMax; }
void SetY2AxisMin(double y2AxisMin) { _y2AxisMin = y2AxisMin; }
void SetY2AxisMax(double y2AxisMax) { _y2AxisMax = y2AxisMax; }
/**
* Called after drawing the plot on to the cairo context. This allows the user
* to draw on the plot. The cairo context will be set up such that the plotted
* units can be used. The exception is when the axes are logarithmic; in that
* case the natural logarithm should be taken of the plot unit before drawing.
*/
sigc::signal<void(const Cairo::RefPtr<Cairo::Context>&)>& SignalDraw() {
return _signalDraw;
}
/**
* Called after having converted the plot data to a heat map image, before it
* is shown. This can be used to modify the heat map before it is displayed,
* e.g. to add a mask.
*/
sigc::signal<void(const Cairo::RefPtr<Cairo::ImageSurface>&)>&
SignalDrawImage() {
return _signalDrawImage;
}
static std::pair<float, float> DetermineRange(
const ImageInterface& image,
const RangeConfiguration& range_configuration, bool log_scale);
protected:
void Draw(const Cairo::RefPtr<Cairo::Context>& cairo) final override;
private:
void postRender(const Cairo::RefPtr<Cairo::Context>& cairo, size_t width,
size_t height);
void redrawWithoutChanges(const Cairo::RefPtr<Cairo::Context>& cairo,
size_t width, size_t height);
void drawAll(const Cairo::RefPtr<Cairo::Context>& cairo, size_t width,
size_t height);
/**
* Sets the trivial fields of the components (axes, title, etc.).
* It does not yet initialize their size.
*/
void initializeComponents();
void downsampleImageBuffer(size_t newWidth, size_t newHeight);
Rectangle getPlotArea(size_t width, size_t height) const final override;
bool _isInitialized;
bool _isImageInvalidated;
size_t _initializedWidth, _initializedHeight;
Cairo::RefPtr<Cairo::ImageSurface> _imageSurface;
ColorMap::Type _colorMap;
std::unique_ptr<ImageInterface> _image;
double _leftBorderSize, _rightBorderSize;
double _topBorderSize, _bottomBorderSize;
double _topAxisHeight;
ColorScale _colorScale;
Title _plotTitle;
bool _logXScale, _logYScale, _logZScale;
bool _showXAxis;
bool _showYAxis;
bool _showX2Axis;
bool _showY2Axis;
bool _showColorScale;
bool _showXAxisDescription;
bool _showYAxisDescription;
bool _showZAxisDescription;
bool _showTitle;
AxisType _xAxisType;
AxisType _yAxisType;
float _derivedMax, _derivedMin;
double _xAxisMin, _xAxisMax;
double _yAxisMin, _yAxisMax;
double _x2AxisMin, _x2AxisMax;
double _y2AxisMin, _y2AxisMax;
std::string _titleText;
RangeConfiguration _zRange;
Cairo::Filter _cairoFilter;
std::string _xAxisDescription;
std::string _x2AxisDescription;
std::string _yAxisDescription;
std::string _y2AxisDescription;
std::string _zAxisDescription;
sigc::signal<void(const Cairo::RefPtr<Cairo::Context>&)> _signalDraw;
sigc::signal<void(const Cairo::RefPtr<Cairo::ImageSurface>&)>
_signalDrawImage;
};
#endif
|