Chaining methods together (pipe)

One useful thing about BedTool methods is that they often return a new BedTool. In practice, this means that we can chain together multiple method calls all in one line, similar to piping on the command line.

For example, this intersect and merge can be combined into one command:

>>> # These two lines...
>>> x1 = a.intersect(b, u=True)
>>> x2 = x1.merge()

>>> # ...can be combined into one line:
>>> x3 = a.intersect(b, u=True).merge()

>>> x2 == x3

A rule of thumb is that all methods that wrap BEDTools programs return BedTool objects, so you can chain these together. Many pybedtools-unique methods return BedTool objects too, just check the docs (according to Principle 7: Check the help). For example, as we saw in one of the examples above, the BedTool.saveas() method returns a BedTool object. That means we can sprinkle those commands within the example above to save the intermediate steps as meaningful filenames for later use. For example:

>>> x4 = a.intersect(b, u=True).saveas('a-with-b.bed').merge().saveas('a-with-b-merged.bed')

Now we have new files in the current directory called a-with-b.bed and a-with-b-merged.bed. Since BedTool.saveas() returns a BedTool object, x4 points to the a-with-b-merged.bed file.

Sometimes it can be cleaner to separate consecutive calls on each line:

>>> x4 = a\
... .intersect(b, u=True)\
... .saveas('a-with-b.bed')\
... .merge()\
... .saveas('a-with-b-merged.bed')

Operator overloading

There’s an even easier way to chain together commands.

I found myself doing intersections so much that I thought it would be useful to overload the + and - operators to do intersections. To illustrate, these two example commands do the same thing:

>>> x5 = a.intersect(b, u=True)
>>> x6 = a + b

>>> x5 == x6

Just as the + operator assumes intersectBed with the -u arg, the - operator assumes intersectBed with the -v arg:

>>> x7 = a.intersect(b, v=True)
>>> x8 = a - b

>>> x7 == x8

If you want to operating on the resulting BedTool that is returned by an addition or subtraction, you’ll need to wrap the operation in parentheses. This is another way to do the chaining together of the intersection and merge example from above:

>>> x9 = (a + b).merge()

And to double-check that all these methods return the same thing:

>>> x2 == x3 == x4 == x9

You can learn more about chaining in Principle 6: Chaining together commands.