<p>In such cases it is best to check the <code>str</code> of an object <em>gr</em>. Then we could see that meta data is just a <em>dataframe</em> inside <em>S4</em> object:</p>

<pre><code>gr@elementMetadata
# DataFrame with 10 rows and 2 columns
#        score        GC
#    &lt;integer&gt; &lt;numeric&gt;
# 1          1 1.0000000
# 2          2 0.8888889
# ...
</code></pre>

<p>Once we know how to access the <em>dataframe</em>, we can then subset the same way as we would subset a <em>dataframe</em>:</p>

<pre><code>gr@elementMetadata[, "score" ]
</code></pre>

<p>I don't see the point of wrapping this into a function, but if it is needed:</p>

<pre><code>subsetter &lt;- function(gr, cname) gr@elementMetadata[, cname ]

# test the function
subsetter(gr, "score")
# [1]  1  2  3  4  5  6  7  8  9 10
</code></pre>

<hr>

<p><strong>Edit</strong></p>

<p>Alternatively, we could use <code>GenomicRanges::elementMetadata()</code> function to extract <em>dataframe</em> then subset:</p>

<pre><code>subsetter &lt;- function(gr, cname) elementMetadata(gr)[, cname ]
</code></pre>

CC BY-SA 4.0
2018-06-04T13:58:40.170Z
While possible, I’d generally avoid accessing S4 object slots: unless explicitly documented, they should be considered an *implementation detail* that may change without warning. Use the public accessors instead (in this case, `mcols`).
Konrad Rudolph
CC BY-SA 4.0
2018-06-04T14:33:08.263Z
@KonradRudolph good point, added alternative solution.
zx8754
CC BY-SA 4.0
2018-06-04T14:35:22.947Z
Ah … well for that function the documentation says not to use it. ;-)
Konrad Rudolph
CC BY-SA 4.0
2018-06-04T14:36:45.533Z
@KonradRudolph I see, should have read the manuals first. Thank you.
zx8754
CC BY-SA 4.0
2018-06-04T12:41:14.140Z
2018-06-04T14:31:42.183Z
2018-06-04T14:31:42.183Z
zx8754
<p>In addition to Devon’s answer, you can use <a href="http://adv-r.had.co.nz/Computing-on-the-language.html" rel="nofollow noreferrer">non-standard evaluation</a> to make this work with R symbol names rather than string arguments:</p>

<pre><code>subsetter = function (gr, cname) {
    cname = as.character(substitute(cname))
    mcols(gr)[[cname]]
}
</code></pre>

<p>Now using <code>subsetter(gr, score)</code> works analogously to <code>gr$score</code>, which may be desirable. But, likewise, you’ll no longer be able to use a variable:</p>

<pre><code>var = 'score'
subsetter(gr, var) # fails, same as `gr$var`
</code></pre>

CC BY-SA 4.0
2018-05-30T17:41:06.487Z
2018-05-30T17:41:06.487Z
Konrad Rudolph
<pre class="lang-r prettyprint-override"><code>subsetter = function(gr, cname) {
    return(mcols(gr)[[cname]])
}
</code></pre>

<p>You can then use things like <code>subsetter(gr, "GC")</code> and <code>subsetter(gr, "score")</code>.</p>

CC BY-SA 4.0
2018-05-30T08:07:59.397Z
2018-05-30T08:07:59.397Z
Devon Ryan
<p>Let's say I have following example GRanges:</p>

<pre><code>&gt; library(GenomicRanges)
&gt; gr = GRanges(
+     seqnames = Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)),
+     ranges = IRanges(101:110, end = 111:120, names = head(letters, 10)),
+     strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)),
+     score = 1:10,
+     GC = seq(1, 0, length=10))
&gt; gr
GRanges object with 10 ranges and 2 metadata columns:
    seqnames     ranges strand |     score                GC
       &lt;Rle&gt;  &lt;IRanges&gt;  &lt;Rle&gt; | &lt;integer&gt;         &lt;numeric&gt;
  a     chr1 [101, 111]      - |         1                 1
  b     chr2 [102, 112]      + |         2 0.888888888888889
  c     chr2 [103, 113]      + |         3 0.777777777777778
  d     chr2 [104, 114]      * |         4 0.666666666666667
  e     chr1 [105, 115]      * |         5 0.555555555555556
  f     chr1 [106, 116]      + |         6 0.444444444444444
  g     chr3 [107, 117]      + |         7 0.333333333333333
  h     chr3 [108, 118]      + |         8 0.222222222222222
  i     chr3 [109, 119]      - |         9 0.111111111111111
  j     chr3 [110, 120]      - |        10                 0
  -------
  seqinfo: 3 sequences from an unspecified genome; no seqlengths
</code></pre>

<p>It is straightforward to subset this GRanges as one would subset an R data.frame, e.g. </p>

<pre><code>&gt; gr$score
 [1]  1  2  3  4  5  6  7  8  9 10
</code></pre>

<p>However, I am writing a function where the user would pass through a string for the metadata column to subset e.g. </p>

