diff options
author | Tom Rondeau <tom@trondeau.com> | 2013-10-22 14:03:39 -0400 |
---|---|---|
committer | Tom Rondeau <tom@trondeau.com> | 2013-10-29 12:23:09 -0400 |
commit | ccb5384d759d8736e596574be770ad36222ef4a1 (patch) | |
tree | c5a5a544b09c53890fe199044b9fee7c9de73dc7 | |
parent | daac8bc5f7c41afa678935344ef25f4f92206b3e (diff) |
qtgui: fixed histogram autoscaling features. Added example script.
-rw-r--r-- | gr-qtgui/examples/CMakeLists.txt | 1 | ||||
-rwxr-xr-x | gr-qtgui/examples/pyqt_histogram_f.py | 200 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h | 13 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h | 46 | ||||
-rw-r--r-- | gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h | 6 | ||||
-rw-r--r-- | gr-qtgui/lib/HistogramDisplayPlot.cc | 133 | ||||
-rw-r--r-- | gr-qtgui/lib/histogram_sink_f_impl.cc | 6 | ||||
-rw-r--r-- | gr-qtgui/lib/histogram_sink_f_impl.h | 1 | ||||
-rw-r--r-- | gr-qtgui/lib/histogramdisplayform.cc | 44 |
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(); } |