Quick and dirty histogramming in python
Normally I’d use R but the day job inspired me to take a look at using Qt from Python. Specifically how easy it’d be to hack up a Qt gui around matplotlib charts. Turns out to be pretty easy.
The goal is to load up some time series from a CSV file and choose from them to draw histograms. Getting the data in is straightforward:
# Load some time series from a csv file. class TimeSeries(object): def __init__(self, filename=None): self.load(filename) def load(self, filename=None): self.data = {} self.names = [] if filename: for line in csv.reader(open(filename, 'rb')): self.names.append(line[0]) self.data[line[0]] = map(int, line[1:]) self.datalen = len(line[1:]) def series(self): return self.names def length(self): return self.datalen def count(self): return len(self.data) def timeseries(self, name): return self.data[name]
And the end result, after loading in a CSV file of data, looks like this:

First, we need a whole mess of imports. This could perhaps be cleaned up but I mainly just wanted to get enough of Qt, matplotlib and numpy in.
import sys, os, csv from PyQt4.QtCore import * from PyQt4.QtGui import * import matplotlib from matplotlib.backends.backend_qt4agg \ import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt4agg \ import NavigationToolbar2QTAgg as NavBar from matplotlib.figure import Figure import numpy
All the action takes place in this code.. should be refactored really. I just crammed in a couple of matplotlib and numpy calls into the Qt code to get it up and running.
# Main window class Form(QMainWindow): def __init__(self, parent=None): super(Form, self).__init__(parent) self.setWindowTitle('Histogram of time series') self.data = TimeSeries() self.series_list_model = QStandardItemModel() self.create_menu() self.create_main_frame() self.create_status_bar() self.on_show() def load_file(self, filename=None): filename = QFileDialog.getOpenFileName(self, 'Open a file', '.', 'CSV files (*.csv);;All Files (*.*)') if filename: self.data.load(filename) self.fill_series_list(self.data.series()) self.status_text.setText("Loaded " + filename) def on_show(self): self.axes.clear() self.axes.grid(True) has_series = False for row in range(self.series_list_model.rowCount()): model_index = self.series_list_model.index(row, 0) checked = self.series_list_model.data(model_index, Qt.CheckStateRole) == QVariant(Qt.Checked) name = str(self.series_list_model.data(model_index).toString()) if checked: has_series = True series = self.data.timeseries(name) maxval = numpy.max(series) bins = numpy.arange(0, maxval, 5) self.axes.hist(series, bins) self.axes.axis(xmax=maxval) self.canvas.draw() def fill_series_list(self, names): self.series_list_model.clear() for name in names: item = QStandardItem(name) item.setCheckState(Qt.Unchecked) item.setCheckable(True) self.series_list_model.appendRow(item) def create_main_frame(self): self.main_frame = QWidget() plot_frame = QWidget() self.dpi = 100 self.fig = Figure((6.0, 4.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.main_frame) self.axes = self.fig.add_subplot(111) self.mpl_toolbar = NavBar(self.canvas, self.main_frame) log_label = QLabel("Data series:") self.series_list_view = QListView() self.series_list_view.setModel(self.series_list_model) self.show_button = QPushButton("&Show") self.connect(self.show_button, SIGNAL('clicked()'), self.on_show) left_vbox = QVBoxLayout() left_vbox.addWidget(self.canvas) left_vbox.addWidget(self.mpl_toolbar) right_vbox = QVBoxLayout() right_vbox.addWidget(log_label) right_vbox.addWidget(self.series_list_view) right_vbox.addWidget(self.show_button) right_vbox.addStretch(1) hbox = QHBoxLayout() hbox.addLayout(left_vbox) hbox.addLayout(right_vbox) self.main_frame.setLayout(hbox) self.setCentralWidget(self.main_frame) def create_status_bar(self): self.status_text = QLabel("Load a data file to begin") self.statusBar().addWidget(self.status_text, 1) def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") load_action = self.create_action("&Load file", shortcut="Ctrl+L", slot=self.load_file, tip="Load a file") quit_action = self.create_action("&Quit", slot=self.close, shortcut="Ctrl+Q", tip="Close the application") self.add_actions(self.file_menu, (load_action, None, quit_action)) def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action
And finally the de rigueur main program to drive it:
# main def main(): app = QApplication(sys.argv) form = Form() form.show() app.exec_() if __name__ == "__main__": main()
