I thought l2p converted from local units (relative) to the yaxis to pixel and d2p converted from domain units, but its not working. Can you elaborate? For example, consider yaxis with domain [0.2, 0.3] inside a plot with height 1000px and limits [0,100] so (counting down from top of window) yaxis has pixels from 700px to 800px. I was expecting d2p(0.25) to give 750px and l2p(50) to also give 750px, this doesnt seem to be happening.
For some background, given multiple yaxis “tracks” (different domains) I want to place cross-hairs as “anchors” on the left of top/bottom of each track. Then I can make those cross-hairs draggable, trigger relayout, etc. Very sexy. Except I am having trouble placing the cross-hairs (in pixel space) to exactly line up with the track.
Any advice other than l2p and d2p wout be fine too…
Thanks
Ah, I’ve found the source code. The difference between “d2p” and “l2p” is when the axis is logarithmic, etc. The “d” doesnt stand for “domain”.
This is a cross-plot of xt-xb vs layout[key][“domain”]… so the xy7, etx, domains are related to pixels… Not totally obvious yet how.
let subplotName = key.replace(“yaxis”, ".xy ");
let subplot = document.querySelector(subplotName);
let rect = subplot.getBoundingClientRect();
let xt = rect.top
let xb = rect.bottom
Looking better
Given, say, yaxis7 then the [xb,xt] computed by this expression puts (xt-xb) on a linear slope with the assigned domain values !
let subplotName = key.replace("yaxis", ".xy"); // eg yaxis7 because .xy7
let subplot = document.querySelector(subplotName);
let rectElement = subplot.querySelector('.nsewdrag');
let rect = rectElement.getBoundingClientRect();
let xt = rect.top
let xb = rect.top+rect.height
createInterval(key, xb , xt)
So close, but not there yet… Enough for one day.
For this example, I have perfect agreement with domain = (887-pixels)/828… so need to work out the magic numbers of 887 and 828
Couldn’t sleep
Ok. Class plotly container. plotly has the 1000px that one might expect. but draglayer
has the magic 868px that is in the above equation;
Ok, I’ve got it!! x = 1 on domain corresponds to the point y = top_margin and you can get the scaling parameter by looking at the class draglayer. If you run the following then you get an exact match between the domain definition and the values in the domains “xy”, “xy1”, etc. Note that you can not use “subplot xy”, etc for this calculation because the rect for the subplot is not clipped, whereas the drag layers are clipped.
let graphInfo = PLOTTER._fullLayout;
let dragPlot = document.querySelector(".draglayer");
let dragRect = dragPlot.getBoundingClientRect();
console.log("Bounding Box", dragRect)
let scale = dragRect.height
if ("margin" in layout) {
scale = scale -layout["margin"]["t"] - layout["margin"]["b"]
}
// Loop through all y-axes in the layout
Object.keys(layout).forEach(function (key) {
if (key.startsWith('yaxis') && layout[key].hasOwnProperty('domain')) {
if (graphInfo[key] !== undefined) {
try {
let subplotName = key.replace("yaxis", ".xy"); // eg yaxis7 because .xy7
let subplot = document.querySelector(subplotName); //assumes unique, otherwise finds the first such
let rectElement = subplot.querySelector('.nsewdrag');
let rect = rectElement.getBoundingClientRect();
console.log(key,rect)
yaxesWithDomain.push({ key: key, planned: layout[key], actual: graphInfo[key] });
let xt = rect.top - dragRect.y
let xb = (rect.top+rect.height ) - dragRect.y
createInterval(key, xb , xt)
console.log(scale*(layout[key]["domain"][1] - layout[key]["domain"][0]), rect.height)
}
catch(e) {;}
}
}
});