Creating a brush region programatically

7,944 views
Skip to first unread message

Bill

unread,
Feb 29, 2012, 5:14:00 PM2/29/12
to d3...@googlegroups.com
I'm using a svg brush element to do a region selection like was done in http://bl.ocks.org/1667367.  I'd like to initialize the selection so that a two week time period is selected starting from the current date (in the example, the user has to manually create the selection region).

I currently have this:

var brush = d3.svg.brush()
.x(x)
.on("brush", brush);

mini.append('g')
.call(brush)
.selectAll('rect')
.attr('y', 0)
.attr('height', height); 

function brush() { };

This all works fine just like the example.  However, I can't figure out how to initialize the brush to a particular region.  I tried manipulating the extent on the brush object, but that doesn't seem to do anything (or throws errors on extent ranges).  I then manipulated the x and width of the 'rect' on the initial append which worked at displaying the brush on load, but then it no longer actually works.  You can no longer drag the selection area, resize it,  or create new ones. 

Can anyone point out what I'm missing?  Thanks!

 
 
 
 

Mike Bostock

unread,
Feb 29, 2012, 5:28:25 PM2/29/12
to d3...@googlegroups.com
Setting the brush extent and redisplaying the brush are two distinct
operations. Typically, it looks something like this:

brush.extent([0.2, 0.8]);
svg.select(".brush").call(brush);

If the extent is in Dates, then you'd need to pass in Date objects
instead of 0.2 and 0.8. The API changes slightly if you are doing
two-dimensional brushing; see the API reference for details.

You can combine those into a single operation like so:

svg.select(".brush").call(brush.extent([0.2, 0.8]));

For more details on this pattern, see my recent post on chart components:

http://bost.ocks.org/mike/chart/

Mike

Bill

unread,
Feb 29, 2012, 6:17:41 PM2/29/12
to d3...@googlegroups.com
Thanks, that works!  Any easy way to disable the ability for users to re-size the brush element?

Mike Bostock

unread,
Feb 29, 2012, 8:30:57 PM2/29/12
to d3...@googlegroups.com
> Any easy way to disable the ability for users to re-size the brush element?

You can set pointer-events: none on the brush.

Mike

Bill

unread,
Feb 29, 2012, 9:41:51 PM2/29/12
to d3...@googlegroups.com
Yeah, that was my first instinct but that prevents dragging from working.  I ended up removing the 'resize' elements which seems to work just fine.

JuanManuel Gimeno Illa

unread,
Mar 1, 2012, 9:23:33 AM3/1/12
to d3...@googlegroups.com
I don't know your case, but you can also use a simple moving rectangle. For instance:


Hope this helps,

Juan Manuel

Dragan Bajcic

unread,
Jun 26, 2012, 11:02:40 AM6/26/12
to d3...@googlegroups.com
Hey Mike, I'm using latest d.3 from github..

My init brush function looks like this

        var _initBrush = function () {


            brush = d3.svg.brush()
                .x(xScaleBrush)
                .on("brushstart", _eventBrushStart)
                .on("brushend", _eventBrushEnd)
                .on("brush", _eventBrushDrag);



            brush.extent([0, Math.round(xRange * initialSelection)]);
            _eventBrushDrag(null);

            // http://bl.ocks.org/1667367
            var gBrush = g.append("g")
                .attr("class", "brush")
                .call(brush)
                .attr("transform", "translate(0," + (height - margin.bottom - 5) + ")")
                .selectAll("rect")
                .attr("y", 0)
                .attr("height", brushHeight);


            var res = g.selectAll("g.brush g.resize");
            res.append("path").attr("d", _resizePath);


        };


Note that i had to manually call _eventBrushDrag function because if i just set extent, it does appear right, but elements don't get selected (this happens in this callback)

Is this the way it supposed to be? Or there is the right way to set extent and call event?

Mike Bostock

unread,
Jun 26, 2012, 11:21:14 AM6/26/12
to d3...@googlegroups.com
Setting the brush extent programmatically does not trigger automatic
redraw and does not dispatch any events.

Mike

andrew payne

unread,
Mar 26, 2013, 5:52:38 PM3/26/13
to d3...@googlegroups.com
Hi Mike,
I'm trying to programmatically set a brush region at the initialization stage.  I've basically followed the comments above and set the initial x domain region (eg. 0.55-0.7) but it doesn't seem to trigger an automatic redraw (unless I move or scale the brush).  I've tried calling the brush function in lots of different ways, but can't seem to get it to automatically redraw for the initial selection.  Do you have any thoughts?  I've attached my working file.
Thanks,
Andy
index.html

Sam Selikoff

