python-ternary icon indicating copy to clipboard operation
python-ternary copied to clipboard

heatmap(density) from scattered dots?

Open xindi-dumbledore opened this issue 6 years ago • 9 comments

Hi~ I'm wondering whether there is a easy way to plot "density" from pure dots? So I'm able to make a scatter plot from dots but what I would like to have is to get a density heat map. But from my understanding, the current heat map function needs a dictionary feed in.

Thanks a lot!

xindi-dumbledore avatar Apr 13 '18 19:04 xindi-dumbledore

There's no built in function like matplotlib provides. The easiest way is to write an interpolation function and use heatmapf or to compute your own dictionary.

marcharper avatar Apr 16 '18 03:04 marcharper

I have tried to compute a 3D histogram based on scatter data of the format [0, 0.8, 0.2], [0.3, 0.4 ,0.3] etc.. I then smooth this histogram with a Gaussian kernel. I finally create a dictionary of the smoothed histogram pointing to each coordinate e.g. (0, 0, 0), (0, 0, 1) ... (1, 1, 1) to be mapped to the simplex space.

data.txt

xyz = np.loadtxt('data.txt', delimiter=',')
nbins = 11
import numpy as np
H, b = np.histogramdd((xyz[:, 0], xyz[:, 1], xyz[:, 2]),
                      bins=(nbins, nbins, nbins), range=((0, 1), (0, 1), (0, 1)))
H = H / np.sum(H)

# 3D smoothing and interpolation
from scipy.ndimage.filters import gaussian_filter
kde = gaussian_filter(H, sigma=2)
interp_dict = dict()
binx = np.linspace(0, 1, nbins)
for i, x in enumerate(binx):
    for j, y in enumerate(binx):
        for k, z in enumerate(binx):
            interp_dict[(i/10, j/10, k/10)] = kde[i, j, k]

fig, tax = ternary.figure(scale=1)
tax.heatmap(interp_dict)
tax.show()

I've attached my result. I'm not entirely too sure what is going on and whether I am calling the scale variable correctly. My understanding was that if scale=1, (i, j, k) had to sum to 1. However, looking at the heatmap example here, the x that is passed to the heatmap function f sum to 1 and not 10.

Any help would be appreciate @marcharper and thanks again for a beautiful package :)

result

fbragman avatar Dec 10 '18 15:12 fbragman

For heatmaps i + j + k = scale. These functions create a partition of the simplex and color each sub-polygon (triangles or hexagons) with the lattice point value. The scale parameter is how it defines the lattice.

I think you can simply scale up your points -- for scale = 1 there's only one subtriangle (0, 0, 1), hence the monocolor plot. Try scale = 10 and interp_dict[(i, j, k)] = kde[i, j, k].

marcharper avatar Dec 11 '18 10:12 marcharper

Yup! Works perfectly - see below.

Thanks again - your package is really helping my upcoming paper submissions

result_2

fbragman avatar Dec 11 '18 11:12 fbragman

Glad to hear it! Let me know when you get published and I'll add your paper to the citations page.

marcharper avatar Dec 12 '18 02:12 marcharper

From here, is there a way to scale back the labels on the axis so they go between 0 and 1?

ShiveshM avatar Feb 26 '19 21:02 ShiveshM

Yes, you can directly overwrite the axes' values using matplotlib's functions for the outer plot (the usual x-axis and y-axis), or the analogous ternary functions if you are using the ternary axes markings on the three triangle sides. See the example here for the matplotlib case.

marcharper avatar Feb 27 '19 02:02 marcharper

This was a very useful piece of code, I think it would be great if it would be part of the ternary codebase!

manuelbaum avatar May 05 '22 09:05 manuelbaum

+1 to this! Supremely helpful, and definitely something that would be a nice addition if possible!

This was a very useful piece of code, I think it would be great if it would be part of the ternary codebase!

nehasrikn avatar May 05 '22 20:05 nehasrikn