How can I create standalone scale that is aware of Observable plot’s width, margins, etc?
- I need to create a standalone scale in order to use its
scale.apply()
method. - However, the resulting scale’s
apply()
function returns values in the range [0,1], not in terms of the plot’s dimensions (width, margin, etc). - Compare to
plot.scale
, which returns values in terms of the plot’s dimensions. - I cannot use
plot.scale
because thescale.apply()
function is needed to define the marks that are part of the options when creating the plot. (Sort of a chicken-and-egg problem.) - I tried adding plot dimension options when creating a scale, but these are ignored.
- Ideally, the scale could be accessed from the callback where it is used, but this does not seem possible.
- Currently, my work-around is to create the plot twice: first to create
plot.scale
, then again to define the plot that usesplot.scale
- Interestingly, if the (Svelte) component is used multiple times, only the first component needs the work-around above. So a “throw-away” component could be hidden.
- Another work-around may be to first generate a simple plot for the scale, then use that for the “real” plot.
I have created a simple sample demonstrating the problem below:
const data = [{
text: 'Weekend',
utc: new Date('2024-06-16'), end: new Date('2024-06-17'),
},{
text: 'Weekdays',
utc: new Date('2024-06-17'), end: new Date('2024-06-22'),
}, {
text: 'Weekend',
utc: new Date('2024-06-22'), end: new Date('2024-06-23'),
}]
// Construct scale:
const scale = Plot.scale({x: {domain: [new Date('2024-06-16'), new Date('2024-06-23')]}})
// Simple plot:
const plot = Plot.plot({
height: 150,
width: 800,
marginRight: 12,
marginLeft: 12,
marks: [
Plot.rectY(data, {
x1: (d) => d.utc,
x2: (d) => d.end,
y: 1,
fill: (d) => d.text == 'Weekend' ? 'lightgray': 'beige'
}),
Plot.text(data, {
x: (d) => (Number(d.utc) + Number(d.end))/2,
text: 'text'
}),
],
});
function compareScales(value) {
console.log({
value,
' scale': scale.apply(value),
'plot.scale': plot.scale('x').apply(value)
})
}
compareScales(new Date('2024-06-16'))
compareScales(new Date('2024-06-17'))
compareScales(new Date('2024-06-23'))
const div = document.querySelector('#myplot');
div.append(plot);
#myplot {
height: 200px;
}
<!DOCTYPE html>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="https://cdn.jsdelivr.net/npm/@observablehq/[email protected]"></script>
<div id="myplot"></div>