Giter VIP home page Giter VIP logo

Comments (6)

hadley avatar hadley commented on August 12, 2024

I think the new listener is expected because there the subset data frame needs some way to be notified if there are changes in the parent so that it can keep up to date. Maybe @lawremi has ideas?

from plumbr.

yihui avatar yihui commented on August 12, 2024

I think we need an additional argument like drop.listeners = TRUE/FALSE when subsetting a mutaframe; there has to be a way to inhibit listeners on subsets.

from plumbr.

lawremi avatar lawremi commented on August 12, 2024

Sorry, I haven't had time to look into this, with the Bioc release. Are you
saying that listeners on the original mutaframe are "copied over" to the
new subset mutaframe?

On Fri, Mar 30, 2012 at 12:40 PM, Yihui Xie <
[email protected]

wrote:

I think we need an additional argument like drop.listeners = TRUE/FALSE
when subsetting a mutaframe; there has to be a way to inhibit listeners on
subsets.


Reply to this email directly or view it on GitHub:
#5 (comment)

from plumbr.

yihui avatar yihui commented on August 12, 2024

They are not copied over. It is just that a new listener is added on the original mutaframe. See this example:

library(plumbr)

mf = mutaframe(x = rnorm(5), y = rnorm(5))
add_listener(mf, function(i, j) {
  print(plumbr:::changed(mf))
})

mf[1, 1] = rnorm(1)

mf2 = mf[1, ] # this will add a listener on mf

mf[1, 1] = rnorm(1)

and here are the results:

> mf = mutaframe(x = rnorm(5), y = rnorm(5))
> add_listener(mf, function(i, j) {
+   print(plumbr:::changed(mf))
+ })
> 
> mf[1, 1] = rnorm(1)
Signal(i = , j = ) with 1 listeners
> 
> mf2 = mf[1, ] # this will add a listener on mf
> 
> mf[1, 1] = rnorm(1)
Signal(i = , j = ) with 2 listeners

After I subset mf to create mf2, there is an additional listener on mf:

> objectSignals::listeners(plumbr:::changed(mf))
$`1`
function (i, j, ...) 
function (i, j) 
{
    print(plumbr:::changed(mf))
}(i = i, j = j)(i, j)

$`2`
function (event_i, event_j, ...) 
function (event_i, event_j) 
{
    if (shape_changed(event_i, event_j)) {
        notify_listeners(child, NULL, NULL)
    }
    else {
        new_i <- match(event_i, i)
        incl <- !is.na(new_i)
        notify_listeners(child, new_i[incl], event_j[incl])
    }
}(event_i = event_i, event_j = event_j)(i, j)

from plumbr.

lawremi avatar lawremi commented on August 12, 2024

As Hadley said, this is by design. Subsetting a mutaframe is going to
create a filter that proxies the original mutaframe. All changes to the
original are implicitly propagated to the subset (there is no copying of
the data). The plan was to have a materialize() function that would copy a
mutaframe. An important realization is that mutaframe is not simply a
data.frame with reference semantics. It is designed for building a graphics
pipeline.

There is a complication though that just occurred to me: there is no easy
way to delete the proxy, since the parent has a reference. And this is a
problem for all garbage collected environments (including Java and C#) when
it comes to signals. The listening object will never be deleted until there
are no other references to the emitting object. GTK+ and Qt do not have
this problem, as they effectively have weak references. R also has the
motion of weak references, internally, but they don't work at the R level,
since there is no way to synchronize with the GC. I guess we will see if
this becomes a performance issue. We could have proxies hold on to their
listeners, and have some function like snip() that would remove all of the
listeners.

Getting to your point, yes, I could see how the materialize() strategy is
not ideal, given the above: a proxy would always be created. We could add
such an argument (and this idea is discussed in the README), but in the big
picture, we wanted to have much of the data.frame API automatically create
such proxies. Things like transform() and aggregate() and split() come to
mind. I am not sure if we want to pepper the API with a "copy" argument.
Another idea would to have a cast like value() that would create a
"valueframe" object, that wraps the original mutaframe, but uses different
semantics. So you could do value(mf)[1,].

This would not be too different though than just doing an as.data.frame()
on it, save the initial copy. My guess is that this is what you really want
to do, at least for now. If it turns out to be super common for people to
want to extract with '[' and make a copy at the same time, we could have an
"as.data.frame" argument to '[', but that would be an optimization.

Michael

On Fri, Mar 30, 2012 at 10:32 PM, Yihui Xie <
[email protected]

wrote:

They are not copied over. It is just that a new listener is added on the
original mutaframe. See this example:

library(plumbr)

mf = mutaframe(x = rnorm(5), y = rnorm(5))
add_listener(mf, function(i, j) {
 print(plumbr:::changed(mf))
})

mf[1, 1] = rnorm(1)

mf2 = mf[1, ] # this will add a listener on mf

mf[1, 1] = rnorm(1)

and here are the results:

> mf = mutaframe(x = rnorm(5), y = rnorm(5))
> add_listener(mf, function(i, j) {
+   print(plumbr:::changed(mf))
+ })
>
> mf[1, 1] = rnorm(1)
Signal(i = , j = ) with 1 listeners
>
> mf2 = mf[1, ] # this will add a listener on mf
>
> mf[1, 1] = rnorm(1)
Signal(i = , j = ) with 2 listeners

After I subset mf to create mf2, there is an additional listener on
mf:

> objectSignals::listeners(plumbr:::changed(mf))
$`1`
function (i, j, ...)
function (i, j)
{
   print(plumbr:::changed(mf))
}(i = i, j = j)(i, j)

$`2`
function (event_i, event_j, ...)
function (event_i, event_j)
{
   if (shape_changed(event_i, event_j)) {
       notify_listeners(child, NULL, NULL)
   }
   else {
       new_i <- match(event_i, i)
       incl <- !is.na(new_i)
       notify_listeners(child, new_i[incl], event_j[incl])
   }
}(event_i = event_i, event_j = event_j)(i, j)

Reply to this email directly or view it on GitHub:
#5 (comment)

from plumbr.

yihui avatar yihui commented on August 12, 2024

Thanks for the detailed discussion. For now I think I will simply use the as.data.frame() approach.

from plumbr.

Related Issues (5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.