# Proper use of TableAlignment

At various times though use of extensive trial-and-error I have gotten results I want out of TableHeadings. More often I give up. For example, given two columns, (a) how does one make the first left-justified and the second right-justified? And (b) is there any elegant way of aligning to the decimal point?

inTable={{"one","two","three","four","five"},{1.2,3.21,.43,5.,23}};


problem (a), output like this:

one     1.2
two    3.21
three   .43
four     5.
five     23


problem (b), output like this:

one      1.2
two      3.21
three     .43
four     5.
five    23

• Have you tried anything? Grid seems like a good option: Grid[Transpose@inTable, Alignment -> {{Left, Right}}]
– Öskå
Mar 31, 2016 at 20:44
• @Öskå If I use Grid, I lose access to TableHeadings, and this approach doesn't solve the decimal alignment problem. Mar 31, 2016 at 20:46
• Yes it does: Grid[Transpose@inTable, Alignment -> {{Left, "."}}]. And you can just add the heading manually in the list.
– Öskå
Mar 31, 2016 at 20:47
• In other words, just look at Grid with the Alignment and Dividers options. Then you might need Prepend to insert headings manually.
– Öskå
Mar 31, 2016 at 21:04

I haven't revised this code for 5 years but think it should do what you need for a):

sortableTable[Transpose@inTable, Alignment -> {{Left,Right}, Center}]


and for b)

sortableTable[Transpose@inTable, Alignment -> {{Right, "."}, Center}]


Clear[sortableTable];

Options[sortableTable] =

SyntaxInformation[
sortableTable] = {"ArgumentsPattern" -> {_, OptionsPattern[]}};

sortableTable::usage = "\!$$\* StyleBox[\"sortableTable\", \"MB\"]$$[\!$$\* StyleBox[\"data\",\nFontSlant->\"Italic\"]$$] takes a list of data \
and returns a table which can be sorted by clicking on column \
headers. Styling options are the saem as for \!$$\* StyleBox[\"Grid\", \"MB\"]$$. Table headings are entered by \
specifying values for teh option TableHeadings. This option functions \
identically to the same option to \!$$\* StyleBox[\"TableForm\", \"MB\"]$$.";

sortableTable::row = "Row labels  need to be entered as a list.";
sortableTable::opts =
"TableHeadings must be a list with a maximum length 2, containing \
specifications for row and column headings.";

sortableTable[data_List, opts : OptionsPattern[]] :=
DynamicModule[{gridOptions, rows, columns, rowOptions,
columnOptions, headings, labels, tmp, i = 1,

If[Length[tableOptions] === 1,
tableOptions = {None, tableOptions[[1]]}];
If[tableOptions === {}, tableOptions = {None, None}];
If[Length[tableOptions] > 2, Message[sortableTable::opts]; Abort[]];

gridOptions = FilterRules[{opts}, Options[Grid]];

{rows, columns} = Dimensions[data];

(* get the value of the TableHeadings options *)
{rowOptions,
columnOptions} = tableOptions;

(* if the user doesn't want headers then make a blank list *)

If[columnOptions === None, headings = Table[" ", {j, columns}]];

(* if the value of the header option is not None then check to \
ensure it is a list *)

If[columnOptions =!= None && ! VectorQ[columnOptions],

(* if the value of the header option is not None,
and was entered as a list then check the list length *)

If[columnOptions =!= None && VectorQ[columnOptions],
Which[
Length[columnOptions] === columns, headings = columnOptions,
Length[columnOptions] >= columns,
Length[columnOptions] < columns,
Flatten[{columnOptions,
Table[" ", {columns - Length[columnOptions]}]}]
]
];

(* if the value of the row option is not None then check to ensure \
it is a list *)

If[rowOptions =!= None && ! VectorQ[rowOptions],
Message[sortableTable::row]; Abort[]];

(* if the value of the row option is not None,
and was entered as a list then check the list length *)

If[rowOptions =!= None && VectorQ[rowOptions],
Which[
Length[rowOptions] === rows, labels = rowOptions,
Length[rowOptions] >= rows, labels = rowOptions[[1 ;; rows]],
Length[rowOptions] < rows,
labels =
Flatten[{rowOptions, Table[" ", {rows - Length[rowOptions]}]}]
]
];

Which[
rowOptions === None && columnOptions === None,
Grid[data, gridOptions],
rowOptions === None,
(* no row labels *)
Dynamic[
tmp = SortBy[data, #[[i]] &];
Deploy@
Grid[Join[{Table[
With[{j = j},
EventHandler[
headings[[j]], {"MouseClicked" :> (i = j)}]], {j,
columns}]}, tmp], gridOptions],
TrackedSymbols :> {i}],

rowOptions =!= None && columnOptions =!= None,
(* else add row labels *)
Dynamic[
tmp =
SortBy[Transpose[Join[{labels}, Transpose[data]]], #[[i]] &];
Deploy@Grid[
Join[
{Join[{EventHandler["     ", {"MouseClicked" :> (i = 1)}]},
Table[With[{j = j},
EventHandler[
headings[[j]], {"MouseClicked" :> (i = j + 1)}]], {j,
columns}]]}, tmp],
gridOptions],
TrackedSymbols :> {i}]
]
];


Now a test showing the use of table headings:

data2 = RandomInteger[{1, 20}, {5, 4}];

(* some Grid options *)

opts = {Background -> {None, {GrayLevel[0.75], {White,
GrayLevel[0.9]}}},
BaseStyle -> Directive[FontFamily -> "Helvetica", 11],
Dividers -> {{GrayLevel[1], {GrayLevel[.9]},
GrayLevel[1]}, {GrayLevel[.2], GrayLevel[.2], {False},
GrayLevel[.2]}},
Alignment -> {{Left, {Right}}},
ItemSize -> {{6, {7}}},
ItemStyle -> {{Directive[FontFamily -> "Helvetica", Bold,
12]}, {Directive[FontFamily -> "Helvetica",
12], {1 ->
Directive[FontFamily -> "Helvetica", Bold, 13, White]}}},
Spacings -> {1, 1}};


In this version I did not sort on the first column but that can be added.

• Above and beyond. Thank you. Apr 1, 2016 at 1:20