2012-01-16 8 views
5

Per aggiungere un divisore tra le righe in una griglia, un modo che so come farlo è utilizzando l'opzione Dividers. Ma questo è usato alla fine, e si deve quindi conoscere il numero di riga a cui un divisore deve essere al di sotto di esso. Quindi, per la grande griglia, mi trovo a utilizzare tentativi ed errori fino a trovare il numero di riga corretto. Poi, quando cambio la griglia in un secondo momento, devo fare di nuovo la prova e l'errore per mettere il divisore nel posto giusto nel caso si sia spostato dopo le mie modifiche.qualsiasi trucco per aggiungere un divisore all'interno di una griglia tra le righe nel punto in cui è necessario

In questo esempio, v'è una griglia di 3 righe e voglio aggiungere divisore sotto dire la seconda fila, così posso fare questo:

Grid[{ 
    {1}, 
    {2}, 
    {3} 
    }, Frame -> True, Dividers -> {All, 3 -> True}] 

altro modo, è quello di mettere False e True, in modo corretto in cui voglio un divisore, come questo

Grid[{ 
    {1}, 
    {2}, 
    {3} 
    }, Frame -> True, Dividers -> {All, {True, False, True, True}}] 

sarebbe bello se potessi fare qualcosa di simile questo (come si può fare per manipolare) (naturalmente questo seguito non funziona qui)

Grid[{ 
    {1}, 
    {2}, 
    Delimiter, 
    {3} 
    }, Frame -> True] 

o

Grid[{ 
    {1}, 
    {Item[2,Dividers->True]}, 
    {3} 
    }, Frame -> True] 

o cosa simile.

Faciliterà la manutenzione del codice.

Ho guardato usando Item e questo, ma non sono riuscito a capirlo.

Qualcuno sa di un trucco per farlo?

edit:

btw, Questo trucco se possibile, non vale solo per divisori. Ma sarebbe utile essere in grado di fare molte delle altre opzioni Grid, che ora vengono fatte a livello di griglia, anche a livello di oggetto. Ad esempio, se voglio aggiungere uno spazio extra dopo una riga, sarà più facile dirlo al ritmo che volevo. Inoltre, se volessi cambiare la dimensione dell'elemento, più facile farlo sul posto, lo stesso per Spacings, ecc. In modo che quando si sposta/copia il codice per un'intera riga o oggetto, è autonomo e lo copia con tutte le sue opzioni insieme.

Penso che ora ciò potrebbe richiedere una nuova opzione da aggiungere a Mathematica Grid per farlo funzionare correttamente ed essere coerente con il progetto di griglia generale.

Questo è tutto fino a quando non viene creato un builder GUI per Mathematica.

Trovo che trascorro più del 60% del mio tempo quando scrivo una demo per far sì che la GUI si adatti e sia corretta. Con un builder GUI, posso invece impiegare questa volta a lavorare sull'algoritmo. Quando uso Matlab GUIDE per creare GUI, mi serve meno del 5% del mio tempo per creare una GUI simile.

Vorrei che WRI facesse un builder GUI per Mathematica, penso che questa sarà l'app killer per Mathematica se me lo chiedi. Ma nessun corpo me :)

di modifica (2)

commento sulla bella soluzione Mr Wizard seguito chiese.
Principalmente volevo questa funzione per le griglie che uso per i controlli di layout per Manipulate. Ecco un semplice esempio:

Manipulate[x, 

Grid[{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    {Control[{{y, 0, "y"}, 0, 10, 1}]} 
    }, Frame -> None, Dividers -> {None, {False, True, False}} 
    ] 
] 

enter image description here

(e devo usare Grid per impostare i controlli). Non posso usare le chiamate di funzione qui. Non riesco a scrivere, utilizzando la soluzione del Mago di sotto, la seguente:

Manipulate[x, 

myGrid[{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    spec["Divider"], 
    {Control[{{y, 0, "y"}, 0, 10, 1}]} 
    }, Frame -> None 
    ], 

Initialization :> 
    { 
    specfunc["Divider", lst_] := Dividers -> {None, # -> True & /@ lst}; 

    myGrid[dat_, opts : OptionsPattern[]] := 
    Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
     Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ 
     dat, _, specfunc] 
    ] 

    } 
] 

questo produce un errore, dal momento che Mathematica cerca di leggere prima il corpo di manipolare per analizzarlo, prima di leggere e l'elaborazione della sezione di inizializzazione.

Ma fuori manipolare, sarà naturalmente funzionerà:

myGrid[{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    spec["Divider"], 
    {Control[{{y, 0, "y"}, 0, 10, 1}]} 
    }, Frame -> None 
] 

specfunc["Divider", lst_] := Dividers -> {None, # -> True & /@ lst}; 
myGrid[dat_, opts : OptionsPattern[]] := 
Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
    Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ 
    dat, _, specfunc] 
    ] 

enter image description here

ho bisogno di passare più tempo su questo, per vedere se riesco a farlo funzionare all'interno manipolare.

btw, ottenere cose come questa per funzionare in Manipulate è davvero difficile. L'unica cosa che so è usare macro con il pattern With[{},.... Grid....] che ho imparato da Leonid.

Ad esempio di tali difficoltà, vedere questo mia domanda

How to define constants for use with With[] in one place and then apply them later?

modifica (3) mio essere io a fare qualcosa di sbagliato, ma io sono sempre alcuni errori all'interno Manipolare:

primo esempio:

Manipulate[x, 

[email protected][{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]} 
    } 
    ], 

Initialization :> 
    { 
    grid[tab_, opts___] := 
    Module[{divlocal, divglobal, div, pos}, 
     divglobal = (Dividers /. opts) /. Dividers -> {False, False}; 
     If[Depth[divglobal] == 1, divglobal = {divglobal, divglobal}]; 
     If[Length[divglobal] == 1, AppendTo[divglobal, False]]; 
     pos = Position[tab, Dividers -> _, 1]; 
     divlocal = 
     MapIndexed[# - #2[[1]] + 1 -> Dividers /. tab[[#]] &, 
     Flatten[pos]]; 
     divglobal[[2]] = {divglobal[[2]], divlocal}; 
     Grid[Delete[tab, pos], Dividers -> divglobal, opts]]; 


    } 
] 

dà erro R:

ReplaceAll::rmix: Elements of {False,{}} are a mixture of lists and nonlists. >> 

stesso se si sostituisce la precedente con

[email protected][{ 
    Dividers -> {Thick, Blue}, 
    {Control[{{x, 0, "x"}, 0, 10, 1}]} 
    } 
    ], 

provato [email protected] al posto di [email protected] senza fortuna. può essere piccola correzione è tutto ciò che è necessario? o non sto usando giusto?

+0

ciao Mike. Sì, so dove voglio aggiungere il divisore, ma in una griglia lunga e complicata, è più facile aggiungere uno snippet di codice nel punto in cui desidero aggiungere il divisore, piuttosto che inserire il codice nella parte inferiore e dover contare e fare errori. Quindi ripetere, quando la griglia cambia. Questo è il mio punto. Grazie – Nasser

+0

L'intero problema di un costruttore di GUI contro la codifica manuale dell'interfaccia utente è qualcosa di ben discusso in molti punti della rete. Mi piacerebbe parlarne di più, ma non credo che questo sia il posto giusto per farlo. Forse quando avremo il nostro forum Mathematica possiamo parlarne di più. Ma dalla mia esperienza, l'utilizzo di un generatore GUI consente di risparmiare un sacco di tempo del programmatore sulla codifica manuale. l'analisi costi/tempo favorisce l'utilizzo del builder della GUI. Il tempo risparmiato può essere utilizzato per altre cose molto importanti. btw, sto parlando di interfacce utente di grandi dimensioni, non di uno semplice o 2 cursori e un'interfaccia utente di tipo Button e one plot. – Nasser

+1

Per far funzionare il 'Manipulate' in edit (2) è possibile sostituire il controllo con' Dynamic @ myGrid [...] '. – Heike

risposta

4

Questa soluzione dovrebbe consentire di combinare le specifiche per i divisori tra le righe specificate nella tabella con quelli specificati utilizzando il Opzione Dividers.

