summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rondeau <tom@trondeau.com>2013-10-22 14:03:39 -0400
committerTom Rondeau <tom@trondeau.com>2013-10-29 12:23:09 -0400
commitccb5384d759d8736e596574be770ad36222ef4a1 (patch)
treec5a5a544b09c53890fe199044b9fee7c9de73dc7
parentdaac8bc5f7c41afa678935344ef25f4f92206b3e (diff)
qtgui: fixed histogram autoscaling features. Added example script.
-rw-r--r--gr-qtgui/examples/CMakeLists.txt1
-rwxr-xr-xgr-qtgui/examples/pyqt_histogram_f.py200
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h13
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h46
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h6
-rw-r--r--gr-qtgui/lib/HistogramDisplayPlot.cc133
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.cc6
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.h1
-rw-r--r--gr-qtgui/lib/histogramdisplayform.cc44
9 files changed, 368 insertions, 82 deletions
diff --git a/gr-qtgui/examples/CMakeLists.txt b/gr-qtgui/examples/CMakeLists.txt
index 700ea027c7..8d3b29957b 100644
--- a/gr-qtgui/examples/CMakeLists.txt
+++ b/gr-qtgui/examples/CMakeLists.txt
@@ -25,6 +25,7 @@ GR_PYTHON_INSTALL(PROGRAMS
pyqt_example_f.py
pyqt_freq_c.py
pyqt_freq_f.py
+ pyqt_histogram_f.py
pyqt_time_c.py
pyqt_time_f.py
pyqt_time_raster_b.py
diff --git a/gr-qtgui/examples/pyqt_histogram_f.py b/gr-qtgui/examples/pyqt_histogram_f.py
new file mode 100755
index 0000000000..7bdcbfcb99
--- /dev/null
+++ b/gr-qtgui/examples/pyqt_histogram_f.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr
+from gnuradio import blocks
+import sys
+
+try:
+ from gnuradio import qtgui
+ from PyQt4 import QtGui, QtCore
+ import sip
+except ImportError:
+ sys.stderr.write("Error: Program requires PyQt4 and gr-qtgui.\n")
+ sys.exit(1)
+
+try:
+ from gnuradio import analog
+except ImportError:
+ sys.stderr.write("Error: Program requires gr-analog.\n")
+ sys.exit(1)
+
+class dialog_box(QtGui.QWidget):
+ def __init__(self, display, control):
+ QtGui.QWidget.__init__(self, None)
+ self.setWindowTitle('PyQt Test GUI')
+
+ self.boxlayout = QtGui.QBoxLayout(QtGui.QBoxLayout.LeftToRight, self)
+ self.boxlayout.addWidget(display, 1)
+ self.boxlayout.addWidget(control)
+
+ self.resize(800, 500)
+
+class control_box(QtGui.QWidget):
+ def __init__(self, snk, parent=None):
+ QtGui.QWidget.__init__(self, parent)
+ self.setWindowTitle('Control Panel')
+ self.snk = snk
+
+ self.setToolTip('Control the signals')
+ QtGui.QToolTip.setFont(QtGui.QFont('OldEnglish', 10))
+
+ self.layout = QtGui.QFormLayout(self)
+
+ # Control the first signal
+ self.freq1Edit = QtGui.QLineEdit(self)
+ self.freq1Edit.setMinimumWidth(100)
+ self.layout.addRow("Sine Frequency:", self.freq1Edit)
+ self.connect(self.freq1Edit, QtCore.SIGNAL("editingFinished()"),
+ self.freq1EditText)
+
+ self.amp1Edit = QtGui.QLineEdit(self)
+ self.amp1Edit.setMinimumWidth(100)
+ self.layout.addRow("Sine Amplitude:", self.amp1Edit)
+ self.connect(self.amp1Edit, QtCore.SIGNAL("editingFinished()"),
+ self.amp1EditText)
+
+
+ # Control the second signal
+ self.amp2Edit = QtGui.QLineEdit(self)
+ self.amp2Edit.setMinimumWidth(100)
+ self.layout.addRow("Noise Amplitude:", self.amp2Edit)
+ self.connect(self.amp2Edit, QtCore.SIGNAL("editingFinished()"),
+ self.amp2EditText)
+
+ # Control the histogram
+ self.hist_npts = QtGui.QLineEdit(self)
+ self.hist_npts.setMinimumWidth(100)
+ self.hist_npts.setValidator(QtGui.QIntValidator(0, 8191))
+ self.hist_npts.setText("{0}".format(self.snk.nsamps()))
+ self.layout.addRow("Number of Points:", self.hist_npts)
+ self.connect(self.hist_npts, QtCore.SIGNAL("editingFinished()"),
+ self.set_nsamps)
+
+ self.hist_bins = QtGui.QLineEdit(self)
+ self.hist_bins.setMinimumWidth(100)
+ self.hist_bins.setValidator(QtGui.QIntValidator(0, 1000))
+ self.hist_bins.setText("{0}".format(self.snk.bins()))
+ self.layout.addRow("Number of Bins:", self.hist_bins)
+ self.connect(self.hist_bins, QtCore.SIGNAL("editingFinished()"),
+ self.set_bins)
+
+ self.hist_auto = QtGui.QPushButton("scale", self)
+ self.layout.addRow("Autoscale X:", self.hist_auto)
+ self.connect(self.hist_auto, QtCore.SIGNAL("pressed()"),
+ self.autoscalex)
+
+ self.quit = QtGui.QPushButton('Close', self)
+ self.quit.setMinimumWidth(100)
+ self.layout.addWidget(self.quit)
+
+ self.connect(self.quit, QtCore.SIGNAL('clicked()'),
+ QtGui.qApp, QtCore.SLOT('quit()'))
+
+
+ def attach_signal1(self, signal):
+ self.signal1 = signal
+ self.freq1Edit.setText(QtCore.QString("%1").arg(self.signal1.frequency()))
+ self.amp1Edit.setText(QtCore.QString("%1").arg(self.signal1.amplitude()))
+
+ def attach_signal2(self, signal):
+ self.signal2 = signal
+ self.amp2Edit.setText(QtCore.QString("%1").arg(self.signal2.amplitude()))
+
+ def freq1EditText(self):
+ try:
+ newfreq = float(self.freq1Edit.text())
+ self.signal1.set_frequency(newfreq)
+ except ValueError:
+ print "Bad frequency value entered"
+
+ def amp1EditText(self):
+ try:
+ newamp = float(self.amp1Edit.text())
+ self.signal1.set_amplitude(newamp)
+ except ValueError:
+ print "Bad amplitude value entered"
+
+ def amp2EditText(self):
+ try:
+ newamp = float(self.amp2Edit.text())
+ self.signal2.set_amplitude(newamp)
+ except ValueError:
+ print "Bad amplitude value entered"
+
+ def set_nsamps(self):
+ res = self.hist_npts.text().toInt()
+ if(res[1]):
+ self.snk.set_nsamps(res[0])
+
+ def set_bins(self):
+ res = self.hist_bins.text().toInt()
+ if(res[1]):
+ self.snk.set_bins(res[0])
+
+ def autoscalex(self):
+ self.snk.autoscalex()
+
+
+class my_top_block(gr.top_block):
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ Rs = 8000
+ f1 = 100
+
+ npts = 2048
+
+ self.qapp = QtGui.QApplication(sys.argv)
+
+ src1 = analog.sig_source_f(Rs, analog.GR_SIN_WAVE, f1, 0, 0)
+ src2 = analog.noise_source_f(analog.GR_GAUSSIAN, 1)
+ src = blocks.add_ff()
+ thr = blocks.throttle(gr.sizeof_float, 100*npts)
+ self.snk1 = qtgui.histogram_sink_f(npts, 200, -5, 5,
+ "Histogram")
+
+ self.connect(src1, (src,0))
+ self.connect(src2, (src,1))
+ self.connect(src, thr, self.snk1)
+
+ self.ctrl_win = control_box(self.snk1)
+ self.ctrl_win.attach_signal1(src1)
+ self.ctrl_win.attach_signal2(src2)
+
+ # Get the reference pointer to the SpectrumDisplayForm QWidget
+ pyQt = self.snk1.pyqwidget()
+
+ # Wrap the pointer as a PyQt SIP object
+ # This can now be manipulated as a PyQt4.QtGui.QWidget
+ pyWin = sip.wrapinstance(pyQt, QtGui.QWidget)
+
+ #pyWin.show()
+ self.main_box = dialog_box(pyWin, self.ctrl_win)
+ self.main_box.show()
+
+if __name__ == "__main__":
+ tb = my_top_block();
+ tb.start()
+ tb.qapp.exec_()
+ tb.stop()
+
diff --git a/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h
index bcf7272691..04b23ee27c 100644
--- a/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h
+++ b/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h
@@ -47,6 +47,7 @@ public:
public slots:
void setAutoScale(bool state);
+ void setAutoScaleX();
void setSemilogx(bool en);
void setSemilogy(bool en);
void setAccumulate(bool en);
@@ -56,19 +57,23 @@ public slots:
void setLineColor(int which, QColor color);
void setNumBins(int bins);
+ void setXaxis(double min, double max);
private:
- void _resetXAxisPoints(double bottom, double top);
- void _autoScale(double bottom, double top);
+ void _resetXAxisPoints(double left, double right);
+ void _autoScaleY(double bottom, double top);
double* _xAxisPoints;
std::vector<double*> _yDataPoints;
- int _bins;
- bool _accum;
+ int d_bins;
+ bool d_accum;
+ double d_xmin, d_xmax, d_left, d_right;
+ double d_width;
bool d_semilogx;
bool d_semilogy;
+ bool _autoscalex_state;
};
#endif /* HISTOGRAM_DISPLAY_PLOT_H */
diff --git a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
index 82fbca64f5..193c786bd9 100644
--- a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
@@ -39,6 +39,24 @@ namespace gr {
* \details
* This is a QT-based graphical sink the displays a histogram of
* the data.
+ *
+ * This histogram allows you to set and change at runtime the
+ * number of points to plot at once and the number of bins in the
+ * histogram. Both x and y-axis have their own auto-scaling
+ * behavior. By default, auto-scaling the y-axis is turned on and
+ * continuously updates the y-axis max value based on the
+ * currently plotted histogram.
+ *
+ * The x-axis auto-scaling function only updates once when
+ * clicked. This resets the x-axis to the current range of minimum
+ * and maximum values represented in the histogram. It resets any
+ * values currently displayed because the location and width of
+ * the bins may have changed.
+ *
+ * The histogram also has an accumulate function that simply
+ * accumulates the data between calls to work. When accumulate is
+ * activated, the y-axis autoscaling is turned on by default as
+ * the values will quickly grow in the this direction.
*/
class QTGUI_API histogram_sink_f : virtual public sync_block
{
@@ -66,19 +84,7 @@ namespace gr {
virtual void exec_() = 0;
virtual PyObject* pyqwidget() = 0;
- virtual void set_y_axis(double min, double max) = 0;
- virtual void set_x_axis(double min, double max) = 0;
- virtual void set_update_time(double t) = 0;
- virtual void set_title(const std::string &title) = 0;
- virtual void set_line_label(int which, const std::string &line) = 0;
- virtual void set_line_color(int which, const std::string &color) = 0;
- virtual void set_line_width(int which, int width) = 0;
- virtual void set_line_style(int which, int style) = 0;
- virtual void set_line_marker(int which, int marker) = 0;
- virtual void set_line_alpha(int which, double alpha) = 0;
- virtual void set_nsamps(const int newsize) = 0;
- virtual void set_bins(const int bins) = 0;
-
+ public:
virtual std::string title() = 0;
virtual std::string line_label(int which) = 0;
virtual std::string line_color(int which) = 0;
@@ -95,11 +101,25 @@ namespace gr {
virtual void enable_semilogx(bool en=true) = 0;
virtual void enable_semilogy(bool en=true) = 0;
virtual void enable_accumulate(bool en=true) = 0;
+ virtual void autoscalex() = 0;
virtual int nsamps() const = 0;
virtual int bins() const = 0;
virtual void reset() = 0;
QApplication *d_qApplication;
+
+ virtual void set_y_axis(double min, double max) = 0;
+ virtual void set_x_axis(double min, double max) = 0;
+ virtual void set_update_time(double t) = 0;
+ virtual void set_title(const std::string &title) = 0;
+ virtual void set_line_label(int which, const std::string &line) = 0;
+ virtual void set_line_color(int which, const std::string &color) = 0;
+ virtual void set_line_width(int which, int width) = 0;
+ virtual void set_line_style(int which, int style) = 0;
+ virtual void set_line_marker(int which, int marker) = 0;
+ virtual void set_line_alpha(int which, double alpha) = 0;
+ virtual void set_nsamps(const int newsize) = 0;
+ virtual void set_bins(const int bins) = 0;
};
} /* namespace qtgui */
diff --git a/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h b/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h
index b1a242ed99..6766b66741 100644
--- a/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h
+++ b/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h
@@ -58,6 +58,7 @@ public slots:
void setNumBins(const int);
void setAccumulate(bool en);
+ void autoScaleX();
private slots:
void newData(const QEvent*);
@@ -73,8 +74,13 @@ private:
bool d_semilogx;
bool d_semilogy;
+ NPointsMenu *d_nptsmenu;
+ NPointsMenu *d_nbinsmenu;
QAction *d_semilogxmenu;
QAction *d_semilogymenu;
+
+ QAction *_autoscalex_act;
+ bool _autoscalex_state;
};
#endif /* HISTOGRAM_DISPLAY_FORM_H */
diff --git a/gr-qtgui/lib/HistogramDisplayPlot.cc b/gr-qtgui/lib/HistogramDisplayPlot.cc
index bcdab6b3f4..68b7d8c3ab 100644
--- a/gr-qtgui/lib/HistogramDisplayPlot.cc
+++ b/gr-qtgui/lib/HistogramDisplayPlot.cc
@@ -114,12 +114,12 @@ private:
HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent)
: DisplayPlot(nplots, parent)
{
- _bins = 100;
- _accum = false;
+ d_bins = 100;
+ d_accum = false;
// Initialize x-axis data array
- _xAxisPoints = new double[_bins];
- memset(_xAxisPoints, 0x0, _bins*sizeof(double));
+ _xAxisPoints = new double[d_bins];
+ memset(_xAxisPoints, 0x0, d_bins*sizeof(double));
_zoomer = new HistogramDisplayZoomer(canvas(), 0);
@@ -136,18 +136,17 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent)
_zoomer->setRubberBandPen(c);
_zoomer->setTrackerPen(c);
- _magnifier->setAxisEnabled(QwtPlot::xBottom, true);
- _magnifier->setAxisEnabled(QwtPlot::yLeft, false);
-
d_semilogx = false;
d_semilogy = false;
+ _autoscale_state = true;
+ _autoscalex_state = false;
setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
setXaxis(-1, 1);
setAxisTitle(QwtPlot::xBottom, "Value");
setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
- setYaxis(-2.0, _bins);
+ setYaxis(-2.0, d_bins);
setAxisTitle(QwtPlot::yLeft, "Count");
QList<QColor> colors;
@@ -159,8 +158,8 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent)
// Setup dataPoints and plot vectors
// Automatically deleted when parent is deleted
for(int i = 0; i < _nplots; i++) {
- _yDataPoints.push_back(new double[_bins]);
- memset(_yDataPoints[i], 0, _bins*sizeof(double));
+ _yDataPoints.push_back(new double[d_bins]);
+ memset(_yDataPoints[i], 0, d_bins*sizeof(double));
_plot_curve.push_back(new QwtPlotCurve(QString("Data %1").arg(i)));
_plot_curve[i]->attach(this);
@@ -176,10 +175,10 @@ HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent)
QPen(colors[i]), QSize(7,7));
#if QWT_VERSION < 0x060000
- _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], _bins);
+ _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], d_bins);
_plot_curve[i]->setSymbol(*symbol);
#else
- _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], _bins);
+ _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], d_bins);
_plot_curve[i]->setSymbol(symbol);
#endif
}
@@ -210,37 +209,41 @@ HistogramDisplayPlot::plotNewData(const std::vector<double*> dataPoints,
if(!_stop) {
if((numDataPoints > 0)) {
- double bottom = *std::min_element(dataPoints[0], dataPoints[0]+numDataPoints);
- double top = *std::max_element(dataPoints[0], dataPoints[0]+numDataPoints);
- for(int n = 1; n < _nplots; n++) {
- bottom = std::min(bottom, *std::min_element(dataPoints[n], dataPoints[n]+numDataPoints));
- top = std::max(top, *std::max_element(dataPoints[n], dataPoints[n]+numDataPoints));
+ // keep track of the min/max values for when autoscaleX is called.
+ d_xmin = 1e20;
+ d_xmax = -1e20;
+ for(int n = 0; n < _nplots; n++) {
+ d_xmin = std::min(d_xmin, *std::min_element(dataPoints[n], dataPoints[n]+numDataPoints));
+ d_xmax = std::max(d_xmax, *std::max_element(dataPoints[n], dataPoints[n]+numDataPoints));
}
- _resetXAxisPoints(bottom, top);
+ // If autoscalex has been clicked, clear the data for the new
+ // bin widths and reset the x-axis.
+ if(_autoscalex_state) {
+ for(int n = 0; n < _nplots; n++)
+ memset(_yDataPoints[n], 0, d_bins*sizeof(double));
+ _resetXAxisPoints(d_xmin, d_xmax);
+ _autoscalex_state = false;
+ }
int index;
- double width = (top - bottom)/(_bins-1);
-
- // Something's wrong with the data (NaN, Inf, or something else)
- if((bottom == top) || (bottom > top))
- return;
-
for(int n = 0; n < _nplots; n++) {
- if(!_accum)
- memset(_yDataPoints[n], 0, _bins*sizeof(double));
+ if(!d_accum)
+ memset(_yDataPoints[n], 0, d_bins*sizeof(double));
for(int64_t point = 0; point < numDataPoints; point++) {
- index = boost::math::iround(1e-20 + (dataPoints[n][point] - bottom)/width);
- index = std::max(std::min(index, _bins), 0);
- _yDataPoints[n][static_cast<int>(index)] += 1;
+ index = boost::math::iround(1e-20 + (dataPoints[n][point] - d_left)/d_width);
+ if((index >= 0) && (index < d_bins))
+ _yDataPoints[n][static_cast<int>(index)] += 1;
}
}
- double height = *std::max_element(_yDataPoints[0], _yDataPoints[0]+_bins);
+ double height = *std::max_element(_yDataPoints[0], _yDataPoints[0]+d_bins);
for(int n = 1; n < _nplots; n++) {
- height = std::max(height, *std::max_element(_yDataPoints[n], _yDataPoints[n]+_bins));
+ height = std::max(height, *std::max_element(_yDataPoints[n], _yDataPoints[n]+d_bins));
}
- _autoScale(0, height);
+
+ if(_autoscale_state)
+ _autoScaleY(0, height);
replot();
}
@@ -248,57 +251,71 @@ HistogramDisplayPlot::plotNewData(const std::vector<double*> dataPoints,
}
void
-HistogramDisplayPlot::_resetXAxisPoints(double bottom, double top)
+HistogramDisplayPlot::setXaxis(double min, double max)
{
- double width = (top - bottom)/(_bins-1);
- for(long loc = 0; loc < _bins; loc++){
- _xAxisPoints[loc] = bottom + loc*width;
- }
+ _resetXAxisPoints(min, max);
+}
- if(!_autoscale_state) {
- bottom = axisScaleDiv(QwtPlot::xBottom)->lowerBound();
- top = axisScaleDiv(QwtPlot::xBottom)->upperBound();
+void
+HistogramDisplayPlot::_resetXAxisPoints(double left, double right)
+{
+ // Something's wrong with the data (NaN, Inf, or something else)
+ if((left == right) || (left > right))
+ throw std::runtime_error("HistogramDisplayPlot::_resetXAxisPoints left and/or right values are invalid");
+
+ d_left = left *(1 - copysign(0.1, left));
+ d_right = right*(1 + copysign(0.1, right));
+ d_width = (d_right - d_left)/(d_bins);
+ for(long loc = 0; loc < d_bins; loc++){
+ _xAxisPoints[loc] = d_left + loc*d_width;
}
+ axisScaleDiv(QwtPlot::xBottom)->setInterval(d_left, d_right);
// Set up zoomer base for maximum unzoom x-axis
// and reset to maximum unzoom level
QwtDoubleRect zbase = _zoomer->zoomBase();
if(d_semilogx) {
- setAxisScale(QwtPlot::xBottom, 1e-1, top);
+ setAxisScale(QwtPlot::xBottom, 1e-1, d_right);
zbase.setLeft(1e-1);
}
else {
- setAxisScale(QwtPlot::xBottom, bottom, top);
- zbase.setLeft(bottom);
+ setAxisScale(QwtPlot::xBottom, d_left, d_right);
+ zbase.setLeft(d_left);
}
- zbase.setRight(top);
+ zbase.setRight(d_right);
_zoomer->zoom(zbase);
_zoomer->setZoomBase(zbase);
_zoomer->zoom(0);
}
void
-HistogramDisplayPlot::_autoScale(double bottom, double top)
+HistogramDisplayPlot::_autoScaleY(double bottom, double top)
{
// Auto scale the y-axis with a margin of 20% (10 dB for log scale)
- double _bot = bottom - fabs(bottom)*0.20;
- double _top = top + fabs(top)*0.20;
+ double b = bottom - fabs(bottom)*0.20;
+ double t = top + fabs(top)*0.20;
if(d_semilogy) {
if(bottom > 0) {
- setYaxis(_bot-10, _top+10);
+ setYaxis(b-10, t+10);
}
else {
- setYaxis(1e-3, _top+10);
+ setYaxis(1e-3, t+10);
}
}
else {
- setYaxis(_bot, _top);
+ setYaxis(b, t);
}
}
void
+HistogramDisplayPlot::setAutoScaleX()
+{
+ _autoscalex_state = true;
+}
+
+void
HistogramDisplayPlot::setAutoScale(bool state)
{
_autoscale_state = state;
@@ -336,7 +353,7 @@ HistogramDisplayPlot::setSemilogy(bool en)
void
HistogramDisplayPlot::setAccumulate(bool state)
{
- _accum = state;
+ d_accum = state;
}
void
@@ -418,21 +435,21 @@ HistogramDisplayPlot::setLineColor(int which, QColor color)
void
HistogramDisplayPlot::setNumBins(int bins)
{
- _bins = bins;
+ d_bins = bins;
delete [] _xAxisPoints;
- _xAxisPoints = new double[_bins];
- memset(_xAxisPoints, 0x0, _bins*sizeof(double));
+ _xAxisPoints = new double[d_bins];
+ _resetXAxisPoints(d_left, d_right);
for(int i = 0; i < _nplots; i++) {
delete [] _yDataPoints[i];
- _yDataPoints[i] = new double[_bins];
- memset(_yDataPoints[i], 0, _bins*sizeof(double));
+ _yDataPoints[i] = new double[d_bins];
+ memset(_yDataPoints[i], 0, d_bins*sizeof(double));
#if QWT_VERSION < 0x060000
- _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], _bins);
+ _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], d_bins);
#else
- _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], _bins);
+ _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], d_bins);
#endif
}
}
diff --git a/gr-qtgui/lib/histogram_sink_f_impl.cc b/gr-qtgui/lib/histogram_sink_f_impl.cc
index cd4012f4f5..ef8a9a52c6 100644
--- a/gr-qtgui/lib/histogram_sink_f_impl.cc
+++ b/gr-qtgui/lib/histogram_sink_f_impl.cc
@@ -331,6 +331,12 @@ namespace gr {
}
void
+ histogram_sink_f_impl::autoscalex()
+ {
+ d_main_gui->autoScaleX();
+ }
+
+ void
histogram_sink_f_impl::reset()
{
d_index = 0;
diff --git a/gr-qtgui/lib/histogram_sink_f_impl.h b/gr-qtgui/lib/histogram_sink_f_impl.h
index 83c8558c1b..995b93bef8 100644
--- a/gr-qtgui/lib/histogram_sink_f_impl.h
+++ b/gr-qtgui/lib/histogram_sink_f_impl.h
@@ -98,6 +98,7 @@ namespace gr {
void enable_semilogx(bool en);
void enable_semilogy(bool en);
void enable_accumulate(bool en);
+ void autoscalex();
int nsamps() const;
int bins() const;
void reset();
diff --git a/gr-qtgui/lib/histogramdisplayform.cc b/gr-qtgui/lib/histogramdisplayform.cc
index a56ad86d3a..22d0d67070 100644
--- a/gr-qtgui/lib/histogramdisplayform.cc
+++ b/gr-qtgui/lib/histogramdisplayform.cc
@@ -39,15 +39,15 @@ HistogramDisplayForm::HistogramDisplayForm(int nplots, QWidget* parent)
_layout->addWidget(_displayPlot, 0, 0);
setLayout(_layout);
- NPointsMenu *nptsmenu = new NPointsMenu(this);
- _menu->addAction(nptsmenu);
- connect(nptsmenu, SIGNAL(whichTrigger(int)),
+ d_nptsmenu = new NPointsMenu(this);
+ _menu->addAction(d_nptsmenu);
+ connect(d_nptsmenu, SIGNAL(whichTrigger(int)),
this, SLOT(setNPoints(const int)));
- NPointsMenu *nbinsmenu = new NPointsMenu(this);
- nbinsmenu->setText("Number of Bins");
- _menu->addAction(nbinsmenu);
- connect(nbinsmenu, SIGNAL(whichTrigger(int)),
+ d_nbinsmenu = new NPointsMenu(this);
+ d_nbinsmenu->setText("Number of Bins");
+ _menu->addAction(d_nbinsmenu);
+ connect(d_nbinsmenu, SIGNAL(whichTrigger(int)),
this, SLOT(setNumBins(const int)));
QAction *accummenu = new QAction("Accumulate", this);
@@ -56,6 +56,23 @@ HistogramDisplayForm::HistogramDisplayForm(int nplots, QWidget* parent)
connect(accummenu, SIGNAL(triggered(bool)),
this, SLOT(setAccumulate(bool)));
+ _menu->removeAction(_autoscale_act);
+ _autoscale_act->setText(tr("Auto Scale Y"));
+ _autoscale_act->setStatusTip(tr("Autoscale Y-axis"));
+ _autoscale_act->setCheckable(true);
+ _autoscale_act->setChecked(true);
+ _autoscale_state = true;
+ _menu->addAction(_autoscale_act);
+
+ _autoscalex_act = new QAction("Auto Scale X", this);
+ _autoscalex_act->setStatusTip(tr("Update X-axis scale"));
+ _autoscalex_act->setCheckable(false);
+ connect(_autoscalex_act, SIGNAL(changed()),
+ this, SLOT(autoScaleX()));
+ _autoscalex_state = false;
+ _menu->addAction(_autoscalex_act);
+
+
// d_semilogxmenu = new QAction("Semilog X", this);
// d_semilogxmenu->setCheckable(true);
// _menu->addAction(d_semilogxmenu);
@@ -130,6 +147,7 @@ void
HistogramDisplayForm::setNPoints(const int npoints)
{
d_npoints = npoints;
+ d_nptsmenu->setDiagText(npoints);
}
void
@@ -142,6 +160,13 @@ HistogramDisplayForm::autoScale(bool en)
}
void
+HistogramDisplayForm::autoScaleX()
+{
+ getPlot()->setAutoScaleX();
+ getPlot()->replot();
+}
+
+void
HistogramDisplayForm::setSemilogx(bool en)
{
d_semilogx = en;
@@ -164,11 +189,16 @@ HistogramDisplayForm::setNumBins(const int bins)
{
getPlot()->setNumBins(bins);
getPlot()->replot();
+ d_nbinsmenu->setDiagText(bins);
}
void
HistogramDisplayForm::setAccumulate(bool en)
{
+ // Turn on y-axis autoscaling when turning accumulate on.
+ if(en) {
+ autoScale(true);
+ }
getPlot()->setAccumulate(en);
getPlot()->replot();
}