Skip to content

Commit d8555e0

Browse files
committed
heatmap: kruler-style freq labels
1 parent f5870c8 commit d8555e0

File tree

2 files changed

+90
-8
lines changed

2 files changed

+90
-8
lines changed

heatmap/Vera.ttf

64.4 KB
Binary file not shown.

heatmap/heatmap.py

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
sys.argv[i] = ' ' + arg
4949
args = parser.parse_args()
5050

51+
try:
52+
font = ImageFont.truetype("Vera.ttf", 10)
53+
except:
54+
print('Please download the Vera.ttf font and place it in the current directory.')
55+
sys.exit(1)
56+
57+
5158
def frange(start, stop, step):
5259
i = 0
5360
while (i*step + start <= stop):
@@ -209,7 +216,8 @@ def rgb3(z):
209216
return (int(c[0]*256),int(c[1]*256),int(c[2]*256))
210217

211218
print("drawing")
212-
img = Image.new("RGB", (len(freqs), len(times)))
219+
tape_height = 25
220+
img = Image.new("RGB", (len(freqs), tape_height + len(times)))
213221
pix = img.load()
214222
x_size = img.size[0]
215223
for line in raw_data():
@@ -237,18 +245,92 @@ def rgb3(z):
237245
# fast check for nan/-inf
238246
if not z >= min_z:
239247
z = min_z
240-
pix[x,y] = rgb2(z)
248+
pix[x,y+tape_height] = rgb2(z)
249+
250+
def closest_index(n, m_list):
251+
error = max(m_list)
252+
best = -1
253+
for i,m in enumerate(m_list):
254+
e2 = abs(m-n)
255+
if e2 > error:
256+
continue
257+
error = e2
258+
best = i
259+
return best
260+
261+
def word_aa(label, pt, fg_color, bg_color):
262+
f = ImageFont.truetype("Vera.ttf", pt*3)
263+
s = f.getsize(label)
264+
s = (s[0], int(s[1]*1.5)) # getsize lies
265+
w_img = Image.new("RGB", s, bg_color)
266+
w_draw = ImageDraw.Draw(w_img)
267+
w_draw.text((0, 0), label, font=f, fill=fg_color)
268+
return w_img.resize((s[0]//3, s[1]//3), Image.ANTIALIAS)
269+
270+
def tape_lines(interval, y1, y2, used=set()):
271+
"returns the number of lines"
272+
low_f = (min(freqs) // interval) * interval
273+
high_f = (1 + max(freqs) // interval) * interval
274+
hits = 0
275+
for i in range(int(low_f), int(high_f), int(interval)):
276+
if i in used:
277+
continue
278+
if not (min(freqs) < i < max(freqs)):
279+
continue
280+
x = closest_index(i, freqs)
281+
hits += 1
282+
draw.line([x,y1,x,y2], fill='black')
283+
used.add(i)
284+
return hits
285+
286+
def tape_text(interval, y, used=set()):
287+
low_f = (min(freqs) // interval) * interval
288+
high_f = (1 + max(freqs) // interval) * interval
289+
for i in range(int(low_f), int(high_f), int(interval)):
290+
if i in used:
291+
continue
292+
if not (min(freqs) < i < max(freqs)):
293+
continue
294+
x = closest_index(i, freqs)
295+
s = str(i)
296+
if interval >= 1e6:
297+
s = '%iM' % (i/1e6)
298+
elif interval > 1000:
299+
s = '%ik' % ((i/1e3) % 1000)
300+
else:
301+
s = '%i' % (i%1000)
302+
w = word_aa(s, tape_pt, 'black', 'yellow')
303+
img.paste(w, (x - w.size[0]//2, y))
304+
used.add(i)
241305

242306
print("labeling")
307+
tape_pt = 10
243308
draw = ImageDraw.Draw(img)
244309
font = ImageFont.load_default()
245310
pixel_width = step
246-
for label in labels:
247-
y = 10
248-
#x = freqs.index(label)
249-
x = int((label-min(freqs)) / pixel_width)
250-
s = '%.3fMHz' % (label/1000000.0)
251-
draw.text((x, y), s, font=font, fill='white')
311+
312+
draw.rectangle([0,0,img.size[0],tape_height], fill='yellow')
313+
min_freq = min(freqs)
314+
max_freq = max(freqs)
315+
delta = max_freq - min_freq
316+
width = len(freqs)
317+
label_base = 8
318+
319+
for i in range(8, 0, -1):
320+
hits = range(0, int(2500e6), int(10**i))
321+
hits = [j for j in hits if min_freq<j<max_freq]
322+
if len(hits) >= 4:
323+
label_base = i
324+
break
325+
label_base = 10**label_base
326+
327+
for scale,y in [(1,10), (5,15), (10,19), (50,22), (100,24), (500, 25)]:
328+
hits = tape_lines(label_base/scale, y, tape_height)
329+
pixels_per_hit = width / hits
330+
if pixels_per_hit > 50:
331+
tape_text(label_base/scale, y-tape_pt)
332+
if pixels_per_hit < 6:
333+
break
252334

253335
if args.time_tick:
254336
label_last = start

0 commit comments

Comments
 (0)