Accessing Internal Objects in Package Development.

387 views
Skip to first unread message

Nicholas Hamilton

unread,
Dec 11, 2013, 9:17:04 PM12/11/13
to ggp...@googlegroups.com
Dear ggplot2 users,

I have recently developed a package, ggtern, for the generation of ternary diagrams, which have an additional axis and variable. My (partially incomplete) website can be found at ggtern.com, and, a case-study to demonstrate the capability can be found http://ggtern.com/case-study-zirconia-alumina-silica/:

The issue that I am having is that CRAN has rejected the package, since it accesses many ggplot2:::<xyz> internal variables and functions.

Dr. Wickham suggested that I post a question here, since some people may have a similar experience, or, know a workaround.

As an example, my package creates MANY new theme elements and inheritances, it firstly accesses the .element_tree (hidden within ggplot2), adds the new structures, then pushes it back to the ggplot2 namespace during the .onLoad() function call.

Here is a list of the internals that I use within this package, most simply get 'used' or referenced, however, there are a couple that get 'patched'.

PATCHED
ggplot2:::StatDensity2d
ggplot2:::GeomSegment
ggplot2:::StatSmooth
ggplot2:::.element_tree (for the new element structures)
ggplot2:::.all_aesthetics (Since I am making new 'aesthetic' mappings)

USED
ggplot2:::Geom    (The root proto environment when patching existing geometries)
ggplot2:::Stat       (Another proto environment when patching the stat-smooth.r function)
ggplot2:::set_last_plot  (Needed to patch print.ggplot, this is used in that function)
ggplot2:::el_def    (So I can define new 'theme' elements and ineritances)
ggplot2:::check_required_aesthetics
ggplot2:::coord_transform.cartesian
ggplot2:::train_cartesian
ggplot2:::zeroGrob
ggplot2:::ggname
ggplot2:::plot_clone
ggplot2:::scales_add_missing
ggplot2:::train_layout
ggplot2:::Map_layout
ggplot2:::calculate_stats
ggplot2:::order_groups
ggplot2:::reset_scales
ggplot2:::scales_train_df
ggplot2:::scales_map_df

Patches are done via the use of the assignInNamespace function, so for example, in reference to the .element_tree, assignInNamespace(".element_tree",.element_tree,"ggplot2") would be the function called upon package loading.

Suggestions would be appreciated.

Regards,

Nicholas Hamilton







Nicholas Hamilton

unread,
Dec 19, 2013, 1:14:26 AM12/19/13
to ggp...@googlegroups.com
Last night ggtern was accepted by CRAN, if anyone is interested in the workaround for accessing internal objects, let me know.

Regards,

Nick Hamilton

BHM

unread,
Dec 20, 2013, 2:46:55 AM12/20/13
to ggp...@googlegroups.com
Hi,

Can you please share your experience / details, as to how you fixed it.


Cheers !

Nicholas Hamilton

unread,
Dec 21, 2013, 4:31:35 AM12/21/13
to ggp...@googlegroups.com
Dear BHM,

Sure, of course.

Basically, I executed the following sequence when the new packages is loaded:

-----------------------------------------------------------------
#define a list of the names of all the internals that I need.
.internals <- c(".all_aesthetics", "set_last_plot", "coord_transform.cartesian", "train_cartesian", "scales_add_missing", "ggname", "new_panel", "train_layout", "map_layout", "map_position", "new_panel", "train_position","Stat","GeomPath","add_group","scales_transform_df","reset_scales","scales_train_df","scales_map_df","order_groups","TopLevel", "compute_intercept", "combine_elements","is.rel", "facet_render", "coord_labels", "xlabel", "ylabel", "element_render", "build_guides", "is.zero", "plot_clone", "set_last_plot", "add_theme", "make_labels", "update_guides", "zeroGrob", "el_def") 
.internals <- unique(.internals) #just in case

#load from the ggplot2 namespace
ggint <- structure(
  mapply(function(.internals, i) getFromNamespace(i,"ggplot2"),.internals, .internals),
  class=c("internal")
)
-----------------------------------------------------------------

This creates a structure (ggint), containing duplicates of all internal functions/objects (as they appear in ggplot2), so, where I initially needed to call ggplot2:::<xyz> (and which was subsequently raising red-flags with CRAN), I can now call with ggint$<xyz>(...).

I ended up absolutely NOT being able to use assignInNamespace(...) in any way whatsoever, which is why I needed to bring so many of these internal functions forward, and, most of the above, were needed to successfully create a new theme_get() and theme_set() routines to address my need for new theme elements and heirarchies that were originally not defined in ggplot2.

Given the previous statement, any function that I initially wanted to patch (and made effective via assignInNamespace(...)), I needed to make a copy (including the desired patches) in the ggtern namespace, and this created a cascading effect in that any function which used the newly patched function in the ggplot2 namespace, also needed to be duplicated in the ggtern namespace, however, any time an internal object/function was used, it needed to be replaced by ggint$<xyz>, which is why the .internals list above is so lengthy.

Anyway, Hope this helps.

Regards,

Nick Hamilton.

Takuto Yamada

unread,
Jun 8, 2016, 4:05:30 PM6/8/16
to ggplot2
Nicholas, I'm also trying to do something similar.  I have a function that I want to replace in quantstrat called walk.forward.  What are the exact steps I need to perform to replace it?  I've identified the internal objects required by my replacement function, but I don't understand how to make a copy of the package.  I'm only trying to insert one line into the existing function!
Reply all
Reply to author
Forward
0 new messages