Это будет замена шкалы журнала, чтобы она могла иметь дело с отрицательными числами. Я не видел много примеров пользовательских масштабов, хотя я пытался использовать источник логарифмической шкалы d3 в качестве отправной точки.
Создание шкалы asinh (обратного гиперболического синуса) в d3.js v4
Ответ 1
Насколько я знаю, нет способов сделать пользовательские шкалы в D3 (по крайней мере, не в том смысле, который вы ищете). Все шкалы D3 масштабируются в два этапа:
- с использованием домена, деинтерполируйте вход с заданной функцией деинтерполяции
- используя интервал, интерполируйте промежуточный результат с шага 1, чтобы получить выход
Я верю, что ваш идеальный ответ в основном ответит на вопрос, "как установить функцию деинтерполяции шкалы D3 в пользовательскую функцию?" , и я не думаю, что в настоящее время это возможно.
Однако вы можете установить интерполяционную функцию. Этот пример из Майка Бостока показывает, как установить интерполяцию с помощью одной из встроенных функций облегчения D3: http://bl.ocks.org/mbostock/56ea94205411ee9e4dbec3742f7ad08c
Этот пример имеет эффект "рыбий глаз", который, вероятно, является противоположностью того, что вы хотите. Вы можете использовать функцию ослабления полинома, d3.easePolyInOut
, с показателем меньше единицы, чтобы приблизиться к масштабированию журнала (см. Мой фрагмент кода). К сожалению, нет "logInOut" или "asinhInOut", поэтому, если вам нужен более крутой роллофф (чем полином), вам придется написать свою собственную функцию ослабления/интерполяции.
var data = Array.from(Array(21), (_,i)=>{return 10*(i-10)})
var svg = d3.select("svg"),
margin = {top: 50, right: 20, bottom: 5, left: 20},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var polyexp = 0.25
var x = d3.scaleLinear()
.domain([-100,100])
.range([0, width])
.interpolate(easeInterpolate(d3.easePolyInOut.exponent(polyexp)));
g.append("g")
.attr("class", "axis axis--x")
.call(d3.axisBottom(x));
g.selectAll("circle").data(data).enter().append("circle")
.attr("cx", (d) => x(d))
.attr("cy", -10)
.attr("r", 3)
.attr("fill", "steelblue")
function easeInterpolate(ease) {
return function(a, b) {
var i = d3.interpolate(a, b);
return function(t) {
return i(ease(t));
};
};
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.js"></script>
<svg width="600" height="100"></svg>
Ответ 2
Лучшим примером в документации, по-видимому, является функция интерполяции масштаба. См. https://github.com/d3/d3-scale/blob/master/README.md#continuous-scales
var color = d3.scaleLinear()
.domain([10, 100])
.range(["brown", "steelblue"])
.interpolate(d3.interpolateHcl);
Я не эксперт d3, поэтому надеюсь, что это поможет.