GNUPLOT : Plot sum of distributions given by parameters in text file - gnuplot

Suppose I have a text file with an arbitrary number of rows where each row gives some set of parameters that define a function (say the (x,y) location and sigmas (possibility unequal) of a 2D Gaussian). For example, in that case, the text file might contain:
100 112 3 4
97 38 8 9
88 79 3 9
...
...
102 152 9 5
I would like to plot (using pm3d) the SUM of all the distributions defined by the text file. How can that be done?

I would like to plot (using pm3d) the SUM of all the distributions defined by the text file. How can that be done?
I think that cannot be done in native gnuplot, at least not in any sane way that I know. That kind of number crunching is not really what gnuplot is designed to do.
Python, however, makes it pretty doable...
#!/usr/bin/env python2
import math
import numpy
import os
class Gaussian(object):
'''A 2D gaussian function (normalized), defined by
mx: x mean position
my: y mean position
sx: sigma in x
sy: sigma in y'''
def __init__(self, mx, my, sx, sy):
self.mx = float(mx)
self.my = float(my)
self.sx = float(sx)
self.sy = float(sy)
def value(self,x,y):
'''Evaluates the value of a Gaussian at a certain point (x,y)'''
prefactor = (1.0/(self.sx*self.sy*2*math.pi))
ypart = math.exp(-(x - self.mx)**2/(2*self.sx**2))
xpart = math.exp(-(y - self.my)**2/(2*self.sy**2))
return prefactor*ypart*xpart
def getLimits(self, devs):
'''Finds the upper and lower x and y limits for the distribution,
defined as points a certain number of deviations from the mean.'''
xmin = self.mx - devs*self.sx
xmax = self.mx + devs*self.sx
ymin = self.my - devs*self.sy
ymax = self.my + devs*self.sy
return (xmin, xmax, ymin, ymax)
def readGaussians(filename):
'''reads in gaussian parameters from an input file in the format
mx my sx sy
This makes some assumptions about how perfect the input file will be'''
gaussians = []
with open(filename, 'r') as f:
for line in f.readlines():
(mx, my, sx, sy) = line.split()
gaussians.append(Gaussian(mx, my, sx, sy))
return gaussians
def getPlotLimits(gaussians, devs):
'''finds the x and y limits of the field of gaussian distributions.
Sets the boundary a set number of deviations from the mean'''
# get the limits from the first gaussian and work from there
(xminlim, xmaxlim, yminlim, ymaxlim) = gaussians[0].getLimits(devs)
for i in range(1, len(gaussians)):
(xmin, xmax, ymin, ymax) = gaussians[i].getLimits(devs)
if (xmin < xminlim):
xminlim = xmin
if (xmax > xmaxlim):
xmaxlim = xmax
if (ymin < yminlim):
yminlim = ymin
if (ymax > ymaxlim):
ymaxlim = ymax
return (xminlim, xmaxlim, yminlim, ymaxlim)
def makeDataFile(gaussians, limits, res, outputFile):
'''makes a data file of x,y coordinates to be plotted'''
xres = res[0]
yres = res[1]
# make arrays of x and y values
x = numpy.linspace(limits[0], limits[1], xres)
y = numpy.linspace(limits[2], limits[3], yres)
# initialize grid of z values
z = numpy.zeros((xres, yres))
# compute z value at each x, y point
for i in range(len(x)):
for j in range(len(y)):
for gaussian in gaussians:
z[i][j] += gaussian.value(x[i], y[j])
# write out the matrix
with open(outputFile, 'w') as f:
for i in range(len(x)):
for j in range(len(y)):
f.write('%f %f %f\n' % (x[i], y[j], z[i][j]))
f.write('\n')
def makePlotFile(limits, outputFile):
'''makes a plot file for gnuplot'''
with open('plot.plt', 'w') as f:
f.write("#!/usr/bin/env gnuplot\n")
f.write("set terminal png font 'Courier'\n")
f.write("set output 'gaussians.png'\n")
f.write("set xr [%f:%f]\n" % (limits[0], limits[1]))
f.write("set yr [%f:%f]\n" % (limits[2], limits[3]))
f.write("set pm3d map\n")
f.write("plot '%s' with image\n" % outputFile)
# make plot file executable
os.system('chmod 755 plot.plt')
# plot
os.system('./plot.plt')
# name of input file
inputFile = 'data.dat'
# name of output (processed data)
outputFile = 'gaussians.dat'
# number of x and y points in plot
res = (100, 100)
# deviations from the mean by which to define Gaussian limits
devs = 3
# read in the gaussians from the data file
print 'reading in data...'
gaussians = readGaussians(inputFile)
# find the plot limits
limits = getPlotLimits(gaussians, devs)
# make the gaussian data file
print 'computing data for plotting...'
makeDataFile(gaussians, limits, res, outputFile)
# make the plot file
print 'plotting...'
makePlotFile(limits, outputFile)
This script produces the following output when run on your example data.

