UPDATE: SOLVED
Most of you probably don't remember me from my previous question, Circles not updating correctly for multiline charts with two-level nested data. I managed to figure out/work around my issue there (although I still am not convinced that what I came up with is 100% correct); however, I now have another question.
My y-axis data (d.mval) has extreme outlier values. As a result, my charts get compressed, with quite a bit of blank space. See, for example, the "Cash Flow" chart in this JSFiddle: https://jsfiddle.net/etonblue/a98m52k4/3/. I've tried various combinations of median, mean, average, std dev, etc., to try to set the domains, but haven't yet found a solution that works consistently for all of my data. So I've resorted to hard-coding my domains:
if (val == 1) {ydom = [-2,20]}
else if (val == 2) {ydom = [-40,240]}
else if (val == 3) {ydom = [-.5,1.5]}
else if (val == 4) {ydom = [-.6,.9]}
else if (val == 5) {ydom = [-.6,.6]}
else if (val == 6) {ydom = [-.16,.16]}
else if (val == 7) {ydom = [-.5,3]}
else if (val == 8) {ydom = [-1000000,2000000]}
else if (val == 9) {ydom = [-1000000,2000000]}
else if (val == 10) {ydom = [-4,10]}
which is not only ugly, it also means that any extreme values are now either far above or far below my displayed y-axis.
My question, is there a way to use D3 to cap a displayed value at the max/min of a domain while retaining the actual value (so that a tooltip shows the actual value rather than the displayed value)?
I'm currently using d3.v4.
UPDATE The solution:
var line = d3.line()
.x(d => x(d.year))
.y(d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
and
.attr("cx", d => x(d.year))
.attr("cy", d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))
Updated fiddle here: https://jsfiddle.net/etonblue/6v924ory/2/.
The above code caps the y-axis value (in this case: d.mval) at the minimum (y.domain()[0]) or maximum (y.domain()[1]) values of the domain itself while not changing the "actual" value of d.mval (so it can be used in a tooltip).
Now I just need to figure out why my update function isn't working properly (e.g., If you click the "Annual Enrollment Change %" function, you can see two green lines (without dots) at the bottom of the chart that are clearly left over from the "Current Ratio" chart). However, this probably warrants a separate question.
Ugh. It's always something.
Thank you for the answer, I'm not sure I ever would have figured this out myself.
CodePudding user response:
The code you provided isn't too relevant to the solution. Working from your fiddle, the solution is in your callbacks for the y positions of your line and circles. For your line:
var line = d3.line()
.x(d => x(d.year))
.y(d => d.mval > 240 ? y(240) : y(d.mval)) //If mval is over 240 plot 240
Likewise for your circles cy:
.attr('cy', d => d.mval > 240 ? y(240) : y(d.mval))
More Generally, you could use the callback:
d => d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval)
I don't quit understand your setup,