r4fun / hierplane

🌳 Hierplane for R
https://r4fun.github.io/hierplane/
Other
9 stars 0 forks source link

A single hierplane function? #21

Closed tylerlittlefield closed 4 years ago

tylerlittlefield commented 4 years ago

Do we prefer the current version:

library(hierplane)

df <- as.data.frame(tibble::tribble(
  ~parent_id,  ~child_id,    ~child,      ~node_type,     ~link,      ~height,  ~age,
  "Bob",       "Bob",        "Bob",       "gen1",         "ROOT",     "100 cm", "60 yo",
  "Bob",       "Angelica",   "Angelica",  "gen2",         "daughter", "100 cm", "30 yo",
  "Bob",       "Eliza",      "Eliza",     "gen2",         "daughter", "90 cm",  "25 yo",
  "Bob",       "Peggy",      "Peggy",     "gen2",         "daughter", "50 cm",  "10 yo",
  "Angelica",  "John",       "John",      "gen3",         "son",      "10 cm",  "0.5 yo"
))

hierplane(df, settings = hierplane_settings(attributes = c("height", "age")))
hierplane_spacy(txt = "Sam likes boats")

Or maybe something like:

hierplane(df, settings = hierplane_settings(attributes = c("height", "age")))
hierplane("Sam likes boats")
tylerlittlefield commented 4 years ago

I've added an experimental branch for this here in explore-s3, which basically lets you do this:

devtools::load_all()

df <- structure(
  list(
    parent_id = c("Bob", "Bob", "Bob", "Bob", "Angelica"),
    child_id = c("Bob", "Angelica", "Eliza", "Peggy", "John"),
    child = c("Bob", "Angelica", "Eliza", "Peggy", "John"),
    node_type = c("gen1", "gen2", "gen2", "gen2", "gen3"),
    link = c("ROOT", "daughter", "daughter", "daughter", "son"),
    height = c("100 cm", "100 cm", "90 cm", "50 cm", "10 cm"),
    age = c("60 yo", "30 yo", "25 yo", "10 yo", "0.5 yo")
  ),
  row.names = c(NA, -5L),
  class = "data.frame"
)

hierplane(df, "Family Tree", hierplane_settings(attributes = c("height", "age")))
hierplane("Sam likes boats")

This would mean that the .data param would basically be described as:

Accepts either a string or a data.frame with hierarchical features.

mathidachuk commented 4 years ago

This should work but I think the documentation will need to be very clear that if a string is passed, spacy will be used. I am leaning slightly towards hierplane_spacy() in case we want to allow additional models/methods to interpret a string. Perhaps hierplane() can take another param for preprocessing method (tho for now it's just spacy lol).

Just trying to think of ways to avoid future rework :D

tylerlittlefield commented 4 years ago

Ah, good point about character objects having the potential to be interpreted differently, e.g. if we wanted to do something other than use spacyr when given a string. Still, I don't know how I feel about adding a function every time we find a new "thing" that hierplane can use. I like that we have a single function + render/output for shiny.

What if we created object functions, like hp_<special>:

So the syntax would be something like:

hierplane(
  .data = hp_dataframe(df), 
  title = "Family Tree", 
  settings = hierplane_settings(attributes = c("height", "age")) # still conflicted about this function name haha
)

hierplane(
  .data = hp_spacyr("Sam likes boats")
)

Then the documentation would say that hierplane only accepts a hierplane object, see the hp_ family. These hp_ functions would just take data and serve as "gatekeepers" for providing usable/hierplane ready data.

mathidachuk commented 4 years ago

Do you like use_spacyr("Sam likes boats")? We can do what caret/tidymodels do and have a script for handlers for each special input (like what we have for spacy now).

tylerlittlefield commented 4 years ago

Are you saying something like this?

hierplane(.data = use_spacyr("Sam likes boats"))
mathidachuk commented 4 years ago

ye

tylerlittlefield commented 4 years ago

And then use_dataframe()?

mathidachuk commented 4 years ago

what does use_dataframe() do again?? use_spacyr() should get the data ready in the format that can be used in build_tree

tylerlittlefield commented 4 years ago

I actually prefer the hp_ prefix so we can explain these functions as functions that create hierplane objects.

In this example, hp_dataframe() would require a dataframe, title, and settings. It would do all kinds of manipulations/checks to make sure this dataframe can be used in hierplane. Then we would remove title/settings from the hierplane function (which I admittedly added in the s3 branch).

In one hypothetical API we have:

In another hypothetical API we have:

In the first API, the workflow is:

  1. Create a hierplane object
  2. Render the widget

In the second API, the workflow is:

  1. Determine the hierplane function you need
  2. Render the widget
mathidachuk commented 4 years ago

What does a hierplane object look like? A list containing tree and theme (what's in hierplane right now)?

tylerlittlefield commented 4 years ago

A hierplane object would always output the necessary json. On master, hierplane always ends up calling build_tree(.data, title, settings), which returns json. So no change there, the only difference between both possible APIs, is:

  1. Use hierplane_ functions to handle different types of hierplanes
  2. Use hp_ functions to handle different types of hierplanes

In point 1, the hierplane_ functions are doing two things, creating a hierplanes and handling special types of hierplane data. In point 2, hierplane does one thing (generate hierplanes) and hp_ functions do one thing (create hierplane objects).

tylerlittlefield commented 4 years ago

I think we can stick with what we have now. But I will give point 2 a shot later, just so we can compare things. Since we only have two functions, translating won't be a huge undertaking.

mathidachuk commented 4 years ago

If I am interpreting what you're saying correctly, I think I'm completely aligned. What I think you're saying is that the hierplane functions will only create the JSON, and the function that creates the actual widget will be a separate function. I think this makes a lot of sense. Essentially we will be extracting the creation of the tree out of the hierplane function, correct?

tylerlittlefield commented 4 years ago

Essentially we will be extracting the creation of the tree out of the hierplane function

Yes, that's what I am thinking, except that there is only one hierplane function for rendering hierplanes.

The hierplane() function only has one job and it's to render the hierplane. The hp_ functions only have one job and it's to create hierplane ready data depending on the input, e.g. hp_spacyr is used for translating spacyr input to hierplane ready json.

mathidachuk commented 4 years ago

Ok yea I think we are on the same page!

So to render the hierplane (i.e. make a widget) it would look something like this?

hierplane(hp_dataframe(df, title, settings), theme) hierplane(hp_spacyr(txt, settings), theme)

tylerlittlefield commented 4 years ago

Exactly! I think just like you decoupled spacyr from the package, we are now trying to decouple the input to json logic from the hierplane function. Mentally this just seems cleaner or more "neat" to me in that the API would be:

  1. hierplane()/renderHierplane()/hierplaneOutput() = render hierplane!
  2. hp_ create hierplane ready data based on different input data
tylerlittlefield commented 4 years ago

Okay, now time to review the style maps :D