1

I've created a scatterplot using dc.js. On plotly there is a function that allows you to select a dot from scatterplot. I want to be able to select a dot from scatter, highlight it somehow and display all data available about it on a different column.

I tried to use an event listener, 'renderlet'. I can display the coordinates of the dot in the console, but nothing more.

            charts[i].on('renderlet', function(chart, filter) {
            chart.selectAll('path.symbol').style('cursor', 'pointer').on('click', function(d) {
                var points = [d.key[0], d.key[1]];
                chart.selectAll('path.symbol')
                      .data(points)
                      .enter().attr("fill", "black")
                console.log(points)
                  }) 
                // chart.select('display-qux').text("how is it");
          });

For now all I can get is this:

https://i.ibb.co/nLzp9Th/what-i-have.png

And when I click on the point the coordinates are displayed in the console.

icoert
  • 73
  • 1
  • 6

1 Answers1

1

dc.js doesn't have anything built-in to display properties, so you'll need to create a div somewhere and populate it with the data you receive on click.

As for coloring the clicked dot, dc.js doesn't have click-selection of dots in a scatterplot, and you wouldn't want it to filter on the one dot.

So you're on the right track implementing it yourself; you just need to change the color of that dot.

indicating selection using color

Since you're in a click handler for the dot, you have the element in this, and the simplest way is

d3.select(this).attr("fill", "black")

The problem is that the chart doesn't know what you did, and when it redraws it will change the color back. So the better way is to keep track of the selection e.g. a global variable, and then check it in the colorAccessor and return a different color for the selected dot:

var _selection = null;

    .colorAccessor(function(d) {
        if(_selection) {
            if(d.key[0] === _selection[0] && d.key[1] === _selection[1])
                return 5; // or a value that makes sense with your color scale
        }
        return chart._groupName; // or whatever color logic you use
    })

chart.on('renderlet', function(chart) {
    chart.selectAll('path.symbol').style('cursor', 'pointer').on('click', function(d) {
        _selection = d.key;
        chart.redraw();
    })
})

indicating selection using size

Unfortunately the dc.js scatter plot does not currently support a size accessor. It sure would be useful!

I tried fiddling with the transform, but I couldn't get that to work because that's also one of the parameters that the scatter plot already controls.

One encoding that is still free is the stroke outline of the dots. By default it's set to stroke: none in dc.css but I got some decent results by overriding it with .style().

With a stroke-width of 8:

stroke width 8

stroke-width 25 (what does this even mean):

stroke width 25

chart.on('pretransition', function(chart) {
    chart.selectAll('path.symbol').style('cursor', 'pointer')
        .style('stroke-width',
              d => (_selection && d.key[0] === _selection[0] && d.key[1] === _selection[1]) ?
              25 : null)
        .style('stroke',
              d => (_selection && d.key[0] === _selection[0] && d.key[1] === _selection[1]) ?
              'green' : null)
        .on('click', function(d) {
            _selection = d.key;
            chart.redraw();
        })
})

Example fiddle.

hint (but no code, sorry) for implementing in canvas mode

If you're using the new(ish) Canvas support in the scatter plot, there is no DOM for the symbols, so two things won't work here:

  1. no symbol objects to receive click events.
  2. no symbol objects to set stroke or stroke-width on.

Sorry this is just an outline but using dc.js I think you'd have to

  1. listen for clicks on chart.svg() (the chart <svg> element)
  2. use the chart scales to convert click coords to data coords
  3. use a quadtree to detect if a symbol was hit. or maybe even voronoi/delaunay for approximate hits
  4. add an SVG overlay and draw a selection marker there

The first three steps will be the same as the example you linked. The fourth step is because there is currently no good way to change the way symbols are drawn, and you can't modify canvas after it's drawn without redrawing the whole thing.

Please try this out and ask another question if you run into trouble. I'm happy to give it a shot but I think this question and answer are played out.

Gordon
  • 19,811
  • 4
  • 36
  • 74
  • Considering that I want a gradient applied on my scatter dots, like we discuss [here](https://stackoverflow.com/questions/57808160/how-can-i-color-my-scatter-using-a-vector-with-values/57822859#57822859) I think it will be nice to only manipulate the size, something like this. I've seen a discussion about this, but I don't know how to make it possible. `.symbolSizeAccessor(function(d) { if(points) { if(d.key[0] === points[0] && d.key[1] === points[1]) return 12;} return 8; })` https://ibb.co/Lz9h3Gp – icoert Sep 07 '19 at 09:31
  • 1
    I added a section on getting an effect sort of like sizing using the stroke & stroke width. – Gordon Sep 07 '19 at 12:36
  • Yep, I think for now this might be the best option. Thank you! https://i.ibb.co/3hbgKyV/image.png – icoert Sep 08 '19 at 10:04
  • Any ideas about how I can make it possible for canvas scatterplot? – icoert Sep 17 '19 at 09:29
  • Whoops. There is no DOM for the symbols, so two things won't work here: 1. no symbol objects to receive `click` events. 2. no symbol objects to set `stroke` or `stroke-width` on. – Gordon Sep 17 '19 at 13:56
  • Yes, I've noticed. There is a way for that using d3, [here](https://bl.ocks.org/starcalibre/5dc0319ed4f92c4fd9f9) – icoert Sep 17 '19 at 14:08
  • 1
    Sorry, if I had put 2+2 together, I would have directed you to [how to connect external charts to dc.js](https://stackoverflow.com/questions/25336528/dc-js-listening-for-chart-group-render) instead of the Canvas PR, and you could use that D3 example or [Chart.js](https://www.chartjs.org/) or whatever has the functionality you want. Nonetheless, I've added above an outline of what you'd need to do to get this functionality in dc.js and I'd be glad to help you if you first try it out and then ask another question if you get stuck. – Gordon Sep 17 '19 at 14:24