vega-lite-api icon indicating copy to clipboard operation
vega-lite-api copied to clipboard

Using different fields for ordering and labeling

Open belmarca opened this issue 4 years ago • 1 comments

Hi,

My data looks like this:

[
 {'commit': 'a', 'timestamp': 1234, 'benchmark': 'b', 'value': 1}
 ...
]

I am trying to plot ordinal values on the x axis using a temporal scale (timestamps). This

  vl.markLine()
    .encode(
      vl.x()
        .fieldT('timestamp')
        .title("Commit")
        .axis({
          labelAngle: 90,
        }),
      vl.y().fieldQ('value').scale({ zero: false }).title("Run time (s)"),
      vl.color().fieldN('benchmark').title("Benchmark"),
      vl.tooltip().fieldN('commit')
    )

puts each point in its proper place. However the axis labels are the timestamps themselves. I would like to print the commit field instead, placed at the proper timestamp (thus possibly irregularly spaced). I have tried a few things such as defining a new scale for the axis and proving a list of values, or registering a new vega.expressionFunction and calling it from a labelExpr, without success. The labelExpr is passed objects with scaled values. The information loss prevents me from easily retrieving the proper label.

I am sure this can be done in vega/vega-lite as this sounds relatively trivial. However I could not figure it out by reading the docs or the examples.

Thanks!

belmarca avatar Nov 17 '21 16:11 belmarca

I should note that this is easy to do with bar charts. The difficulty lies in placing custom text labels at the proper fieldT points in a line or scatter plot. An alternative is doing this directly in d3, but that's something I'd rather avoid for now.

By the way, I would gladly take this discussion elsewhere as it is not an issue per se, but haven't found any support forums or Gitter channel, for example.


This is how I would draw the axis in d3:

const margin = {top: 20, right: 10, bottom: 20, left: 10};
const width = chartDiv.offsetWidth - margin.left - margin.right,
      height = chartDiv.offsetHeight - margin.top - margin.bottom;
const g = d3.select("#chart").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

let xScale = d3.scaleTime()
               .domain([start, end])
               .range([0, width]);
let xAxisGenerator = d3.axisBottom(xScale)
                       .ticks(nTicks)
                       .tickValues(tickValues)
                       .tickFormat(textFromValue);
let xAxis =  g.append("g")
              .call(xAxisGenerator)
              .selectAll("text")
              .style("text-anchor", "start")
              .attr("dx", ".8em")
              .attr("dy", "-5px")
              .attr("transform", function(d) {
                return "rotate(90)"
              });

which produces the following axis:

Custom axis in d3js

belmarca avatar Nov 17 '21 19:11 belmarca