[python] matplotlib: change Store::Rectangle structure to (left, right,

top, bottom) and avoid rounding error when converting flaot rect to
pixel
This commit is contained in:
Émilie Feral
2020-03-30 18:03:10 +02:00
parent d468f5e130
commit 7c612f35a8
4 changed files with 29 additions and 29 deletions

View File

@@ -182,8 +182,9 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) {
mp_float_t iW = mp_obj_get_float(wItems[wLength > 1 ? i : 0]);
mp_float_t iB = mp_obj_get_float(bItems[bLength > 1 ? i : 0]);
mp_float_t iX = mp_obj_get_float(xItems[i])-iW/2.0;
mp_float_t iY = iH < 0.0 ? iB : iB + iH;
sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iY), mp_obj_new_float(iW), mp_obj_new_float(std::fabs(iH)), color);
mp_float_t iYStart = iH < 0.0 ? iB : iB + iH;
mp_float_t iYEnd = iH < 0.0 ? iB + iH : iB;
sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iX+iW), mp_obj_new_float(iYStart), mp_obj_new_float(iYEnd), color); // TODO: use float_binary_op?
}
return mp_const_none;
}
@@ -262,7 +263,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) {
mp_float_t upperBound = mp_obj_get_float(edgeItems[binIndex+1]);
while (mp_obj_get_float(xItems[xIndex]) < upperBound || (binIndex == nBins - 1 && mp_obj_get_float(xItems[xIndex]) == upperBound)) {
// Increment the bin count
binItems[binIndex] = mp_obj_new_int(mp_obj_get_int(binItems[binIndex]) + 1); // TODO: better way?
binItems[binIndex] = mp_obj_new_int(mp_obj_get_int(binItems[binIndex]) + 1); // TODO: better way? Use int_unary_op?
xIndex++;
if (xIndex == xLength) {
break;
@@ -273,8 +274,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) {
KDColor color = Palette::nextDataColor(&paletteIndex);
for (size_t i=0; i<nBins; i++) {
mp_float_t width = mp_obj_get_float(edgeItems[i+1]) - mp_obj_get_float(edgeItems[i]);
sPlotStore->addRect(edgeItems[i], binItems[i], mp_obj_new_float(width), binItems[i], color);
sPlotStore->addRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color);
}
return mp_const_none;
}

View File

@@ -121,16 +121,16 @@ template class PlotStore::ListIterator<PlotStore::Rect>;
PlotStore::Rect::Rect(mp_obj_t tuple) {
mp_obj_t * elements;
mp_obj_get_array_fixed_n(tuple, 5, &elements);
m_x = mp_obj_get_float(elements[0]);
m_y = mp_obj_get_float(elements[1]);
m_width = mp_obj_get_float(elements[2]);
m_height = mp_obj_get_float(elements[3]);
m_left = mp_obj_get_float(elements[0]);
m_right = mp_obj_get_float(elements[1]);
m_top = mp_obj_get_float(elements[2]);
m_bottom = mp_obj_get_float(elements[3]);
m_color = KDColor::RGB16(mp_obj_get_int(elements[4]));
}
void PlotStore::addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c) {
void PlotStore::addRect(mp_obj_t left, mp_obj_t right, mp_obj_t top, mp_obj_t bottom, KDColor c) {
mp_obj_t color = mp_obj_new_int(c);
mp_obj_t items[5] = {x, y, width, height, color};
mp_obj_t items[5] = {left, right, top, bottom, color};
checkFloatType(items, 4);
mp_obj_t tuple = mp_obj_new_tuple(5, items);
mp_obj_list_append(m_rects, tuple);
@@ -204,10 +204,8 @@ void PlotStore::initRange() {
updateRange(&xMin, &xMax, &yMin, &yMax, segment.xEnd(), segment.yEnd());
}
for (PlotStore::Rect rectangle : rects()) {
float x = rectangle.x();
float y = rectangle.y();
updateRange(&xMin, &xMax, &yMin, &yMax, x, y);
updateRange(&xMin, &xMax, &yMin, &yMax, x + rectangle.width(), y - rectangle.height());
updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.left(), rectangle.top());
updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.right(), rectangle.bottom());
}
checkPositiveRangeAndAddMargin(&xMin, &xMax);
checkPositiveRangeAndAddMargin(&yMin, &yMax);

View File

@@ -87,16 +87,16 @@ public:
class Rect {
public:
Rect(mp_obj_t tuple);
float x() const { return m_x; }
float y() const { return m_y; }
float width() const { return m_width; }
float height() const { return m_height; }
float left() const { return m_left; }
float right() const { return m_right; }
float top() const { return m_top; }
float bottom() const { return m_bottom; }
KDColor color() const { return m_color; }
private:
float m_x;
float m_y;
float m_width;
float m_height;
float m_left;
float m_right;
float m_top;
float m_bottom;
KDColor m_color;
};

View File

@@ -54,13 +54,15 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen
static inline KDCoordinate maxKDCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const {
KDCoordinate left = std::round(floatToPixel(Axis::Horizontal, rect.left()));
KDCoordinate right = std::round(floatToPixel(Axis::Horizontal, rect.right()));
KDCoordinate top = std::round(floatToPixel(Axis::Vertical, rect.top()));
KDCoordinate bottom = std::round(floatToPixel(Axis::Vertical, rect.bottom()));
KDRect pixelRect(
std::round(floatToPixel(Axis::Horizontal, rect.x())),
std::round(floatToPixel(Axis::Vertical, rect.y())),
// Use std::ceil instead of std::round to avoid empty pixel line between bars and horizontal axis line
// TODO: change stored rectangles to keep all summits?
maxKDCoordinate(std::ceil(rect.width() / pixelWidth()), 1), // Rectangle should at least be visible
std::ceil(rect.height() / pixelHeight())
left,
top,
maxKDCoordinate(right - left, 1), // Rectangle should at least be visible
bottom - top
);
ctx->fillRect(pixelRect, rect.color());
}