28
$\begingroup$

I have a list of coordinates in form {{x1,y1},{x2,y2},...}

Is there a way in mma to builds density plots based on position ( ListDensityPlot calculates density based on value in {x,y,value})? I want to create something similar to heatmap.py.

$\endgroup$

3 Answers 3

27
$\begingroup$

There are two functions that can do this:

These functions also come in a smoothed version (prepend Smooth to the name), which can be used to obtain results similar to what Heike plotted.

Edit

If you work in a regime where individual points are resolved, you may notice a disconcerting shift in the output of SmoothDensityHistogram (at least I see it on Mac OS X, MMA version 8.0.4):

data = RandomReal[1, {100, 2}];
Show[
 SmoothDensityHistogram[data, 0.015, "PDF",
  ColorFunction -> "Rainbow",
  Mesh -> 0,
  PlotRange -> {{0, 1}, {0, 1}}],
 Graphics[Point@data],
 PlotRange -> {{0, 1}, {0, 1}}
 ]

ShiftedDensity

I only noticed this after looking at R.M.'s plot with the original points superimposed, as shown above.

To fix this and at the same time understand better what these smoothed histogram plots really do, you could take a look at the following function:

heatMap[data_, opts : OptionsPattern[]] := Module[
  {n, size, xRange, pr},
  n = "Points" /. {opts} /. {"Points" -> 100};
  pr = PlotRange /. {opts} /. {PlotRange :> 
      Map[{Min[#], Max[#]} &, Transpose[data]]};
  xRange = -Subtract @@ pr[[1]];
  size = Floor[
    n ("Radius" /. {opts} /. {"Radius" -> xRange/6})/xRange];
  Graphics[{
    Inset[
     ArrayPlot[
      Rescale@GaussianFilter[
        ImageData@ColorNegate@ColorConvert[
           Rasterize[Graphics[Point[data],
             Background -> White,
             PlotRangePadding -> 0,
             ImagePadding -> 0,
             ImageMargins -> 0,
             PlotRange -> pr],
            "Image", ImageSize -> n], "GrayScale"],
        {3 size, size}, Padding -> 0],
      ColorFunction ->  
       (ColorFunction /. {opts} /. 
        {ColorFunction -> 
         ColorData["LakeColors"]
        }
       ),
      ImagePadding -> 0,
      PlotRangePadding -> 0, Frame -> False],
     pr[[All, 1]], {0, 0}, xRange]},
   PlotRange -> pr, Frame -> True, PlotRangePadding -> Scaled[.02]
   ]
  ]

Show[heatMap[data, "Points" -> 300, "Radius" -> .02, 
  PlotRange -> {{0, 1}, {0, 1}}, 
  ColorFunction -> ColorData["Rainbow"]],
 Graphics[Point@data], 
 PlotRange -> {{0, 1}, {0, 1}}]

noSHift

So I basically re-implemented this plotting function by using GaussianFilter, without trying to implement all the options provided by the built-in function.

The options it recognizes are "Points" (the number of sampling points in the horizontal direction), "Radius" (the radius of the Gaussian) and PlotRange.

Besides giving better alignment between the heat map and the points, this manual approach also could be used to do some non-standard things. For example, you could change Padding -> 0 to Padding -> "Periodic" if the data points live on a torus topology.

To show the dependence on the choice of radius, here is a movie:

Export["l.gif", 
 Join[#, Reverse[#]] &@
  Table[Show[
    heatMap[data, "Points" -> 300, "Radius" -> r^2, 
     PlotRange -> {{0, 1}, {0, 1}}], Graphics[Point@data], 
    PlotRange -> {{0, 1}, {0, 1}}],
   {r, .15, .25, .015}], "DisplayDurations" -> .1]

snoothing

Edit

I forgot to add ColorFunction as an option - that's now done, with "LakeColors" as the default, as it is for SmoothDensityHistogram. There was also a Frame -> False missing in ArrayPlot, which I fixed in the code.

As an added bonus, plots created with heatMap take much less space when exported as PDF.

$\endgroup$
20
$\begingroup$

You can use SmoothDensityHistogram to generate heatmaps. This does the same as what Heike's method does, but in one line. Example:

data = RandomReal[1, {100, 2}];
SmoothDensityHistogram[data, 0.02, "PDF", ColorFunction -> "Rainbow", Mesh -> 0]

enter image description here

$\endgroup$
9
  • 1
    $\begingroup$ @R.M. Do you also see an offset between the maxima and the original points if you plot them together? I see that on my machine, see my answer. It seems to indicate that someone was sloppy when writing this function. $\endgroup$
    – Jens
    May 27, 2012 at 23:04
  • 1
    $\begingroup$ @Jens Yes, it shows up on mine and Heike's too. Looks like SmoothKernelDistribution is the culprit (since SDH calls SKD internally). I did notice a spurious offset in a more involved example I was working on that included image processing, but I didn't realize it was due to SKD and instead thought it was due to some sloppy Dilations on my part... Thanks for pointing this out. Probably should send an email to support@wolfram too... $\endgroup$
    – rm -rf
    May 27, 2012 at 23:48
  • 3
    $\begingroup$ I've sent a bug report about SmoothDensityHistogram to Wolfram [TS 21354]. $\endgroup$
    – Jens
    May 28, 2012 at 5:41
  • 2
    $\begingroup$ @Jens This is a case where boosting InterpolationPoints to say 256 will be useful. It is more of a failure of automation than a bug. KernelMixtureDistribution might be a better alternative though. $\endgroup$
    – Andy Ross
    May 29, 2012 at 20:46
  • 1
    $\begingroup$ @AlexeyPopkov I believe it actually does have this option it just isn't documented. It certainly seems to have an effect for me. $\endgroup$
    – Andy Ross
    Sep 15, 2012 at 15:43
18
$\begingroup$

It looks like SmoothKernelDistribution might do the trick. For example

data = RandomReal[1, {100, 2}];

dist = SmoothKernelDistribution[data, .02]

DensityPlot[Evaluate[PDF[dist, {x, y}]], {x, 0, 1}, {y, 0, 1}, 
 PlotRange -> All, ColorFunction -> "SunsetColors", PlotPoints -> 40]

Mathematica graphics

$\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.