Skip to content

Commit

Permalink
ide/scave: Change automatic line chart area computation logic
Browse files Browse the repository at this point in the history
The main motivation was to make sure that data which is far from
the origin, but spans a relatively small range (say, 10000..10005),
is still plotted so that the points are not too close to the edge
of the axes area, making them hard to find/see.

This is done by calculating the padding after including the origin
in the bounds rectangle, so it will be sized relative to the "10005",
and not to the "5" in the example above.

This should be more intuitive.
  • Loading branch information
torokati44 committed Jan 26, 2024
1 parent efad726 commit 8e7a641
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 61 deletions.
95 changes: 59 additions & 36 deletions python/omnetpp/scave/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1254,52 +1254,75 @@ def get_prop(k):
# only use scientific notation for negative exponents
ax.ticklabel_format(scilimits=(0, 1000), useOffset=False, useLocale=False)

from enum import Enum

class PlotAreaCalculationMode(Enum):
DATA_WITH_PADDING = 0
DATA_WITH_PADDING_AND_ORIGIN = 1
DATA_WITH_PADDING_AND_ORIGIN_WITH_PADDING = 2

mode = PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN

# start with a tight value bounding box
ax.margins(0)
ax.autoscale(True)

# apply the same auto-range logic as in the native widgets of the IDE
min_x, max_x = ax.get_xlim()
width = max_x - min_x # not computing twice, would cause asymmetry
min_x = 0 if min_x >= 0 else min_x - width/80
max_x = 0 if max_x <= 0 else max_x + width/80

if width == 0:
if max_x > 0:
max_x *= 1.25
if min_x < 0:
min_x *= 1.25
if min_x == max_x == 0:
min_x = -1
max_x = 1

if get_prop("xaxis_min"):
min_x = float(get_prop("xaxis_min"))
if get_prop("xaxis_max"):
max_x = float(get_prop("xaxis_max"))
min_y, max_y = ax.get_ylim()

ax.set_xlim(left=min_x, right=max_x)
# relative to data range
padding_left = 0.1
padding_right = 0.1
padding_bottom = 0.2
padding_top = 0.2

if mode in (PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN_WITH_PADDING,
PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN):

# The idea is that if we're extending the axis range just to include
# the origin, we probably don't want as much padding around it.

origin_margin_factor = 0.0 if (mode == PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN) \
else 0.5

if min_x >= 0:
min_x = 0
padding_left *= origin_margin_factor
if max_x <= 0:
max_x = 0
padding_right *= origin_margin_factor
if min_y >= 0:
min_y = 0
padding_bottom *= origin_margin_factor
if max_y <= 0:
max_y = 0
padding_top *= origin_margin_factor

w = max_x - min_x
h = max_y - min_y

if w == 0:
min_x -= 0.5
max_x += 0.5
else:
min_x -= w * padding_left
max_x += w * padding_right

if h == 0:
min_y -= 0.5
max_y += 0.5
else:
min_y -= h * padding_bottom
max_y += h * padding_top

min_y, max_y = ax.get_ylim()
height = max_y - min_y # not computing twice, would cause asymmetry
min_y = 0 if min_y >= 0 else min_y - height/3
max_y = 0 if max_y <= 0 else max_y + height/3

if height == 0:
if max_y > 0:
max_y *= 1.25
if min_y < 0:
min_y *= 1.25
if min_y == max_y:
min_y = -1
max_y = 1

if get_prop("yaxis_min"):
min_y = float(get_prop("yaxis_min"))
if get_prop("yaxis_max"):
max_y = float(get_prop("yaxis_max"))
min_x = float(get_prop("xaxis_min") or min_x)
max_x = float(get_prop("xaxis_max") or max_x)

min_y = float(get_prop("yaxis_min") or min_y)
max_y = float(get_prop("yaxis_max") or max_y)

ax.set_xlim(left=min_x, right=max_x)
ax.set_ylim(bottom=min_y, top=max_y)

# reducing margins all around
Expand Down
81 changes: 56 additions & 25 deletions ui/org.omnetpp.scave/src/org/omnetpp/scave/charting/Lines.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ class Lines implements ILinePlot {

private static final boolean debug = false;

public enum PlotAreaCalculationMode {
DATA_WITH_PADDING,
DATA_WITH_PADDING_AND_ORIGIN,
DATA_WITH_PADDING_AND_ORIGIN_WITH_PADDING,
}

private LinePlot parent;
private Rectangle rect = new Rectangle(0,0,1,1);

Expand Down Expand Up @@ -61,6 +67,10 @@ public Rectangle getPlotRectangle() {
}

protected RectangularArea calculatePlotArea() {
return calculatePlotArea(PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN);
}

protected RectangularArea calculatePlotArea(PlotAreaCalculationMode mode) {

RectangularArea area = new RectangularArea(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
Expand Down Expand Up @@ -138,37 +148,58 @@ protected RectangularArea calculatePlotArea() {
area.maxY = 1.0;
}

double w = area.width();
double h = area.height();
// relative to data range
double paddingLeft = 0.1;
double paddingRight = 0.1;
double paddingBottom = 0.2;
double paddingTop = 0.2;

area.minX = (area.minX>=0 ? 0 : area.minX-w/80);
area.maxX = (area.maxX<=0 ? 0 : area.maxX+w/80);
area.minY = (area.minY>=0 ? 0 : area.minY-h/3);
area.maxY = (area.maxY<=0 ? 0 : area.maxY+h/3);
if (mode == PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN_WITH_PADDING
|| mode == PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN) {

// If the original area was 0 size in either dimension, add a 25% margin "away from zero"
// in both dimensions, so the data is not covered by the chart area border.
// If all data was on the 0 line in a dimension, set a fixed range for it.
if (h == 0) {
if (area.maxY > 0)
area.maxY *= 1.25;
if (area.minY < 0)
area.minY *= 1.25;
if (area.height() == 0) {
area.minY = -1;
area.maxY = 1;
// The idea is that if we're extending the axis range in a direction just to
// include the origin, we probably don't want as much (or any) padding there.

double originMarginFactor = (mode == PlotAreaCalculationMode.DATA_WITH_PADDING_AND_ORIGIN)
? 0.0 : 0.5;

if (area.minX >= 0) {
area.minX = 0;
paddingLeft *= originMarginFactor;
}
if (area.maxX <= 0) {
area.maxX = 0;
paddingRight *= originMarginFactor;
}
if (area.minY >= 0) {
area.minY = 0;
paddingBottom *= originMarginFactor;
}
if (area.maxY <= 0) {
area.maxY = 0;
paddingTop *= originMarginFactor;
}
}

double w = area.width();
double h = area.height();

if (w == 0) {
if (area.maxX > 0)
area.maxX *= 1.25;
if (area.minX < 0)
area.minX *= 1.25;
if (area.width() == 0) {
area.minX = -1;
area.maxX = 1;
}
area.minX -= 0.5;
area.maxX += 0.5;
}
else {
area.minX -= w * paddingLeft;
area.maxX += w * paddingRight;
}

if (h == 0) {
area.minY -= 0.5;
area.maxY += 0.5;
}
else {
area.minY -= h * paddingBottom;
area.maxY += h * paddingTop;
}

return area;
Expand Down

0 comments on commit 8e7a641

Please sign in to comment.