Related

How to combine multiple spectrogram subplots to produce single plot?

I am visualizing four classes of the spectrogram. For a single class, My spectrogram code looks like this
Considering this as one image.
And the code to produce this, is
def spec(filename):
time_period = 0.5 # FFT time period (in seconds). Can comfortably process time frames from 0.05 seconds - 10 seconds
# ==============================================
fs_rate, signal_original = wavfile.read(filename)
total_time = int(np.floor(len(signal_original)/fs_rate))
sample_range = np.arange(0,total_time,time_period)
total_samples = len(sample_range)
print ("Frequency sampling", fs_rate)
print ("total time: ", total_time)
print ("sample time period: ", time_period)
print ("total samples: ", total_samples)
output_array = []
for i in sample_range:
# print ("Processing: %d / %d (%d%%)" % (i/time_period + 1, total_samples, (i/time_period + 1)*100/total_samples))
sample_start = int(i*fs_rate)
sample_end = int((i+time_period)*fs_rate)
signal = signal_original[sample_start:sample_end]
l_audio = len(signal.shape)
#print ("Channels", l_audio)
if l_audio == 2:
signal = signal.sum(axis=1) / 2
N = signal.shape[0]
#print ("Complete Samplings N", N)
secs = N / float(fs_rate)
# print ("secs", secs)
Ts = 1.0/fs_rate # sampling interval in time
#print ("Timestep between samples Ts", Ts)
t = scipy.arange(0, secs, Ts) # time vector as scipy arange field / numpy.ndarray
FFT = abs(scipy.fft(signal))
FFT_side = FFT[range(int(N/2))] # one side FFT range
freqs = scipy.fftpack.fftfreq(signal.size, t[1]-t[0])
fft_freqs = np.array(freqs)
freqs_side = freqs[range(int(N/2))] # one side frequency range
fft_freqs_side = np.array(freqs_side)
# Reduce to 0-5000 Hz
bucket_size = 5
buckets = 16
FFT_side = FFT_side[0:bucket_size*buckets]
fft_freqs_side = fft_freqs_side[0:bucket_size*buckets]
# Combine frequencies into buckets
FFT_side = np.array([int(sum(FFT_side[current: current+bucket_size])) for current in range(0, len(FFT_side), bucket_size)])
fft_freqs_side = np.array([int(sum(fft_freqs_side[current: current+bucket_size])) for current in range(0, len(fft_freqs_side), bucket_size)])
# FFT_side: Normalize (0-1)
max_value = max(FFT_side)
if (max_value != 0):
FFT_side_norm = FFT_side / max_value
# Append to output array
output_array.append(FFT_side_norm)
# ============================================
# Plotting
plt.figure(figsize=(4,7))
plt.subplot(411)
plt.subplots_adjust(hspace = 0.5)
plt.plot(t, signal, "g") # plotting the signal
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.subplot(412)
diff = np.diff(fft_freqs_side)
widths = np.hstack([diff, diff[-1]])
plt.bar(fft_freqs_side, abs(FFT_side_norm), width=widths) # plotting the positive fft spectrum
plt.xticks(fft_freqs_side, fft_freqs_side, rotation='vertical')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Count single-sided')
FFT_side_norm_line = FFT_side_norm.copy()
FFT_side_norm_line.resize( (1,buckets) )
plt.subplot(413)
plt.imshow(FFT_side_norm_line)
plt.xlabel('Image Representation 1D')
plt.show()
print("\n\n\n\n\n\n")
How can I combine four images plot like this, and make a single output image. Something like this
I'd suggest using fig.subfigures and plt.subplot_mosaic.
The plot above was obtained using this simple script:
import matplotlib.pyplot as plt
fig = plt.figure(figsize = (8, 10), layout='constrained')
# next two lines make the trick
sfigs = fig.subfigures(2,2)
mosaics = [f.subplot_mosaic('t;t;t;f;f;f;i;.') for f in sfigs.flat]
# next, "how to" reference the subplots in subfigures
mosaics[0]['t'].plot(range(5), color='b')
mosaics[1]['t'].plot(range(5), color='k')
mosaics[2]['t'].plot(range(5), color='r')
mosaics[3]['t'].plot(range(5), color='g')
mosaics[0]['f'].plot(range(3), color='b')
mosaics[1]['f'].plot(range(3), color='k')
mosaics[2]['f'].plot(range(3), color='r')
mosaics[3]['f'].plot(range(3), color='g')
mosaics[0]['i'].imshow([range(10)]*2)
plt.show()
You can do it this way:
fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(x, y)
axs[0, 0].set_title('Axis [0, 0]')
axs[0, 1].plot(x, y, 'tab:orange')
axs[0, 1].set_title('Axis [0, 1]')
axs[1, 0].plot(x, -y, 'tab:green')
axs[1, 0].set_title('Axis [1, 0]')
axs[1, 1].plot(x, -y, 'tab:red')
axs[1, 1].set_title('Axis [1, 1]')
for ax in axs.flat:
ax.set(xlabel='x-label', ylabel='y-label')
# Hide x labels and tick labels for top plots and y ticks for right plots.
for ax in axs.flat:
ax.label_outer()
The result will be like this:
Taken from https://matplotlib.org/stable/gallery/subplots_axes_and_figures/subplots_demo.html