grid[tab_, opts___] := 
Module[{divlocal, divglobal, div, pos}, 

    (* extract option value of Dividers from opts to divglobal *) 
    (* default value is {False, False} *) 
    divglobal = (Dividers /. {opts}) /. Dividers -> {False, False}; 

    (* transform divglobal so that it is in the form {colspecs, rowspecs} *) 
    If[Head[divglobal] =!= List, divglobal = {divglobal, divglobal}]; 
    If[Length[divglobal] == 1, AppendTo[divglobal, False]]; 

    (* Extract positions of dividers between rows from tab *) 
    pos = Position[tab, Dividers -> _, 1]; 

    (* Build list of rules for divider specifications between rows *) 
    divlocal = MapIndexed[# - #2[[1]] + 1 -> Dividers /. tab[[#]] &, Flatten[pos]]; 

    (* Final settings for dividers are {colspecs, {rowspecs, divlocal}} *) 
    divglobal[[2]] = {divglobal[[2]], divlocal}; 
    Grid[Delete[tab, pos], Dividers -> divglobal, opts]] 

Per specificare un divisore tra le file è necessario inserire Dividers->spec nella posizione desiderata in cui spec è o False, True, o una direttiva grafico (colore, spessore, etc.). Per esempio

tab = {{1, 2, 3}, Dividers -> {Thick, Blue}, {4, 5, 6}, {7, 8, 9}, 
    Dividers -> False, {10, 11, 12}}; 

grid[tab, Dividers -> All] 

Mathematica graphics

Modifica

ho aggiunto alcuni commenti al mio codice su richiesta di Mr. Wizard.

+0

+1, comunque gradirei qualche spiegazione per ogni riga di codice –

+0

Inoltre, penso che sia necessario '/. {Opts}' –

+0

Heike, grazie. Ma sto ottenendo un po ' Ho provato Dynamic @ e Evaluate @ ma ho riscontrato alcuni errori.Verrà mostrato degli esempi che ho provato nel mio edit (3). – Nasser

2

Propongo di utilizzare una nuova testina in grado di contenere istruzioni (spec di seguito) e una nuova funzione che elabora queste istruzioni (di seguito) come richiesto singolarmente. Il vantaggio è che questo è facilmente generalizzabile per le diverse istruzioni intercalate e ciascuna può essere elaborata in modo arbitrario.

specfunc["Divider", lst_] := Dividers -> {All, # -> True & /@ lst} 

myGrid[dat_, opts:OptionsPattern[]] := 
Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
    Reap[ 
    If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ dat, 
    _, 
    specfunc 
    ] 
] 

Usage:

dat = 
{ 
    {1, 2, 3}, 
    {4, 5, 6}, 
    spec["Divider"], 
    {7, 8, 9}, 
    spec["Divider"], 
    {"a", "b", "c"} 
}; 

myGrid[dat, Frame -> True] 

Mathematica graphics


Se ogni istruzione può essere una singola stringa come "Divider" e si dispone di alcun conflitto con loro in questo modo, si potrebbe eliminare spec e utilizzare MatchQ[#, _String] e Sow[x, #].


Affrontare la tua domanda aggiornato, come ho osservato in un commento qui sotto credo che ha più senso usare gli elementi più fondamentali nel vostro oggetto finale Manipulate, e scrivere gli strumenti per aiutare a generare questo oggetto più facilmente. Credo che il tentativo di rendere questo tipo di personalizzazione all'interno del blocco Manipulate sia destinato a fallire, e probabilmente in modi strani e opachi.

Tuttavia, per questo caso particolare questo sembra funzionare, anche se ne dubito è robusto:

Manipulate[x, 
Evaluate[ 
    {specfunc["Divider", lst_] := Dividers -> {All, # -> True & /@ lst}; 
    myGrid[dat_, opts : OptionsPattern[]] := 
    Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
     Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ 
     dat, _, specfunc]]}; 
    myGrid[{{Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    spec["Divider"], {Control[{{y, 0, "y"}, 0, 10, 1}]}}, 
    Frame -> True] 
    ] 
] 
+0

Grazie, questo è veramente pulito, e potrei usarlo. Ma l'uso principale che ho per questa funzionalità è nella creazione di controlli per Manipolazione. E non ero in grado di usarlo come è in quel contesto. Ho bisogno di passare più tempo per vedere se riesco ad adattarlo per quello. Aggiungo edit (2) ora per spiegare meglio cosa intendo. Il problema è che in Manipulate control area, l'ambiente è un po 'più restrittivo e qualcosa che funziona fuori, non funziona facilmente lì. – Nasser

+1

@Nasser Mi dispiace, non costruisco demo, e non so come fare tutto all'interno di un 'Manipola' nel modo in cui stai provando. Posso solo suggerire meta-programmazione, cioè scrivere strumenti facili da usare che generano l'oggetto contorto 'Manipulate' che è sicuramente richiesto. Nel tuo caso 'Grid' funziona, quindi lo userei; crea invece uno strumento per scrivere più facilmente l'oggetto 'Grid'. Questo aiuta affatto? –

+0

MrWizard, Heike ha appena indicato una soluzione semplice. Ho solo bisogno di aggiungere Dynamics a tutto il resto. Avrei dovuto provarlo anch'io, e mi sono semplicemente dimenticato di farlo. Grazie per una soluzione molto bella. – Nasser

Problemi correlati