0

I've been trying to refactor my code such that instead of removing all the elements and replacing them like I have been doing, I update the container's data and positions. I've used this tutorial to understand how to handle data selections, however I'm still having trouble understanding how to update or exit data selections. I have two main questions about this:

  1. How do I correctly add attributes to where I update the data?

  2. When I update the data, how do I choose to append the data to the rectangles?

All of the following code is within a click function of a different element. Below is where I first create the selection which should run the first time the element is clicked.

var update = function () {

    if (firstClick == true) {

        firstClick = false;

        magBox = svgContainer.selectAll("svg")
            .data(containerViewer)
            .enter()
            .append("rect")
            .attr("width", 10)
            .attr("height", 10)
            .attr("y", -1000)
            .attr("width", ((max_x / 3.5) / selectedContainer[1].length))

            // sets height of magBox to a percentage of the total waterfall height
            .attr("height", ((max_x / 3.5) / 1.7) / arrayMagnified)

            // sets the position left from
            .attr("x", function () {
                lencount++;

                if (lencount == parseInt(containerViewer.length / arrayMagnified)) {
                    console.log(lencount);
                    lencount = 0;
                }

                if (d3.event.pageX / max_x - 0.01 >= 0.5) {
                    return -(rectSize * 2) + (lencount * ((max_x / 3.5) / selectedContainer[1].length));

                }
                else {
                    return (rectX - (magFrameWidth * 0.9)) + (lencount * ((max_x / 3.5) / selectedContainer[1].length));
                }
            })
            .attr("y", function (d, i) {

                // height of each magBox pixel
                var pixelHeight = ((max_x / 3.5) / 1.7) / arrayMagnified;

                // uses i to iterate in relation to array length
                var iterator = parseInt(i / selectedContainer[1].length);

                if (selected > (rawDataStore.length) / 2) {
                    return (-(rectSize * 2) + pixelHeight * iterator);
                }
                else {
                    return ((rectY - magFrameHeight * 0.8) + pixelHeight * iterator);
                }
            })
            .style("fill", function (d) {
                negativeColors = -1 * d;
                invertedColors = normalize_value(negativeColors, -(rmax), -(rmin), 0, 255);
                return "rgb(" + 255 + "," + (parseInt(invertedColors)) + "," + 0 + ")";
            });
    }

After the first time this runs, it should then go to the following else condition which updates the data every consecutive time this is clicked:

    else {

        magBox.data(containerViewer);

        d3.selectAll(".magContainer").moveToFront();

    }
};

update();

Currently, it works the first time but then doesn't update the data or replace the attributes. When I try entering, appending, and adding attributes to the "else" section of the code, it creates a new selection as opposed to updating the first one.

If there's any additional things I'm missing conceptually, I'd be happy to know!

AstroBoogie
  • 498
  • 5
  • 17
  • 1
    First, congratulation for abandoning the approach of removing your elements. I've written a tutorial on enter, update and exit selections in the "documentation", but unfortunately I can't link it because it's lying there unapproved. Meanwhile, try to create a fiddle or something similar with your code, so we can actually change it. With this bunch of "if", it's very difficult to help you just by seeing the code. Is that the exoplanets heat map? – Gerardo Furtado Aug 05 '16 at 01:25
  • How is selecting '.magContainer' going to recreate your selection from the first branch? And what are you trying to modify - just bring the elements to the front? Keep in mind that some d3 functions (such as `enter` and `append`) change the selection, and it's useful to keep the relevant selection around for later manipulation instead of reselecting. – Owen Aug 05 '16 at 01:31
  • Thank you! I've tried to set up a jsfiddle (never used it before) and [this is it](https://jsfiddle.net/2f0q9yd6/). Line 528 is where I'm currently working on. @Owen, .magContainer isn't the piece where I'm recreating the selection. magBox.data is where I'm attempting to update the data. I just read [this post in stack overflow](http://stackoverflow.com/questions/34178408/update-data-in-d3-js-group) which indicated that I need to input the attributes and styles again. I'll also try to fix that! – AstroBoogie Aug 05 '16 at 01:37
  • @Owen, are you sure that `append` changes the selection? – Gerardo Furtado Aug 05 '16 at 01:39
  • @GerardoFurtado It must or the method chaining wouldn't work. See [API documentation](https://github.com/d3/d3-selection/blob/master/README.md#selection_append) for confirmation: "this method returns a new selection containing the appended elements" – Owen Aug 05 '16 at 01:41
  • @AstroBoogie Fiddle not working because the external data is not available. Can you put the full URL or perhaps turn it into a JS variable within the fiddle instead of loading via d3.json? – Owen Aug 05 '16 at 01:44
  • @Owen, it returns a new selection. What I'm asking is: does it change the selection upon which it was called? – Gerardo Furtado Aug 05 '16 at 01:47
  • 1
    @GerardoFurtado Ah. It does not alter the properties of the selection, it just returns a new selection - my fault for being imprecise. – Owen Aug 05 '16 at 01:48
  • @Owen The external data are two ~2000x4000 2-dimensional arrays. Is there a place I can upload it as raw text perhaps? – AstroBoogie Aug 05 '16 at 01:49
  • Owen, no worries! Now let's focus on helping our mate... @AstroBoogie, if you have external files, you may find Plunker easier than fiddle. – Gerardo Furtado Aug 05 '16 at 01:50
  • @GerardoFurtado Alright let's see if this plunker works. I uploaded it here: http://embed.plnkr.co/8UTpfdNZL9xruYbQwU9A/ – AstroBoogie Aug 05 '16 at 02:00
  • @GerardoFurtado It seems that this also is having a hard time with this .txt file. I have a github repository with a working version. [link](https://github.com/AstroBoogie/BL-files/tree/master/BL_waterfall). – AstroBoogie Aug 05 '16 at 02:06
  • @AstroBoogie, I tried to create a plunker for you but I couldn't, you have more than 100MB of data! Are you sure that you need all of that just to create a heatmap? – Gerardo Furtado Aug 05 '16 at 04:00
  • @GerardoFurtado Hey, sorry for the late response! Yeah, all the data is accounted for in this graph. I am storing it using json within a .txt file. Is there a more efficient approach to this? I'm running it in Webstorm if that helps any. The thing in particular I'm trying to figure out is how to update the data correctly in the else condition of the original post. If I could figure that out, I think I could apply that method throughout the code. Thank you again! – AstroBoogie Aug 05 '16 at 19:10

0 Answers0