How to insert Gaussian/Normal distribution in multiple subplots?

So I have multiple plots, using subplot and I would like to add the Gaussian distribution on it. I have done it, in a for loop for each plot separately, but I am not sure how to do it using subplots. At the moment it does not show anything on the subplots.
def index_of(arrval, value):
if value < min(arrval):
return 0
return max(np.where(arrval <= value)[0])
# load file using loadtxt
for file in filename:
data = np.loadtxt(file,delimiter='\t', skiprows=2)
for x,y in data:
x = data[:,0]
y = data[:,1]
xs.append(x)
ys.append(y)
# Make the subplots
for i, (x, y) in enumerate(zip(xs, ys)):
ij = np.unravel_index(i, axs.shape)
axs[ij].plot(x, y,label = lsnames[i])
axs[ij].set_title(lsnames[i])
axs[ij].legend()
# Using one of the lmfit functions to get the Gaussian plot.
# But it does not show anything
gauss1 = GaussianModel(prefix='g1_')
gauss2 = GaussianModel(prefix='g2_')
pars = gauss1.guess(y, x=x)
pars.update(gauss2.make_params())
ix1 = index_of(x, 20)
ix2 = index_of(x, 40)
ix3 = index_of(x, 75)
gauss1.guess(y[ix1:ix2], x=x[ix1:ix2])
gauss2.guess(y[ix2:ix3], x=x[ix2:ix3])
mod = gauss1 + gauss2
mod = GaussianModel()
pars = mod.guess(y, x=x)
out = mod.fit(y, pars, x=x)
print(out.fit_report(min_correl=0.25))
plt.show()
Maybe I'm not fully understanding, but this seems like it could just be a looping question or even an indentation problem.
I think what you're asking to do is something like:
# loop over datasets, putting each in a subplot
for i, (x, y) in enumerate(zip(xs, ys)):
ij = np.unravel_index(i, axs.shape)
axs[ij].plot(x, y,label = lsnames[i])
axs[ij].set_title(lsnames[i])
axs[ij].legend()
# fit this dataset with 1 gaussian
mod = GaussianModel()
pars = mod.guess(y, x=x)
out = mod.fit(y, pars, x=x)
# plot best-fit
axs[ij].plot(x, out.best_fit, label='fit')
print("Data Set %d" % i)
print(out.fit_report(min_correl=0.25))
plt.show()
Your code was sort of confusingly making a model with two Gaussians and then not using it. It would be fine to use a more complicated model in the loop.
Hope that helps.