unread,
Mar 30, 2013, 5:37:24 PM3/30/13
to d3...@googlegroups.com, mbos...@cs.stanford.edu
I have been trying to get this working for a long time now, and for some reason I just can't get it. I've taken a look at the source code of the demo for Crossfilter too.

  • If I set brush.extent from within the chart() function of my object (the pattern you've outlined), calling gBrush.call(brush) on my brush selection just fills out the rectangle; it doesn't update the focus.
  • I defined an accessor function to allow my program to set the extent() from outside the object, which it does successfully; but then brush is not defined if I try to use .call(brush). How can I return the brush function as well as the chart function using your reusable chart pattern?
Either way I'm completely out of ideas. Any help would be greatly appreciated.

Kai Chang

unread,
Mar 30, 2013, 5:58:17 PM3/30/13
to d3...@googlegroups.com
For anyone capable of solving this problem, there is an open bounty with a 0.5 Bitcoin reward as incentive.


Kai


--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Jim Gwilliam

unread,
May 17, 2013, 11:20:34 PM5/17/13
to d3...@googlegroups.com
I have modified the swimlane into what has turned out to be a very functional multi-category timeline.  I've modified this one: http://bl.ocks.org/bunkat/1962173

My question is.... is there a way in d3 to control the width of the brushed region using keyboard strokes instead of (or in addition to) using the mouse to resize?

How would I go about using keyboard key presses (e.g the + key to make wider and the ' - ' key to make it narrower?

Is this possible?

Jim

John Delacour

unread,
May 18, 2013, 5:06:20 AM5/18/13
to d3...@googlegroups.com
On 17/5/13 at 04:20, jimgw...@gmail.com (Jim Gwilliam) wrote:

>My question is.... is there a way in d3 to control the width of
>the brushed region using keyboard strokes instead of (or in
>addition to) using the mouse to resize?
>
>How would I go about using keyboard key presses (e.g the + key
>to make wider and the ' - ' key to make it narrower?

I discovered a bit of code the other day and have adapted it a
little and put it here:

<http://jsfiddle.net/eremita/Dp9a2/>

How to convert the remaining raw JavaScript to d3 I don't know
but I am sure someone else will.

JD


Chris Viau

unread,
May 18, 2013, 1:19:48 PM5/18/13
to d3...@googlegroups.com
Here is one way to write it in a more D3 way http://jsfiddle.net/christopheviau/aPVxP/
Chris




JD


--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+unsubscribe@googlegroups.com.

Ian Johnson

unread,
May 20, 2013, 10:41:26 AM5/20/13
to d3...@googlegroups.com
i took a crack at it too :)

also, I recommend putting pointer-events: none on the elements in your brush area so they don't interfere with the mouse


To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Ian Johnson - 周彦

Madhavi Tendulkar

unread,
May 28, 2013, 2:18:52 AM5/28/13
to d3...@googlegroups.com
Is there any way to add multiple brushes?

Ted Strauss

unread,
May 31, 2013, 3:03:57 PM5/31/13
to d3...@googlegroups.com, kai.s...@gmail.com
Kai,
There was a commit yesterday in the 3.2 branch that appears to address the issue
If you get a chance to test it, please report back whether programmatic brush setting and initializing works.
-ted

Kristofer Gryte

unread,
Jun 30, 2013, 12:39:15 AM6/30/13
to d3...@googlegroups.com
For auto-redraw such that the focus of a 1D brush matches the graphed domain, you need to do as follows:

(1) Apply the brush scale to the graphed domain (i.e., the brush extent) --> store in var brushExtent; (units: pixels)
(2) Within the brush element (class='brush'), select the <rect> with class='extent'.
(3) If the brush is horizontal (i.e., for the x-axis), set the 'x' attribute to the first value in brushExtent. This moves the start position of the focus <rect> to match the graphed domain. If the brush is vertical (i.e., for the y-axis), set the 'y' attribute to the second value in brushExtent.
(4) Next, set the 'width' attribute of the extent to brushExtent[1] - brushExtent[0]. The end of the brush focus is brushExtent[1], but the length of the focus is this minus the offset introduced by brushExtent[0]. (If a y-axis brush, switch [0] and [1]).

(*) The extent should now programmatically match the graphed domain.

I use this procedure as part of a resize function. Hope this works. 

-KG

Brian Hernandez

unread,
Jun 18, 2014, 3:07:12 PM6/18/14
to d3...@googlegroups.com, mbos...@cs.stanford.edu
You're awesome and what you are doing is helping to enlighten the world! Thanks for all you've done!


On Wednesday, February 29, 2012 5:28:25 PM UTC-5, Mike Bostock wrote:

Kenton Russell

unread,
Sep 10, 2014, 5:09:59 PM9/10/14
to d3...@googlegroups.com, mbos...@cs.stanford.edu
I know this discussion was a long time ago, but I thought I would complete the loop with this example http://bl.ocks.org/timelyportfolio/5c136de85de1c2abb6fc
Reply all
Reply to author
Forward
0 new messages