Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

share 0-line between y axes #1271

Closed
themasch opened this issue Dec 23, 2014 · 7 comments

Comments

Projects
None yet
6 participants
@themasch
Copy link

commented Dec 23, 2014

I'd like to have an option that forces both y-axes to share the same 0-line.
Currently, when I got positive and negative values on first y-axis and positive values on the second one,
it looks kind of unsexy

grafana-axes1

I'd really prefer both scales to use the same origin here. Is that possible?

@sahilthapar

This comment has been minimized.

Copy link

commented Dec 29, 2014

👍

@torkelo

This comment has been minimized.

Copy link
Member

commented Jan 12, 2015

Not sure how to do this, so if anyone is up to try it I would welcome a PR :)

@JeremyMorton

This comment has been minimized.

Copy link

commented Jan 13, 2015

I haven't had a chance to look into putting this in the Grafana code, but here's the pseudo-code algorithm I came up with for changing the min and max of the left and right y-axes so that a number on the left axis is "equivalent" to a number on the right axis [0 being that value on both sides in the example above]:

ScaleWithOneEquivalentValue(leftMin, leftMax,
                            rightMin, rightMax,
                            leftEquivalentValue, rightEquivalentValue,
                            leftIsMaxFixed, leftIsMinFixed,
                            rightIsMaxFixed, rightIsMinFixed)
{
    if (leftIsMaxFixed and leftIsMinFixed and rightIsMaxFixed and rightIsMinFixed)
        fail("The minimum and maximum value for both axes can't all be fixed when trying to line up equivalent values");

    var leftMinIncludingEquivalent = min(leftEquivalentValue, leftMin);
    var leftMaxIncludingEquivalent = max(leftEquivalentValue, leftMax);
    var rightMinIncludingEquivalent = min(rightEquivalentValue, rightMin);
    var rightMaxIncludingEquivalent = max(rightEquivalentValue, rightMax);

    var leftExtent = leftMaxIncludingEquivalent - leftMinIncludingEquivalent;
    var rightExtent = rightMaxIncludingEquivalent - rightMinIncludingEquivalent;

    var leftPercentageAbove = (leftMaxIncludingEquivalent - leftEquivalentValue) / leftExtent;
    var leftPercentageBelow = 1 - leftPercentageAbove;
    var rightPercentageAbove = (rightMaxIncludingEquivalent - rightEquivalentValue) / rightExtent;
    var rightPercentageBelow = 1 - rightPercentageAbove;

    var leftDesiredPercentageBelow = leftPercentageBelow;
    var leftDesiredPercentageAbove = leftPercentageAbove;
    var rightDesiredPercentageBelow = rightPercentageBelow;
    var rightDesiredPercentageAbove = rightPercentageAbove;

    if (leftPercentageAbove < rightPercentageAbove)
    {
        // The left upper and right lower axis need to have their proportional size increased
        if (leftIsMaxFixed and rightIsMinFixed)
            fail("The left maximum value and the right minimum value are both fixed, so equivalent values can't be lined up");
        else if (leftIsMaxFixed)
            // The left maximum is fixed, so we can only lengthen the right lower axis
            if (leftPercentageAbove == 0 and rightPercentageAbove > 0)
                fail("Fixed left maximum value is not greater than the equivalent value while the right maximum value is, so equivalent values can't be lined up");
            rightDesiredPercentageBelow = leftPercentageBelow;
        else if (rightIsMinFixed)
            // The right minimum is fixed, so we can only lengthen the left upper axis
            if (rightPercentageBelow == 0 and leftPercentageBelow > 0)
                fail("Fixed right minimum value is not less than the equivalent value while the left minimum value is, so equivalent values can't be lined up");
            leftDesiredPercentageAbove = rightPercentageAbove;
        else
            // Lengthen the left upper and the right lower axis
            leftDesiredPercentageAbove = (leftPercentageAbove + rightPercentageAbove) / 2;
            rightDesiredPercentageBelow = (leftPercentageBelow + rightPercentageBelow) / 2;
    }
    if (leftPercentageAbove > rightPercentageAbove)
    {
        // The left lower and right upper axis need to have their proportional size increased
        if (leftIsMinFixed and rightIsMaxFixed)
            fail("The left minimum value and the right maximum value are both fixed, so equivalent values can't be lined up");
        else if (leftIsMinFixed)
            // The left minimum is fixed, so we can only lengthen the right upper axis
            if (leftPercentageBelow == 0 and rightPercentageBelow > 0)
                fail("Fixed left minimum value is not less than the equivalent value while the right minimum value is, so equivalent values can't be lined up");
            rightDesiredPercentageAbove = leftPercentageAbove;
        else if (rightIsMaxFixed)
            // The right maximum is fixed, so we can only lengthen the left lower axis
            if (rightPercentageAbove == 0 and leftPercentageAbove > 0)
                fail("Fixed right maximum value is not greater than the equivalent value while the left maximum value is, so equivalent values can't be lined up");
            leftDesiredPercentageBelow = rightPercentageBelow;
        else
            // Lengthen the left lower and the right upper axis
            leftDesiredPercentageBelow = (leftPercentageBelow + rightPercentageBelow) / 2;
            rightDesiredPercentageAbove = (leftPercentageAbove + rightPercentageAbove) / 2;
    }

    var leftNewMin = leftMinIncludingEquivalent;
    var leftNewMax = leftMaxIncludingEquivalent;
    var rightNewMin = rightMinIncludingEquivalent;
    var rightNewMax = rightMaxIncludingEquivalent;

    var leftDistanceBelow = leftEquivalentValue - leftMinIncludingEquivalent;
    var leftDistanceAbove = leftMaxIncludingEquivalent - leftEquivalentValue;
    var rightDistanceBelow = rightEquivalentValue - rightMinIncludingEquivalent;
    var rightDistanceAbove = rightMaxIncludingEquivalent - rightEquivalentValue;

    if (leftDesiredPercentageAbove > 0)
        leftNewMin = leftEquivalentValue - leftDistanceBelow * leftDesiredPercentageBelow / leftDesiredPercentageAbove;
    if (leftDesiredPercentageBelow > 0)
        leftNewMax = leftEquivalentValue + leftDistanceAbove * leftDesiredPercentageAbove / leftDesiredPercentageBelow;
    if (rightDesiredPercentageAbove > 0)
        rightNewMin = rightEquivalentValue - rightDistanceBelow * rightDesiredPercentageBelow / rightDesiredPercentageAbove;
    if (rightDesiredPercentageBelow > 0)
        rightNewMax = rightEquivalentValue + rightDistanceAbove * rightDesiredPercentageAbove / rightDesiredPercentageBelow;

    return {
        "leftNewMin": leftNewMin,
        "leftNewMax": leftNewMax,
        "rightNewMin": rightNewMin,
        "rightNewMax": rightNewMax
    }
}

