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:


(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:

merged_data <- read.csv("merged_data.csv")
melted = melt(merged_data, id=1)
 + 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.

  • 2
    $\begingroup$ Could you add some sample data (for example, merged_data.csv) that you used for the R plot (or link to it somewhere)? $\endgroup$
    – rm -rf
    Nov 2, 2012 at 3:05
  • $\begingroup$ Coming right up... $\endgroup$ Nov 2, 2012 at 3:14
  • $\begingroup$ Edited to add pastebin link to 10k lines of sample data $\endgroup$ Nov 2, 2012 at 3:20
  • $\begingroup$ @nicolaskruchten, have you tried setting PlotRange to the same value for all graphs? $\endgroup$ Nov 2, 2012 at 3:38
  • $\begingroup$ 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 :) $\endgroup$ Nov 2, 2012 at 3:52

2 Answers 2


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"]]

enter image description here

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

enter image description here

  • $\begingroup$ 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)? $\endgroup$ Nov 2, 2012 at 4:45
  • $\begingroup$ @nicolaskruchten Yes, it is possible to automate the filtering of genders, - please see updated code. $\endgroup$ Nov 2, 2012 at 5:09
  • $\begingroup$ 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? $\endgroup$ Nov 2, 2012 at 5:24
  • $\begingroup$ @nicolaskruchten Done, see update. But I am sure there are many other ways to find domain/range - maybe more elegant ones. $\endgroup$ Nov 2, 2012 at 5:56
  • $\begingroup$ Thanks very much! I've learned a lot from this answer :) $\endgroup$ Nov 2, 2012 at 12:15

Well, the following will get you close ...

    idata = Import["merged_data.txt", "CSV"];
    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];
     Join[Partition[hlist, 4], {{hlist[[12]], hlist[[13]], hlist[[14]]}}]]

How much closer to you need to get?


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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