Create Image using Matplotlib imshow meshgrid and custom colors

I am trying to create an image where the x axis is the width, and y axis is the height of the image. And where each point can be given a color based on a RBG mapping. From looking at imshow() from Matplotlib I guess I need to create a meshgrid on the form (NxMx3) where 3 is a tuple or something similar with the rbg colors.
But so far I have not managed to understand how to do that. Lets say I have this example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
x_min = 1
x_max = 5
y_min = 1
y_max = 5
Nx = 5 #number of steps for x axis
Ny = 5 #number of steps for y axis
x = np.linspace(x_min, x_max, Nx)
y = np.linspace(y_min, y_max, Ny)
#Can then create a meshgrid using this to get the x and y axis system
xx, yy = np.meshgrid(x, y)
#imagine I have some funcion that does someting based on the x and y values
def somefunc(x_value, y_value):
#do something and return rbg based on that
return x_value + y_value
res = somefunc(xx, yy)
cmap = LinearSegmentedColormap.from_list('mycmap', ['white', 'blue', 'black'])
plt.figure(dpi=100)
plt.imshow(res, cmap=cmap, interpolation='bilinear')
plt.show()
And this creates a plot, but what would I have to do if my goal was to give spesific rbg values based on x and y values inside somefunc and make the resulting numpy array into a N x M x 3 array
I tried to make the somefunc function return a tuple of rbg values to use (r, b g) but that does not seem to work
It will of course completely depend on what you want to do with the values you supply to the function. So let's assume you just want to put the x values as the red channel and the y values as the blue channel, this could look like
def somefunc(x_value, y_value):
return np.dstack((x_value/5., np.zeros_like(x_value), y_value/5.))
Complete example:
import numpy as np
import matplotlib.pyplot as plt
x_min = 1
x_max = 5
y_min = 1
y_max = 5
Nx = 5 #number of steps for x axis
Ny = 5 #number of steps for y axis
x = np.linspace(x_min, x_max, Nx)
y = np.linspace(y_min, y_max, Ny)
#Can then create a meshgrid using this to get the x and y axis system
xx, yy = np.meshgrid(x, y)
#imagine I have some funcion that does someting based on the x and y values
def somefunc(x_value, y_value):
return np.dstack((x_value/5., np.zeros_like(x_value), y_value/5.))
res = somefunc(xx, yy)
plt.figure(dpi=100)
plt.imshow(res)
plt.show()
If you already have a (more complicated) function that returns an RGB tuple you may loop over the grid to fill an empty array with the values of the function.
#If you already have some function that returns an RGB tuple
def somefunc(x_value, y_value):
if x_value > 2 and y_value < 3:
return np.array(((y_value+1)/4., (y_value+2)/5., 0.43))
elif x_value <=2:
return np.array((y_value/5., (x_value+3)/5., 0.0))
else:
return np.array((x_value/5., (y_value+5)/10., 0.89))
# you may loop over the grid to fill a new array with those values
res = np.zeros((xx.shape[0],xx.shape[1],3))
for i in range(xx.shape[0]):
for j in range(xx.shape[1]):
res[i,j,:] = somefunc(xx[i,j],yy[i,j])
plt.figure(dpi=100)
plt.imshow(res)

Updating pyplot.vlines in interactive plot

I need your help. Please consider the code below, which plots a sinusoid using pylab in IPython. A slider below the axis enables the user to adjust the frequency of the sinusoid interactively.
%pylab
# setup figure
fig, ax = subplots(1)
fig.subplots_adjust(left=0.25, bottom=0.25)
# add a slider
axcolor = 'lightgoldenrodyellow'
ax_freq = axes([0.3, 0.13, 0.5, 0.03], axisbg=axcolor)
s_freq = Slider(ax_freq, 'Frequency [Hz]', 0, 100, valinit=a0)
# plot
g = linspace(0, 1, 100)
f0 = 1
sig = sin(2*pi*f0*t)
myline, = ax.plot(sig)
# update plot
def update(value):
f = s_freq.val
new_data = sin(2*pi*f*t)
myline.set_ydata(new_data) # crucial line
fig.canvas.draw_idle()
s_freq.on_changed(update)
Instead of the above, I need to plot the signal as vertical lines, ranging from the amplitude of each point in t to the x-axis. Thus, my first idea was to use vlines instead of plot in line 15:
myline = ax.vlines(range(len(sig)), 0, sig)
This solution works in the non-interactive case. The problem is, plot returns an matplotlib.lines.Line2D object, which provides the set_ydata method to update data interactively. The object returned by vlines is of type matplotlib.collections.LineCollection and does not provide such a method.
My question: how do I update a LineCollection interactively?
Using #Aaron Voelker's comment of using set_segments and wrapping it up in a function:
def update_vlines(*, h, x, ymin=None, ymax=None):
seg_old = h.get_segments()
if ymin is None:
ymin = seg_old[0][0, 1]
if ymax is None:
ymax = seg_old[0][1, 1]
seg_new = [np.array([[xx, ymin],
[xx, ymax]]) for xx in x]
h.set_segments(seg_new)
Analog for hlines:
def update_hlines(*, h, y, xmin=None, xmax=None):
seg_old = h.get_segments()
if xmin is None:
xmin = seg_old[0][0, 0]
if xmax is None:
xmax = seg_old[0][1, 0]
seg_new = [np.array([[xmin, yy],
[xmax, yy]]) for yy in y]
h.set_segments(seg_new)
I will give examples for vlines here.
If you have multiple lines, #scleronomic solution works perfect. You also might prefer one-liner:
myline.set_segments([np.array([[x, x_min], [x, x_max]]) for x in xx])
If you need to update only maximums, then you can do this:
def update_maxs(vline):
vline[:,1] = x_min, x_max
return vline
myline.set_segments(list(map(update_maxs, x.get_segments())))
Also this example could be useful: LINK

Generating a KML heatmap from given data set of [lat, lon, density]