It's actually more straightforward to do this when you have two "equivalent" values between the axes, as you can figure out the simple linear translation between the 2 axes using those 2 points and then take the max of the normalized axes' max values and the min of the normalized axes' min values and extend both of the axes to those limits:

ScaleWithTwoEquivalentValues(leftMin, leftMax,
                             rightMin, rightMax,
                             leftEquivalentValue1, rightEquivalentValue1,
                             leftEquivalentValue2, rightEquivalentValue2,
                             leftIsMaxFixed, leftIsMinFixed,
                             rightIsMaxFixed, rightIsMinFixed)
{
    if (leftIsMaxFixed and leftIsMinFixed and rightIsMaxFixed and rightIsMinFixed)
        fail("The minimum and maximum value for both axes can't all be fixed when trying to line up equivalent values");

    // linear translation: y = mx + b, or left = slope * right + offset
    // calculate slope: slope  deltaLeft/deltaRight
    var slope = (leftEquivalentValue2 - leftEquivalentValue1) / (rightEquivalentValue2 - rightEquivalentValue1);
    // calculate offset: offset = left - slope * right
    var offset = leftEquivalentValue1 - slope * rightEquivalentValue1;

    // translate right min and max into left scale
    var rightMinInLeftScale = slope * rightMin + offset;
    var rightMaxInLeftScale = slope * rightMax + offset;

    // find the new min and max
    var leftNewMin = min(leftMin, rightMinInLeftScale);
    var leftNewMax = max(leftMax, rightMaxInLeftScale);

    // translate the new min and max back to the right scale
    var rightNewMin = (leftNewMin - offset) / slope;
    var rightNewMax = (leftNewMax - offset) / slope;

    return {
        "leftNewMin": leftNewMin,
        "leftNewMax": leftNewMax,
        "rightNewMin": rightNewMin,
        "rightNewMax": rightNewMax
    }
}
@torkelo

This comment has been minimized.

Copy link
Member

commented Jan 15, 2015

interesting :) PR?

@JeremyMorton

This comment has been minimized.

Copy link

commented Jan 15, 2015

I'll see if I can get this together this weekend.

Edit: It looks like this is handled by jquery.flot.js; should Flot requests go there, or should it be changed here for this project?

I am also looking into my ability to contribute; hopefully, I can get that straightened out in the near future.

@rfrail3

This comment has been minimized.

Copy link

commented Mar 23, 2017

👍

@marefr

This comment has been minimized.

Copy link
Member

commented Mar 22, 2018

Fixed by #10994

@marefr marefr closed this Mar 22, 2018

marefr added a commit that referenced this issue Mar 22, 2018

ryantxu added a commit to ryantxu/grafana that referenced this issue Mar 23, 2018

Merge remote-tracking branch 'grafana/master' into annotations-created
* grafana/master: (30 commits)
  changelog: adds note about closing grafana#11278
  docs: spelling
  docs: add intro paragraph to provisioning page
  Cleanup CircleCI V2 Conversion
  changelog: notes for grafana#1271 and grafana#2740
  graph: minor fixes to y-axes alignment feature
  added save icon to save buttons
  removed trash can icon from save buttons
  Return actual user ID in UserProfileDTO
  dashboard version cleanup: more tests and refactor
  minor refactor of dashboard version cleanup
  refactor: dashboard version cleanup
  limit number of rows deleted by dashboard version cleanup
  fix dashboard version cleanup on large datasets
  Allocated to a separate alignment block. Replaced the attribute of the second axis by the attribute of the axes.
  Fixed unit test.
  Changed the way this feature was activated. And changed tolltip.
  Added validation of input parameters.
  Resolved conflict
  Corrected work for graphs created before this feature.
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.