Ecco un approccio sfruttando la funzione di utils::getParseData
e prestito da una funzione scritta per la parser
package e utilizzando igraph
per le immagini.La funzione collegata fa quasi ciò che volevi, ma i dati restituiti dalla funzione getParseData
hanno nodi vuoti con i valori numerici/simboli/operatori ecc. Sulle foglie. Questo ha senso se si tenta di analizzare funzioni o espressioni ternarie o cose più complicate.
Questa funzione crea semplicemente un edgelist dai dati di analisi.
## https://github.com/halpo/parser/blob/master/R/plot.parser.R
## Modified slightly to return graph instead of print/add attr
parser2graph <- function(y, ...){
y$new.id <- seq_along(y$id)
h <- graph.tree(0) + vertices(id = y$id, label= y$text)
for(i in 1:nrow(y)){
if(y[i, 'parent'])
h <- h + edge(c(y[y$id == y[i, 'parent'], 'new.id'], y[i, 'new.id']))
}
h <- set_edge_attr(h, 'color', value='black')
return(h)
}
La funzione successiva comprime l'albero di analisi rimuovendo tutti gli spazi vuoti '() {}' e rimanenti. L'idea è di spostare prima tutte le etichette su un livello nell'albero, quindi tagliare le foglie. Infine, tutti gli spazi delle espressioni nidificate ('() {}') vengono rimossi creando/distruggendo i bordi. Ho colorato i bordi blu dove sono stati rimossi i livelli di nidificazione da parentesi/parentesi graffe.
## Function to collapse the parse tree (removing() and {})
parseTree <- function(string, ignore=c('(',')','{','}'), ...) {
dat <- utils::getParseData(parse(text=string))
g <- parser2graph(dat[!(dat$text %in% ignore), ])
leaves <- V(g)[!degree(g, mode='out')] # tree leaves
preds <- sapply(leaves, neighbors, g=g, mode="in") # their predecessors
vertex_attr(g, 'label', preds) <- vertex_attr(g, 'label', leaves) # bump labels up a level
g <- g - leaves # remove the leaves
gaps <- V(g)[!nchar(vertex_attr(g, 'label'))] # gaps where()/{} were
nebs <- c(sapply(gaps, neighbors, graph=g, mode='all')) # neighbors of gaps
g <- add_edges(g, nebs, color='blue') # edges around the gaps
g <- g - V(g)[!nchar(vertex_attr(g, 'label'))] # remove leaves/gaps
plot(g, layout=layout.reingold.tilford, ...)
title(string, cex.main=2.5)
}
Un esempio, un'espressione leggermente più nidificata. L'animazione mostra come l'albero originale è collassato.
## Example string
library(igraph)
string <- "(a/{5})+(2*b+c)"
parseTree(string, # plus some graphing stuff
vertex.color="#FCFDBFFF", vertex.frame.color=NA,
vertex.label.font=2, vertex.label.cex=2.5,
vertex.label.color="darkred", vertex.size=25,
asp=.7, edge.width=3, margin=-.05)
Incredibile risposta grazie! Penso che questa sia la risposta migliore finora, quindi accetterò. – Gumeo
Si noti che se l'input non è una stringa, ma un'espressione da un sostituto, è possibile utilizzare deparse per ottenere la stringa corrispondente. – Gumeo
@bunk Risposta stupenda. Questa domanda sembra correlata? Qualsiasi aiuto: http://stackoverflow.com/q/33473107/1000343 –