Message Boards Message Boards

Facing your data with Chernoff faces

Posted 8 years ago
POSTED BY: Anton Antonov
6 Replies

Here is a link to the recently approved Wolfram Function Repository function ChernoffFace.

There are some important extensions of the original ChernoffFace scope described above:

  • allowing for auto-coloring with the option "ColorFunction", and

  • allowing a list of records to be visualized.

The latter is not done just with a Map call -- if the data argument can be interpreted as a full array, then the columns are rescaled first. (Each column is rescaled separately.)

An example illustrating that follows.

Get the "USArrests" data:

data = ExampleData[{"Statistics", "USArrests"}];
Dimensions[data]
(* {50, 5} *)

Get the corresponding column names:

dataColumnNames = ExampleData[{"Statistics", "USArrests"}, "ColumnHeadings"]    
(* {"StateName", "Murder", "Assault", "UrbanPopulation", "Rape"} *)

Here is a summary of the dataset:

ResourceFunction["RecordsSummary"][data, dataColumnNames]

enter image description here

Visualize with Chernoff faces:

Block[{data = data[[All, 2 ;; -1]], recNames = data[[All, 1]], dataColumnNames = dataColumnNames[[2 ;; -1]], imgs},
 imgs = ResourceFunction["ChernoffFace"][data, ColorFunction -> "Rainbow", ImageSize -> 100];
 imgs = MapThread[Append[#1, PlotLabel -> #2] &, {imgs, recNames}];
 Legended[
  Grid[Partition[imgs, 8], Dividers -> All],
  Placed[Framed[
    Grid[Thread[{Take[Keys@ResourceFunction["ChernoffFace"]["FaceParts"], Length[dataColumnNames]], dataColumnNames}], 
     Alignment -> {{Right, Left}}]], "Top"]]
 ]

enter image description here

POSTED BY: Anton Antonov

The MathematicaVsR at GitHub project BrowsingDataWithChernoffFaces compares Mathematica and R codes for interactive data browsers that utilize Chernoff faces.

Here is an image (based on the built-in USA arrests data) from the album of screenshots of the Mathematica-made browser:

enter image description here

POSTED BY: Anton Antonov

Set-up

The data in this MSE question Finding the best way to visualize rather complicated data presents a good case for visualization with Chernoff faces. For that data, actually, the Chernoff faces work "out of the box" pretty well!

Here is the data:

data = {{7.5, 12.45, 12.45, 12.75, 12.75, 12.25, 12.25, 12.53, 12.53},
{8.5, 12.22, 12.22, 12.23, 12.23, 13, 13, 12.54, 12.54}, 
{9.5, 11.58, 11.53, 12.75, 13.48, 12.39, 12.52, 12.17, 13.56}, 
{10.5, 11.76, 11.82, 12.97, 13.55, 12.15, 11.88, 13.07, 12.79}, 
{11.5, 11.18, 11.85, 13.27, 13.02, 12.32, 13, 12.72, 12.63}, 
{12.5, 11.04, 11.61, 13.70, 14.17, 12.77, 12.79, 12.13, 11.78}, 
{13.5, 11.64, 10.68, 13.52, 14.03, 13.14, 13.21, 11.64, 12.13}, 
{14.5, 12.04, 12.12, 13.23, 13.67, 12.58, 13.02, 11.26, 12.05}, 
{15.5, 14.10, 14, 11.65, 11.68, 12.17, 12.36, 12.19, 11.85}, 
{16.5, 14.85, 14.54, 10.94, 11.62, 12.17, 11.72, 11.84, 12.31}, 
{17.5, 15.78, 15.78, 10.62, 10.62, 11.72, 11.72, 11.88, 11.88}, 
{18.5, 17.18, 17.18, 9.53, 9.53, 11.66, 11.66, 11.63, 11.63}};

The data in the question presents a good case for visualization with Chernoff faces. For that data, actually, the Chernoff faces work "out of the box" pretty well!

Make faces

Load Chernoff faces plotting package:

Import["https://raw.githubusercontent.com/antononcube/\
MathematicaForPrediction/master/ChernoffFaces.m"]

As it is explained in the question the first element of each row is a coordinate and the rest of the elements are percentages:

Total@*Rest /@ data

(* {99.96, 99.98, 99.98, 99.99, 99.99, 99.99, 99.99, 99.97, 100., 99.99, 100., 100.} *)

Using that data property we apply Chernoff faces in the following way.

  • The Chernoff faces are applied after each non-coordinate column is rescaled into [0,1].

  • The faces are colored according to how close the values of each row of data[[All,2;;-1]] are to the Normal Distribution.

  • The rows with close to normally distributed percentages have faces that are more yellow and more smiling.

Here is a grid of the obtained Chernoff faces :

facesGrid =
 Grid[ArrayReshape[#, {3, 4}, ""], Dividers -> All, 
    Alignment -> {Left, Top}] &@
  MapThread[
   (asc = 
      AssociationThread[
       Take[Keys@ChernoffFace["FacePartsProperties"], 
         Length[#3] + 1] -> Append[#3, #4]];
     Column[{
       Row[{"row:", #1, ", x=", #2}],
       ChernoffFace[
        Join[asc, <|"FaceColor" -> Blend[{White, Lighter[Yellow]}, #4]|>], 
        ImageSize -> 150, AspectRatio -> Automatic]}]) &
   , {Range[Length[data]], First /@ data, 
    Transpose[Rescale /@ Transpose[Rest /@ data]], 
    PearsonChiSquareTest[Standardize[Rest[#]], 
       NormalDistribution[0, 1]] & /@ data}]

enter image description here

Here are all face properties used in the Chernoff faces above:

props = 
 Take[Keys@ChernoffFace["FacePartsProperties"], Length[First@data]]

(* {"FaceLength", "ForheadShape", "EyesVerticalPosition", "EyeSize",\
    "EyeSlant", "LeftEyebrowSlant", "LeftIris", "NoseLength", \
    "MouthSmile"} *)

Discernibility and classification

The main motivation behind the introduction and use of Chernoff faces is that they would provide inherent visual discernibility and classification. With this data that claim is fulfilled.

We can easily see that the face of row 7 is a clear outlier which can be explained by looking at the columns "ForheadShape" and "EyeSlant" of the table of the data:

enter image description here

Also we can easily see from the faces that row 5 has rows 3, 4, 6 as nearest neighbors. This can be demonstrated with the following commands:

nf = Nearest[data[[All, 2 ;; -1]] -> Automatic];
nf[data[[5, 2 ;; -1]], 5]

(*  {5, 4, 3, 6, 1} *)

(Of course other nearest neighbors can be easily found.)

POSTED BY: Anton Antonov

Here is a combination of Chernoff faces and SectorChart plots:

facesGrid =
 Grid[ArrayReshape[#, {3, 4}, ""], Dividers -> All, Alignment -> {Left, Top}] &@
  MapThread[
   (asc = 
      AssociationThread[
       Take[Keys@ChernoffFace["FacePartsProperties"], 
         Length[#3] + 1] -> Append[#3, #4]];
     Grid[{
       {Row[{"row:", #1, ", x=", #2}], SpanFromLeft},
       {ChernoffFace[Join[asc, <|"FaceColor" -> Blend[{White, Lighter[Yellow]}, #4]|>], 
         ImageSize -> 150, AspectRatio -> Automatic], 
        SectorChart[Transpose@{ConstantArray[1, Length[#3]], #5}]}}]) &
   , {Range[Length[data]], First /@ data, 
    Transpose[Rescale /@ Transpose[Rest /@ data]], 
    PearsonChiSquareTest[Standardize[Rest[#]], NormalDistribution[0, 1]] & /@ data, 
    Rest /@ data}]

enter image description here

POSTED BY: Anton Antonov

Here are links to the related Python package "ChernoffFace" at:

Here is a plot of the "USA arrests" data using that Python package:

enter image description here

Remark: Because of the way the Python matplotlib library is designed the faces in the plot above are wide instead of being long as in the corresponding WL plot.

POSTED BY: Anton Antonov

enter image description here - another post of yours has been selected for the Staff Picks group, congratulations !

We are happy to see you at the tops of the "Featured Contributor" board. Thank you for your wonderful contributions, and please keep them coming!

POSTED BY: Moderation Team
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract