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.
Mathematica Stack Exchange is a question and answer site for users of Wolfram Mathematica. It only takes a minute to sign up.
Sign up to join this communityI 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.
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}}
]
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}}]
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]
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
.
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]
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 Dilation
s on my part... Thanks for pointing this out. Probably should send an email to support@wolfram
too...
$\endgroup$
SmoothDensityHistogram
to Wolfram [TS 21354].
$\endgroup$
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$
May 29, 2012 at 20:46
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]