# share 0-line between y axes #1271

Closed
opened this issue Dec 23, 2014 · 7 comments

Projects
None yet
6 participants

### themasch 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 I'd really prefer both scales to use the same origin here. Is that possible?

 👍
Member

### torkelo commented Jan 12, 2015

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

### JeremyMorton 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 } } ``````
Member

### torkelo commented Jan 15, 2015

 interesting :) PR?

### JeremyMorton 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.

Closed

Closed

 👍

Merged

Member

### marefr commented Mar 22, 2018

 Fixed by #10994

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

``` changelog: notes for #1271 and #2740 ```
`[skip ci]`
``` 63465fd ```

### 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)
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.
``` 4ed1ec5 ```