Visx: scaleTime and ticks()

Created on 16 Mar 2018  路  4Comments  路  Source: airbnb/visx

Hello,

Let's assume the following code :

const xMax = 600
const x = d => d.date

const data = Array(12).fill(1).map((d, i) => ({
  date: +new Date(Date.now() - (i * 3600000)),
  value: Math.round(Math.max(250, Math.random() * 3000)),
}))

const xScale = scaleTime({
  range: [0, xMax],
  domain: extent(data, x),
})

console.log(xScale.ticks()) // array with 11 items

The data array is filled with 12 items, but the function "ticks()" return 11 items. Why is that ?
When I use the xScale with a shape (e.g : LinePath), it works well. But when I use an Axis (that uses the ticks() function), it doesn't work as expected.

capture d ecran 2018-03-16 a 14 43 16

Most helpful comment

@DarKDinDoN another option if you don't want to define your entire Axis component is to pass an array of tickValues to <Axis* />, which is _not_ approximate and will override the those from scale.ticks().

e.g., const tickValues = data.map(d => d.date) for each data point, or const tickValues = data.filter((d, i) => i === 0 || i === data.length - 1) for just the start + end.

All 4 comments

Ok, maybe I did not read the documentation carefully enough 馃槂
Ticks are approximate.

I would like to display the ticks with at least the very first and the last one. Is it possible ?

Thanks

Hi @DarKDinDoN, here's an example of rendering custom axis ticks with <AxisBottom /> https://codesandbox.io/s/rrkq83p9x4. hope it helps!

You might also want to try adding nice: true

const xScale = scaleTime({
  range: [0, xMax],
  domain: extent(data, x),
  nice: true
})

docs: https://github.com/d3/d3-scale#continuous_nice

screen shot 2018-03-16 at 1 25 53 pm

      <AxisBottom
        top={height - margin.bottom}
        left={margin.left}
        scale={xScale}
        numTicks={numTicksForWidth(width)}
        label="time"
      >
        {props => {
          const tickLabelSize = 10;
          const tickColor = "black";
          const axisCenter = (props.axisToPoint.x - props.axisFromPoint.x) / 2;
          return (
            <g className="my-custom-bottom-axis" fontFamily="arial">
              {/* start */}
              <Line
                from={{ x: 0, y: 0 }}
                to={{ x: 0, y: 8 }}
                stroke={tickColor}
              />
              <text
                transform={`translate(${0}, 18)`}
                fontSize={tickLabelSize}
                textAnchor="start"
                fill={tickColor}
              >
                {formatTime(x(data[0]))}
              </text>

              {/* middle */}
              <Line
                from={{ x: axisCenter, y: 0 }}
                to={{ x: axisCenter, y: 8 }}
                stroke={tickColor}
              />
              <text
                transform={`translate(${axisCenter}, 18)`}
                fontSize={tickLabelSize}
                textAnchor="middle"
                fill={tickColor}
              >
                {formatTime(xScale.invert(axisCenter))}
              </text>

              {/* end */}
              <Line
                from={{ x: xMax, y: 0 }}
                to={{ x: xMax, y: 8 }}
                stroke={tickColor}
              />
              <text
                transform={`translate(${xMax}, 18)`}
                fontSize={tickLabelSize}
                textAnchor="end"
                fill={tickColor}
              >
                {formatTime(x(data[data.length - 1]))}
              </text>

              {/* axis label */}
              <text
                textAnchor="middle"
                transform={`translate(${axisCenter}, 50)`}
                fontSize="12"
              >
                {props.label}
              </text>
            </g>
          );
        }}
      </AxisBottom>

@DarKDinDoN another option if you don't want to define your entire Axis component is to pass an array of tickValues to <Axis* />, which is _not_ approximate and will override the those from scale.ticks().

e.g., const tickValues = data.map(d => d.date) for each data point, or const tickValues = data.filter((d, i) => i === 0 || i === data.length - 1) for just the start + end.

Thank you ! 馃槃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

EfosaSO picture EfosaSO  路  4Comments

stefanvermaas picture stefanvermaas  路  3Comments

danielprogramic picture danielprogramic  路  3Comments

elisechant picture elisechant  路  3Comments

m0t0r picture m0t0r  路  3Comments