<pre><code>subsetter = function(granges, column){
    return(granges$column)
}
</code></pre>

<p>I try to use the function as follows:</p>

<pre><code>&gt; subsetter(gr, score)
</code></pre>

<p>which outputs <code>NULL</code></p>

<p>This obvious doesn't work, as it will subset the <code>gr</code> by <code>column</code>, not <code>score</code>. </p>

<pre><code>&gt; subsetter(gr, score)
NULL
</code></pre>

<p>If this was a data.frame, I could subset as follows:</p>

<pre><code>gr[[(score)]]
</code></pre>

<p>but this gives the error </p>

<pre><code>Error in gr[[(score)]] : this S4 class is not subsettable
</code></pre>

<p>Are there any other ways to subset a GRanges besides using <code>$</code>? </p>

<r><bioconductor><genomicranges>
How to subset a GRanges via an argument passed into a function?
# How to subset a GRanges via an argument passed into a function?

(Asked by: username_0 on 2018-05-29)

Let's say I have following example GRanges:
> library(GenomicRanges)
> gr = GRanges(
+     seqnames = Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)),
+     ranges = IRanges(101:110, end = 111:120, names = head(letters, 10)),
+     strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)),
+     score = 1:10,
+     GC = seq(1, 0, length=10))
> gr
GRanges object with 10 ranges and 2 metadata columns:
    seqnames     ranges strand |     score                GC
            |          
  a     chr1 [101, 111]      - |         1                 1
  b     chr2 [102, 112]      + |         2 0.888888888888889
  c     chr2 [103, 113]      + |         3 0.777777777777778
  d     chr2 [104, 114]      * |         4 0.666666666666667
  e     chr1 [105, 115]      * |         5 0.555555555555556
  f     chr1 [106, 116]      + |         6 0.444444444444444
  g     chr3 [107, 117]      + |         7 0.333333333333333
  h     chr3 [108, 118]      + |         8 0.222222222222222
  i     chr3 [109, 119]      - |         9 0.111111111111111
  j     chr3 [110, 120]      - |        10                 0
  -------
  seqinfo: 3 sequences from an unspecified genome; no seqlengths

It is straightforward to subset this GRanges as one would subset an R data.frame, e.g. 
> gr$score
 [1]  1  2  3  4  5  6  7  8  9 10

However, I am writing a function where the user would pass through a string for the metadata column to subset e.g. 
subsetter = function(granges, column){
    return(granges$column)
}

I try to use the function as follows:
> subsetter(gr, score)

which outputs NULL
This obvious doesn't work, as it will subset the gr by column, not score. 
> subsetter(gr, score)
NULL

If this was a data.frame, I could subset as follows:
gr[[(score)]]

but this gives the error 
Error in gr[[(score)]] : this S4 class is not subsettable

Are there any other ways to subset a GRanges besides using $?

**Tags:** r, bioconductor, genomicranges

---

## 3 answers

### Answer by username_3 on 2018-05-30. Score: 6 | Accepted answer

subsetter = function(gr, cname) {
    return(mcols(gr)[[cname]])
}

You can then use things like subsetter(gr, "GC") and subsetter(gr, "score").


---

### Answer by username_1 on 2018-06-04. Score: 5

In such cases it is best to check the str of an object gr. Then we could see that meta data is just a dataframe inside S4 object:
gr@elementMetadata
# DataFrame with 10 rows and 2 columns
#        score        GC
#     
# 1          1 1.0000000
# 2          2 0.8888889
# ...

Once we know how to access the dataframe, we can then subset the same way as we would subset a dataframe:
gr@elementMetadata[, "score" ]

I don't see the point of wrapping this into a function, but if it is needed:
subsetter <- function(gr, cname) gr@elementMetadata[, cname ]

# test the function
subsetter(gr, "score")
# [1]  1  2  3  4  5  6  7  8  9 10


Edit
Alternatively, we could use GenomicRanges::elementMetadata() function to extract dataframe then subset:
subsetter <- function(gr, cname) elementMetadata(gr)[, cname ]

> **Comments:**
> **username_2**: While possible, I’d generally avoid accessing S4 object slots: unless explicitly documented, they should be considered an *implementation detail* that may change without warning. Use the public accessors instead (in this case, `mcols`).  
> **username_1**: @KonradRudolph good point, added alternative solution.  
> **username_2**: Ah … well for that function the documentation says not to use it. ;-)  
> **username_1**: @KonradRudolph I see, should have read the manuals first. Thank you.  

---

### Answer by username_2 on 2018-05-30. Score: 4

In addition to Devon’s answer, you can use non-standard evaluation to make this work with R symbol names rather than string arguments:
subsetter = function (gr, cname) {
    cname = as.character(substitute(cname))
    mcols(gr)[[cname]]
}

Now using subsetter(gr, score) works analogously to gr$score, which may be desirable. But, likewise, you’ll no longer be able to use a variable:
var = 'score'
subsetter(gr, var) # fails, same as `gr$var`


---

