4
$\begingroup$

I'm trying to build a sortable grid:

sortBy[data_, idx_] := 
  If[idx == 0, data, Sort[data, #1[[idx]] < #2[[idx]] &]];
sortableTable[data_, header_] := DynamicModule[
  {h, sort = 0},
  h = MapIndexed[Button[#1, sort = #2] &, header];
  Dynamic[Grid[Prepend[sortBy[data, sort], h]]]];
sortableTable[
  Table[
    RandomInteger[100], {i, 3}, {j, 4}], 
    {"First", "Second", "Third", "Fourth"}]

For some reason it is not behaving like I expected: header disappears and sorting doesn't occur. I've tried all sorts of stuff but can't make it work like intended. Any help is much appreciated.

$\endgroup$
2
  • 3
    $\begingroup$ try: sort = First@#2 in the MapIndexed $\endgroup$ Sep 9, 2013 at 17:54
  • $\begingroup$ Thanks. This was the actual error. $\endgroup$
    – mikea
    Sep 9, 2013 at 20:24

4 Answers 4

7
$\begingroup$

This should work:

rows = 3;
cols = 4;
data = RandomInteger[{1, 100}, {rows, cols}];
names = {"First", "Second", "Third", "Fourth"};
sortBy[data_, idx_] := If[idx == 0, data, Sort[data, #1[[idx]] < #2[[idx]] &]];
Dynamic@Grid@Prepend[data, Array[Button[names[[#]], data = sortBy[data, #]] &, cols]]

enter image description here

$\endgroup$
5
$\begingroup$

There is no need to re-invent SortBy.

Stealing ybeltukov solution:

Dynamic@Grid@
 Prepend[data, 
         Array[Button[names[[#]],
                      data = SortBy[data, Function[x, #[[x]] &][#]]
                     ] &
               , cols]
        ]
$\endgroup$
3
  • $\begingroup$ You forgot to localize x. $\endgroup$
    – Mr.Wizard
    Sep 9, 2013 at 21:14
  • $\begingroup$ @Mr.Wizard I didn't, I was just too lazy to do this. Or frustrated by recent question where no one cared about localiziing t or letter case in sin till you posted the answer :) $\endgroup$
    – Kuba
    Sep 9, 2013 at 21:18
  • 1
    $\begingroup$ @Mr.Wizard But I should act like an adult so I've edited it :p $\endgroup$
    – Kuba
    Sep 9, 2013 at 21:32
4
$\begingroup$

Here is a possibility:

SeedRandom[1];
labels = {"First", "Second", "Third", "Fourth"};
nrows = 4;
data = RandomInteger[{1, 100}, {nrows, Length@labels}];

DynamicModule[{idx = 1},
 Dynamic@Grid[
   Prepend[SortBy[data, #[[idx]] &], 
    MapIndexed[Setter[Dynamic@idx, #2, #1] &, labels]],
   Spacings -> {0, Automatic}]
 ]

Mathematica graphics

If speed on a large dataset should happen to be an issue (unlikely, since the data are displayed), then this will be faster:

DynamicModule[{idx = 1},
 Dynamic@Grid[
   Prepend[data[[Ordering[data[[All, idx]]]]], 
    MapIndexed[Setter[Dynamic@idx, #2, #1] &, labels]],
   Spacings -> {0, Automatic}]
 ]
$\endgroup$
1
$\begingroup$

The above answers worked for me, but I thought I'd add my tweak to allow clicking twice to toggle reverse sort:

names={"matches","p1","p2","diff","factored","gap signature"};
lastSort=0;
disp:=Dynamic[Refresh[Block[{t},Grid[Prepend[tab,Array[Button[names[[#]],t=If[#==lastSort,lastSort=0;-1,lastSort=#;1];data=SortBy[data,Function[x,t #[[x]]&][#]]]&,Length[names]]]]],TrackedSymbols:>{data}]];

This gives the buttons the names provided, and disp is now a dynamic stand-in for the sortable table.

As an aside, the Refresh[expr, TrackedSymbols:>{data}] I've found seems to help Dynamic expressions not suck up so much CPU.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.