# How can I create facetted histograms?

I love Mathematica, and I would love to be able to use it for all of my data analysis tasks, but there is one type of analysis which I find almost trivial in R, and I have no idea how to approach in Mathematica.

Say I have a CSV file containing a few hundred thousand people's ranked preferences for items, in a format like this:

Gender,X29234,X30310,X28908,...
Male,1,2,3,...
Female,1,3,2,...
...


(in this case the female liked item X28908 more than item X30310)

10000 rows of sample data can be found here.

I want to plot histograms of the ranks each gender assigned to each item. In R I can use reshape2 and ggplot2 to do something like this:

library(reshape2)
library(ggplot2)
melted = melt(merged_data, id=1)
ggplot(melted)
+ geom_histogram(aes(x=value,y = ..density..,fill=factor(Gender)),binwidth=1, position="identity",alpha=.5)
+ facet_wrap(~variable)
+ theme(legend.position="bottom")
+ scale_fill_discrete(name="Gender: ")


to get a nice graph like this:

The key thing for me here are that the individual plots all end up having the same axis bounds, even though the bounds of the data in each plot aren't the same, which makes comparisons really easy.

How would I go about doing something like this in Mathematica so I can get rid of R in my workflow?

Edit: I should clarify that this example with Gender is to simplify the problem to something easier to explain, and I'm looking for a solution which is as automatic as possible: doesn't involve enumerating in the source the possible values of the Gender field, doesn't involve hard-coding in the source the bounds of the plot etc. ggplot2 does all of these out of the box, so I'm looking for a reusable approach to do something similar.

-
Could you add some sample data (for example, merged_data.csv) that you used for the R plot (or link to it somewhere)? –  rm -rf Nov 2 '12 at 3:05
Coming right up... –  nicolaskruchten Nov 2 '12 at 3:14
Edited to add pastebin link to 10k lines of sample data –  nicolaskruchten Nov 2 '12 at 3:20
@nicolaskruchten, have you tried setting PlotRange to the same value for all graphs? –  alancalvitti Nov 2 '12 at 3:38
To be honest, I don't even know to split the data in this way and generate all these graphs in the first place, or how I would compute the PlotRange to assign to them :) –  nicolaskruchten Nov 2 '12 at 3:52

If I understand correctly, this question is about complete automation for uniform look. Hence the specifics of solution below. Import data:

data = Import["http://pastebin.com/download.php?i=fZKMqxK9"];


Define filter that automatically separates data by gender:

filter[gender_] := Rest[Transpose[Select[data, #[[1]] == gender &]]]


For complete automation find absolute domain and range for all plots so it is easy to compare them (not sure if this is most elegant way):

doMraN = {{1, Max[Rest@Transpose@Rest@data]},
{0, Max[((Max[#]/Total[#]) &@Tally[#][[All, 2]]) & /@
Flatten[(filter /@ Union[Rest[data[[All, 1]]]]), 1]]}}


{{1, 14}, {0, 977/1411}}

And you are done basically:

MapThread[Histogram[{#2, #3}, Automatic, "Probability", PlotRange -> doMraN,
PlotLabel -> #1[[1]], ChartStyle -> 54, GridLines -> {None, Automatic}, Frame -> True] &,
filter /@ Prepend[Union[Rest[data[[All, 1]]]], "Gender"]]


Grid[data[[1 ;; 20]], Frame -> All, Alignment -> Left, Background -> {{Yellow}, {Green}}]


-
Wow, that's impressive! Is there any way to avoid hardcoding the "Male" and "Female" strings and have it break out according to all the unique values of a column (i.e. so that if I added rows with an "Unknown" gender a third set of bars would automatically appear)? –  nicolaskruchten Nov 2 '12 at 4:45
@nicolaskruchten Yes, it is possible to automate the filtering of genders, - please see updated code. –  Vitaliy Kaurov Nov 2 '12 at 5:09
OK, very neat. The only remaining issue is the bounds of the plot: I see that you hard-coded the range, and that the domain is left to chance, for example the second plot only goes to 10. Would I have to generate the list of plots, iterate through them to find the min/max of the domain/range and then apply that to each plot? –  nicolaskruchten Nov 2 '12 at 5:24
@nicolaskruchten Done, see update. But I am sure there are many other ways to find domain/range - maybe more elegant ones. –  Vitaliy Kaurov Nov 2 '12 at 5:56
Thanks very much! I've learned a lot from this answer :) –  nicolaskruchten Nov 2 '12 at 12:15

Well, the following will get you close ...

    idata = Import["merged_data.txt", "CSV"];
Dimensions@idata
hedr = idata[[1]];
idata = Rest@idata[[2 ;;]];
ftik = {#, #/10000.} & /@ Range[0, 6000, 1000];
xtik = {#, #} & /@ Range[0, 15, 1];
hlist = Histogram[{
Select[idata, SameQ[#[[1]], "Female"] &][[All, #]],
Select[idata, SameQ[#[[1]], "Male"] &][[All, #]]}, {1},
PlotLabel -> hedr[[#]],
Frame -> True,
GridLines -> Automatic,
FrameTicks -> {{ftik, None}, {xtik, None}},
PlotRange -> {{0, 15}, {0, 6000}},
ImageSize -> 200,
BaseStyle -> {FontFamily -> "Helvetica", FontSize -> 12}
] & /@ Range[2, Length@hedr];
GraphicsGrid[
Join[Partition[hlist, 4], {{hlist[[12]], hlist[[13]], hlist[[14]]}}]]


How much closer to you need to get?

-