Skip to content

Commit 59bd6db

Browse files
committed
open source work
1 parent cded03a commit 59bd6db

File tree

6 files changed

+622
-32
lines changed

6 files changed

+622
-32
lines changed

bashplotlib/histogram.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def run_demo():
8888
plot_hist(demo_file, height=35.0, bincount=40)
8989

9090

91-
def plot_hist(f, height=20.0, bincount=None, binwidth=None, pch="o", colour="default", title="", xlab=None, showSummary=False, regular=False):
91+
def plot_hist(f, height=20.0, bincount=None, binwidth=None, pch="o", colour="default", title="", xlab=None, showSummary=False, regular=False, xtitle=None, ytitle=None):
9292
"""
9393
Make a histogram
9494
@@ -159,9 +159,13 @@ def plot_hist(f, height=20.0, bincount=None, binwidth=None, pch="o", colour="def
159159
nlen = max(len(str(min_y)), len(str(max_y))) + 1
160160

161161
if title:
162-
print(box_text(title, max(len(hist) * 2, len(title)), nlen))
162+
print(box_text([title], max(len(hist) * 2, len(title)), nlen))
163163
print()
164164

165+
if ytitle:
166+
print(" " + "y: "+ ytitle + "\n")
167+
# return_string += "y: "+ ytitle + "\n"
168+
165169
used_labs = set()
166170
for y in ys:
167171
ylab = str(int(y))
@@ -197,22 +201,31 @@ def plot_hist(f, height=20.0, bincount=None, binwidth=None, pch="o", colour="def
197201
else:
198202
print(" ", end=' ')
199203
print('')
204+
if xtitle:
205+
full_title = "x: "+ xtitle
206+
print(" " * ((nlen + 1) + len(xs) - len(full_title)) + full_title + "\n")
207+
# return_string += " " * (xs - len(full_title)) + full_title + "\n"
200208

201209
center = max(map(len, map(str, [n, min_val, mean, max_val])))
202210
center += 15
203211

204212
if showSummary:
205213
print()
206-
print("-" * (2 + center))
207-
print("|" + "Summary".center(center) + "|")
208-
print("-" * (2 + center))
209-
summary = "|" + ("observations: %d" % n).center(center) + "|\n"
210-
summary += "|" + ("min value: %f" % min_val).center(center) + "|\n"
211-
summary += "|" + ("mean : %f" % mean).center(center) + "|\n"
212-
summary += "|" + ("std dev : %f" % sd).center(center) + "|\n"
213-
summary += "|" + ("max value: %f" % max_val).center(center) + "|\n"
214-
summary += "-" * (2 + center)
215-
print(summary)
214+
title = ["Summary"]
215+
print(box_text(title, max(len(hist) * 2, len(title)), nlen))
216+
stats = ["observations: %d" % n, "min value: %f" % min_val,
217+
"mean : %f" % mean, "std dev : %f" % sd, "max value: %f" % max_val]
218+
print(box_text(stats, max(len(hist) * 2, len(title)), nlen))
219+
# print("-" * (2 + center))
220+
# print("|" + "Summary".center(center) + "|")
221+
# print("-" * (2 + center))
222+
# summary = "|" + ("observations: %d" % n).center(center) + "|\n"
223+
# summary += "|" + ("min value: %f" % min_val).center(center) + "|\n"
224+
# summary += "|" + ("mean : %f" % mean).center(center) + "|\n"
225+
# summary += "|" + ("std dev : %f" % sd).center(center) + "|\n"
226+
# summary += "|" + ("max value: %f" % max_val).center(center) + "|\n"
227+
# summary += "-" * (2 + center)
228+
# print(summary)
216229

217230

218231
def main():
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
Plotting terminal based histograms
6+
"""
7+
8+
from __future__ import print_function
9+
from __future__ import division
10+
11+
import os
12+
import sys
13+
import math
14+
import optparse
15+
from os.path import dirname
16+
from .utils.helpers import *
17+
from .utils.commandhelp import hist
18+
19+
20+
def calc_bins(n, min_val, max_val, h=None, binwidth=None):
21+
"""
22+
Calculate number of bins for the histogram
23+
"""
24+
if not h:
25+
h = max(10, math.log(n + 1, 2))
26+
if binwidth == 0:
27+
binwidth = 0.1
28+
if binwidth is None:
29+
binwidth = (max_val - min_val) / h
30+
for b in drange(min_val, max_val, step=binwidth, include_stop=True):
31+
if b.is_integer():
32+
yield int(b)
33+
else:
34+
yield b
35+
36+
37+
def read_numbers(numbers):
38+
"""
39+
Read the input data in the most optimal way
40+
"""
41+
if isiterable(numbers):
42+
for number in numbers:
43+
yield float(str(number).strip())
44+
else:
45+
with open(numbers) as fh:
46+
for number in fh:
47+
yield float(number.strip())
48+
49+
50+
def run_demo():
51+
"""
52+
Run a demonstration
53+
"""
54+
module_dir = dirname(dirname(os.path.realpath(__file__)))
55+
demo_file = os.path.join(module_dir, 'examples/data/exp.txt')
56+
57+
if not os.path.isfile(demo_file):
58+
sys.stderr.write("demo input file not found!\n")
59+
sys.stderr.write("run the downloaddata.sh script in the example first\n")
60+
sys.exit(1)
61+
62+
# plotting a histogram
63+
print("plotting a basic histogram")
64+
print("plot_horiz_hist('%s')" % demo_file)
65+
print("hist -f %s" % demo_file)
66+
print("cat %s | hist" % demo_file)
67+
plot_horiz_hist(demo_file)
68+
print("*" * 80)
69+
70+
# with colours
71+
print("histogram with colours")
72+
print("plot_horiz_hist('%s', colour='blue')" % demo_file)
73+
print("hist -f %s -c blue" % demo_file)
74+
plot_horiz_hist(demo_file, colour='blue')
75+
print("*" * 80)
76+
77+
# changing the shape of the point
78+
print("changing the shape of the bars")
79+
print("plot_horiz_hist('%s', pch='.')" % demo_file)
80+
print("hist -f %s -p ." % demo_file)
81+
plot_horiz_hist(demo_file, pch='.')
82+
print("*" * 80)
83+
84+
# changing the size of the plot
85+
print("changing the size of the plot")
86+
print("plot_horiz_hist('%s', width=35.0, bincount=40)" % demo_file)
87+
print("hist -f %s -s 35.0 -b 40" % demo_file)
88+
plot_horiz_hist(demo_file, width=35.0, bincount=40)
89+
90+
91+
def plot_horiz_hist(f, width=20.0, bincount=None, binwidth=None, pch="o", colour="default", title="", xlab=None, showSummary=False, regular=False, xtitle=None, ytitle=None):
92+
"""
93+
Make a histogram
94+
95+
Arguments:
96+
width -- the width of the histogram in # of characters
97+
bincount -- number of bins in the histogram
98+
binwidth -- width of bins in the histogram
99+
pch -- shape of the bars in the plot
100+
colour -- colour of the bars in the terminal
101+
title -- title at the top of the plot
102+
xlab -- boolen value for whether or not to display x-axis labels
103+
showSummary -- boolean value for whether or not to display a summary
104+
regular -- boolean value for whether or not to start y-labels at 0
105+
"""
106+
if pch is None:
107+
pch = "o"
108+
109+
if isinstance(f, str):
110+
with open(f) as fh:
111+
f = fh.readlines()
112+
113+
min_val, max_val = None, None
114+
n, mean, sd = 0.0, 0.0, 0.0
115+
116+
for number in read_numbers(f):
117+
n += 1
118+
if min_val is None or number < min_val:
119+
min_val = number
120+
if max_val is None or number > max_val:
121+
max_val = number
122+
mean += number
123+
124+
mean /= n
125+
126+
for number in read_numbers(f):
127+
sd += (mean - number)**2
128+
129+
sd /= (n - 1)
130+
sd **= 0.5
131+
132+
bins = list(calc_bins(n, min_val, max_val, bincount, binwidth))
133+
hist = dict((i, 0) for i in range(len(bins)))
134+
135+
for number in read_numbers(f):
136+
for i, b in enumerate(bins):
137+
if number <= b:
138+
hist[i] += 1
139+
break
140+
if number == max_val and max_val > bins[len(bins) - 1]:
141+
hist[len(hist) - 1] += 1
142+
143+
min_y, max_y = min(hist.values()), max(hist.values())
144+
145+
start = max(min_y, 1)
146+
stop = max_y + 1
147+
148+
if regular:
149+
start = 1
150+
151+
if width is None:
152+
width = stop - start
153+
if width > 20:
154+
width = 20
155+
156+
ys = list(drange(start, stop, float(stop - start) / width))
157+
ys.reverse()
158+
159+
nlen = max(len(str(min_y)), len(str(max_y))) + 1
160+
161+
max_bin, min_bin = min(hist.keys()), max(hist.keys())
162+
binlen = max(len(str(min_bin)), len(str(max_bin)))
163+
164+
if title:
165+
print(box_text([title], max(len(hist) * 2, len(title)), nlen))
166+
print()
167+
168+
if xtitle:
169+
print(" " + "x: "+ xtitle )
170+
# return_string += "y: "+ ytitle + "\n"
171+
172+
173+
start = min_val
174+
stop = max_val + 1
175+
num_buckets = 11
176+
xs = list(drange(start, stop, float(stop - start) / num_buckets))
177+
178+
if xlab:
179+
index = 0
180+
for x in xs:
181+
binlab = str(int(x))
182+
binlab = " " * (binlen - len(binlab)) + binlab + "|"
183+
print(binlab, end=' ')
184+
185+
bin_sum = 0
186+
for i in hist.keys():
187+
if i >= index and i <= x:
188+
bin_sum += hist[i]
189+
index = i + 1
190+
191+
for y in ys:
192+
if bin_sum >= y:
193+
printcolour(pch, True, colour)
194+
print('')
195+
196+
print(" " * (nlen + 1) + "-" * len(ys))
197+
198+
used_labs = set()
199+
# print(" " * (binlen + 1))
200+
y_master_label = " " * (binlen + 1)
201+
202+
power_of_ten = 1
203+
while power_of_ten < max_y:
204+
power_of_ten *= 10
205+
206+
current_power = 10
207+
while index * 10
208+
for y in ys:
209+
if y > current_power * 10:
210+
current_power *= 10
211+
if y < current_power:
212+
y_master_label += str(y) + " "
213+
else:
214+
y_master_label += str(y/current_power) + " "
215+
while power_of_ten > 0:
216+
labels = []
217+
218+
# print(ys)
219+
for lab in labels:
220+
ylab = lab
221+
if ylab in used_labs:
222+
ylab = ""
223+
else:
224+
used_labs.add(ylab)
225+
y_master_label += " " + ylab
226+
print(y_master_label)
227+
228+
# print(ylab, end=' ')
229+
230+
# for i in range(len(hist)):
231+
# if int(y) <= hist[i]:
232+
# printcolour(pch, True, colour)
233+
# else:
234+
# printcolour(" ", True, colour)
235+
# print('')
236+
# xs = hist.keys()
237+
238+
# print(" " * (nlen) + "+" + "-" * len(xs))
239+
240+
# if xlab:
241+
# labels = abbreviate([str(y) for y in ys])
242+
# xlen = len(labels[0])
243+
# for i in range(0, xlen):
244+
# printcolour(" " * (nlen + 1), True, colour)
245+
# for x in range(0, len(hist)):
246+
# num = labels[x]
247+
# if x % 2 != 0:
248+
# pass
249+
# elif i < len(num):
250+
# print(num[i], end=' ')
251+
# else:
252+
# print(" ", end=' ')
253+
# print('')
254+
if ytitle:
255+
full_title = "y: "+ ytitle
256+
print(" " * ((nlen + 1) + len(xs) - len(full_title)) + full_title)
257+
# return_string += " " * (xs - len(full_title)) + full_title + "\n"
258+
259+
center = max(map(len, map(str, [n, min_val, mean, max_val])))
260+
center += 15
261+
262+
if showSummary:
263+
print()
264+
title = ["Summary"]
265+
print(box_text(title, max(len(hist) * 2, len(title)), nlen))
266+
stats = ["observations: %d" % n, "min value: %f" % min_val,
267+
"mean : %f" % mean, "std dev : %f" % sd, "max value: %f" % max_val]
268+
print(box_text(stats, max(len(hist) * 2, len(title)), nlen))
269+
# print("-" * (2 + center))
270+
# print("|" + "Summary".center(center) + "|")
271+
# print("-" * (2 + center))
272+
# summary = "|" + ("observations: %d" % n).center(center) + "|\n"
273+
# summary += "|" + ("min value: %f" % min_val).center(center) + "|\n"
274+
# summary += "|" + ("mean : %f" % mean).center(center) + "|\n"
275+
# summary += "|" + ("std dev : %f" % sd).center(center) + "|\n"
276+
# summary += "|" + ("max value: %f" % max_val).center(center) + "|\n"
277+
# summary += "-" * (2 + center)
278+
# print(summary)
279+
280+
281+
def main():
282+
283+
parser = optparse.OptionParser(usage=hist['usage'])
284+
285+
parser.add_option(
286+
'-f', '--file', help='a file containing a column of numbers', default=None, dest='f')
287+
parser.add_option('-t', '--title', help='title for the chart', default="", dest='t')
288+
parser.add_option(
289+
'-b', '--bins', help='number of bins in the histogram', type='int', default=None, dest='b')
290+
parser.add_option('-w', '--binwidth', help='width of bins in the histogram',
291+
type='float', default=None, dest='binwidth')
292+
parser.add_option('-s', '--width', help='width of the histogram (in lines)',
293+
type='int', default=None, dest='h')
294+
parser.add_option('-p', '--pch', help='shape of each bar', default='o', dest='p')
295+
parser.add_option('-x', '--xlab', help='label bins on x-axis',
296+
default=None, action="store_true", dest='x')
297+
parser.add_option('-c', '--colour', help='colour of the plot (%s)' %
298+
colour_help, default='default', dest='colour')
299+
parser.add_option('-d', '--demo', help='run demos', action='store_true', dest='demo')
300+
parser.add_option('-n', '--nosummary', help='hide summary',
301+
action='store_false', dest='showSummary', default=True)
302+
parser.add_option('-r', '--regular',
303+
help='use regular y-scale (0 - maximum y value), instead of truncated y-scale (minimum y-value - maximum y-value)',
304+
default=False, action="store_true", dest='regular')
305+
306+
opts, args = parser.parse_args()
307+
308+
if opts.f is None:
309+
if len(args) > 0:
310+
opts.f = args[0]
311+
elif opts.demo is None or opts.demo is False:
312+
opts.f = sys.stdin.readlines()
313+
314+
if opts.demo:
315+
run_demo()
316+
elif opts.f:
317+
plot_hist(opts.f, opts.h, opts.b, opts.binwidth, opts.p, opts.colour,
318+
opts.t, opts.x, opts.showSummary, opts.regular)
319+
else:
320+
print("nothing to plot!")
321+
322+
323+
if __name__ == "__main__":
324+
main()

0 commit comments

Comments
 (0)