I am looking to build a static KML (Google Earth markup) file which displays a heatmap-style rendering of a few given data sets in the form of [lat, lon, density] tuples.
A very straightforward data set I have is for population density.
My requirements are:
Must be able to feed in data for a given lat, lon
Must be able to specify the density of the data at that lat, lon
Must export to KML
The requirements are language agnostic for this project as I will be generating these files offline in order to build the KML used elsewhere.
I have looked at a few projects, most notably heatmap.py, which is a port of gheat in Python with KML export. I have hit a brick wall in the sense that the projects I have found to date all rely on building the heatmap from the density of [lat, lon] points fed into the algorithm.
If I am missing an obvious way to adapt my data set to feed in just the [lat, lon] tuples but adjusting how I feed them using the density values I have, I would love to know!
Hey Will, heatmap.py is me. Your request is a common-enough one and is on my list of things to address. I'm not quite sure yet how to do so in a general fashion; in heatmap.py parlance, it would be straightforward to have a per-point dotsize instead of a global dotsize as it is now, but I'm not sure that will address the true need. I'm aiming for a summer 2010 release, but you could probably make this mod yourself.
You may try searching for Kernel Density Estimator tools; that's what the statisticians call heatmaps. R has some good built-in tools you can use that might satisfy your need more quickly.
good luck!
I updated the heatmap.py script so you can specify a density for each point. I uploaded my changes to my blog. Not sure if it'll do exactly what you want though!
Cheers,
Alex
Update [13 Nov 2020]
I archived my blog a while back, so the link no longer works, so for reference here are the changes:
the diff file:
--- __init__.py 2010-09-14 08:40:35.829079482 +0100
+++ __init__.py.mynew 2010-09-06 14:50:10.394447647 +0100
## -1,5 +1,5 ##
#heatmap.py v1.0 20091004
-from PIL import Image,ImageChops
+from PIL import Image,ImageChops,ImageDraw
import os
import random
import math
## -43,10 +43,13 ##
Most of the magic starts in heatmap(), see below for description of that function.
"""
def __init__(self):
+ self.minIntensity = 0
+ self.maxIntensity = 0
self.minXY = ()
self.maxXY = ()
+
- def heatmap(self, points, fout, dotsize=150, opacity=128, size=(1024,1024), scheme="classic"):
+ def heatmap(self, points, fout, dotsize=150, opacity=128, size=(4048,1024), scheme="classic", area=(-180,180,-90,90)):
"""
points -> an iterable list of tuples, where the contents are the
x,y coordinates to plot. e.g., [(1, 1), (2, 2), (3, 3)]
## -59,33 +62,41 ##
size -> tuple with the width, height in pixels of the output PNG
scheme -> Name of color scheme to use to color the output image.
Use schemes() to get list. (images are in source distro)
+ area -> specify the coordinates covered by the resulting image
+ (could create an image to cover area larger than the max/
+ min values given in the points list)
"""
-
+ print("Starting heatmap")
self.dotsize = dotsize
self.opacity = opacity
self.size = size
self.imageFile = fout
-
+
if scheme not in self.schemes():
tmp = "Unknown color scheme: %s. Available schemes: %s" % (scheme, self.schemes())
raise Exception(tmp)
- self.minXY, self.maxXY = self._ranges(points)
- dot = self._buildDot(self.dotsize)
+ self.minXY = (area[0],area[2])
+ self.maxXY = (area[1],area[3])
+ self.minIntensity, self.maxIntensity = self._intensityRange(points)
+
img = Image.new('RGBA', self.size, 'white')
- for x,y in points:
+ for x,y,z in points:
+ dot = self._buildDot(self.dotsize,z)
tmp = Image.new('RGBA', self.size, 'white')
tmp.paste( dot, self._translate([x,y]) )
img = ImageChops.multiply(img, tmp)
-
+ print("All dots built")
colors = colorschemes.schemes[scheme]
img.save("bw.png", "PNG")
+ print("Saved temp b/w image")
+ print("Colourising")
self._colorize(img, colors)
img.save(fout, "PNG")
-
+ print("Completed colourising and saved final image %s" % fout)
def saveKML(self, kmlFile):
"""
Saves a KML template to use with google earth. Assumes x/y coordinates
## -110,17 +121,19 ##
"""
return colorschemes.schemes.keys()
- def _buildDot(self, size):
+ def _buildDot(self, size,intensity):
""" builds a temporary image that is plotted for
each point in the dataset"""
+
+ intsty = self._calcIntensity(intensity)
+ print("building dot... %d: %f" % (intensity,intsty))
+
img = Image.new("RGB", (size,size), 'white')
- md = 0.5*math.sqrt( (size/2.0)**2 + (size/2.0)**2 )
- for x in range(size):
- for y in range(size):
- d = math.sqrt( (x - size/2.0)**2 + (y - size/2.0)**2 )
- rgbVal = int(200*d/md + 50)
- rgb = (rgbVal, rgbVal, rgbVal)
- img.putpixel((x,y), rgb)
+ draw = ImageDraw.Draw(img)
+ shade = 256/(size/2)
+ for x in range (int(size/2)):
+ colour = int(256-(x*shade*intsty))
+ draw.ellipse((x,x,size-x,size-x),(colour,colour,colour))
return img
def _colorize(self, img, colors):
## -139,7 +152,7 ##
rgba.append(alpha)
img.putpixel((x,y), tuple(rgba))
-
+
def _ranges(self, points):
""" walks the list of points and finds the
max/min x & y values in the set """
## -153,6 +166,23 ##
return ((minX, minY), (maxX, maxY))
+ def _calcIntensity(self,z):
+ return (z/self.maxIntensity)
+
+ def _intensityRange(self, points):
+ """ walks the list of points and finds the
+ max/min points of intensity
+ """
+ minZ = points[0][2]
+ maxZ = minZ
+
+ for x,y,z in points:
+ minZ = min(z, minZ)
+ maxZ = max(z, maxZ)
+
+ print("(minZ, maxZ):(%d, %d)" % (minZ,maxZ))
+ return (minZ, maxZ)
+
def _translate(self, point):
""" translates x,y coordinates from data set into
pixel offsets."""
and a demo script:
import heatmap
import random
import MySQLdb
import math
print "starting script..."
db = MySQLdb.connect(host="localhost", # your host, usually localhost
user="username", # your username
passwd="password", # your password
db="database") # name of the data base
cur = db.cursor()
minLng = -180
maxLng = 180
minLat = -90
maxLat = 90
# create and execute the query
query = "SELECT lat, lng, intensity FROM mytable \
WHERE %f<=tllat AND tllat<=%f \
AND %f<=tllng AND tllng<=%f" % (minLat,maxLat,minLng,maxLng)
cur.execute(query)
pts = []
# print all the first cell of all the rows
for row in cur.fetchall() :
print (row[1],row[0],row[2])
# work out the mercator projection for latitute x = asinh(tan(x1))
proj = math.degrees(math.asinh(math.tan(math.radians(row[0]))))
print (row[1],proj,row[2])
print "-"*15
if (minLat < proj and proj < maxLat):
pts.append((row[1],proj,row[2]))
print "Processing %d points..." % len(pts)
hm = heatmap.Heatmap()
hm.heatmap(pts, "bandwidth2.png",30,155,(1024,512),'fire',(minLng,maxLng,minLat,maxLat))
I think one way to do this is to create a (larger) list of tuples with each point repeated according to the density at that point. A point with a high density is represented by lots of points on top of each other while a point with a low density has few points. So instead of: [(120.7, 82.5, 2), (130.6, 81.5, 1)] you would use [(120.7, 82.5), (120.7, 82.5), (130.6, 81.5)] (a fairly dull dataset).
One possible issue is that your densities may well be floats, not integers, so you should normalize and round the data. One way to do the conversion is something like this:
def dens2points (dens_tups):
min_dens = dens_tups[0][2]
for tup in dens_tups:
if (min_dens > tup[2]):
min_dens = tup[2]
print min_dens
result = []
for tup in dens_tups:
for i in range(int(tup[2]/min_dens)):
result.append((tup[0],tup[1]))
return result
if __name__ == "__main__":
input = [(10, 10, 20.0),(5, 5, 10.0),(10,10,0.9)]
output = dens2points(input)
print input
print output
(which isn't very pythonic, but seems to work for the simple test case). This subroutine should convert your data into a form that is accepted by heatmap.py. With a little effort I think the subroutine can be reduced to two lines.

Resources