Thank you for the information and recommendations. I was afraid that it might 
be fairly subtle/complicated, but your code example will be a big help.

James

> On Aug 25, 2021, at 1:04 AM, Patrick <[email protected]> wrote:
> 
> Hi,
> 
> Yeah, this is actually harder than you'd think since when everything is in a 
> full UI layout with windows resizing etc the extra space has to come or go 
> from somewhere... You need to either restrict the zoom range of each axis so 
> that the other doesn't exceed its limits (but that will stop a full zoom-out 
> of that axis), or dynamically grow or shrink the whole plot area and pad out 
> with empty space.
> 
> If you want to go the first path (restricting zoom based on size of other 
> axis), you'll need to do a bunch of manual handling of the ViewBox signals 
> such as sigRangeChanged, sigResized etc:
> https://pyqtgraph.readthedocs.io/en/latest/_modules/pyqtgraph/graphicsItems/ViewBox/ViewBox.html#ViewBox
> That should work but would a bit tedious.
> 
> Your comment about matplotlib reminded me I had to work around something 
> similar previously when embedding matplotlib multi-panel plot into a Qt Ul, 
> where I wanted the whole plot area to maintain a fixed aspect ratio. It turns 
> out set_aspect doesn't work with twinned and shared axes. It was adapted from 
> something I found elsewhere on the internet so it's a bit hacky and not well 
> documented, sorry. Basically it's a QWidget that you insert another widget 
> inside (eg. PlotWidget or similar) and it handles the extra padding required 
> to keep the widget at a fixed ratio.
> 
> #import stuff here as needed...
> class AspectRatioWidget(QWidget):
>     """A widget that will maintain a specified aspect ratio.
>     Good for plots where we want to fill the maximum space without stretching 
> the aspect ratio."""
> 
>     def __init__(self, widget, parent, aspect_ratio):
>         super().__init__(parent)
>         self.aspect_ratio = aspect_ratio
>         self.setLayout(QBoxLayout(QBoxLayout.LeftToRight, self))
>         self.layout().addItem(QSpacerItem(0, 0))
>         self.layout().addWidget(widget)
>         self.layout().addItem(QSpacerItem(0, 0))
> 
>     def setAspectRatio(self, aspect_ratio):
>         self.aspect_ratio = aspect_ratio
>         self._adjust_ratio(self.geometry().width(), self.geometry().height());
> 
>     def resizeEvent(self, e):
>         self._adjust_ratio(e.size().width(), e.size().height())
> 
>     def _adjust_ratio(self, w, h):
>         if w / h > self.aspect_ratio:  # too wide
>             self.layout().setDirection(QBoxLayout.LeftToRight)
>             widget_stretch = h * self.aspect_ratio
>             outer_stretch = (w - widget_stretch) / 2 + 0.5
>         else:  # too tall
>             self.layout().setDirection(QBoxLayout.TopToBottom)
>             widget_stretch = w / self.aspect_ratio
>             outer_stretch = (h - widget_stretch) / 2 + 0.5
> 
>         self.layout().setStretch(0, outer_stretch)
>         self.layout().setStretch(1, widget_stretch)
>         self.layout().setStretch(2, outer_stretch)
> 
> 
> It was used something like this. You'll need to adapt the matplotlib 
> FigureCanvas part to be a pyqtgraph PlotWidget or GraphicsLayoutWidget or 
> similar.
> 
>         self.resultplot_figureCanvas = 
> FigureCanvas(mpl.figure.Figure(constrained_layout=True))
>         # A widget hacky thing to keep fixed aspect ratio of plot, since 
> matplotlib.axes.Axes.set_aspect doesn't work
>         # when there is both twinned and shared axes...
>         self.resultplot_aspectwidget = 
> AspectRatioWidget(self.resultplot_figureCanvas, parent=self, aspect_ratio=1.5)
>         
> self.resultplots_groupBox.layout().addWidget(self.resultplot_aspectwidget)
> 
> 
> Patrick
> On Wednesday, 25 August 2021 at 12:54:30 pm UTC+9:30 James wrote:
> Thanks for the suggestion Patrick. This does work for me in the minimal 
> working example above, as long as the glw.resize() sets the aspect ratio of 
> the GraphicsLayoutWidget to match that of the desired plot (and the GLW fits 
> on my screen). But when I try this in a GUI, I have a problem. See e.g. the 
> following MWE in which I have a PlotWidget and a QPushButton in a 
> QHBoxLayout().
> 
> Without resizing the PlotWidget, the axis limits are not respected (should be 
> x=[0,2000], y=[0,6000]).  And calling resize on the PlotWidget seems to have 
> no effect on the displayed size of the PW (see code below and attached image).
> 
> So it looks like the plot axes are forced to fill the entire PlotWidget area 
> (or at least they do by default), which makes it hard to enforce an aspect 
> ratio for the axes that doesn't match the aspect ratio of the PlotWidget 
> itself.
> There must be a way to do this (e.g. in matplotlib I can configure a set of 
> axes to have whatever aspect ratio I'd like, independent of the dimensions of 
> the figure that holds those axes -- see code below and attached image).
> 
> # pyqtgraph version
> 
> import sys
> import PyQt5.QtWidgets as qtw
> 
> import pyqtgraph as pg
> 
> app = qtw.QApplication(sys.argv)
> window = qtw.QWidget()
> window.setWindowTitle('Fixed aspect ratio')
> layout = qtw.QHBoxLayout()
> layout.addWidget(qtw.QPushButton('Button'))
> 
> _width  = 2000
> _height = 6000
> 
> pw = pg.PlotWidget()
> pw.setLimits(xMin=0, xMax=_width, yMin=0, yMax=_height)
> pw.setRange(xRange=(0, _width), yRange=(0, _height), padding=0, update=True, 
> disableAutoRange=True)
> pw.resize(_width, _height)
> pw.setAspectLocked(lock=True, ratio=1)
> pw.setMouseEnabled(x=False, y=False)
> layout.addWidget(pw)
> 
> window.setLayout(layout)
> window.show()
> 
> # Plot a square                                                               
>                                                   
> pw.plot([_width/4, _width/2, _width/2, _width/4, _width/4], [_width/4, 
> _width/4, _width/2, _width/2, _width/4])
> 
> sys.exit(app.exec_())
> 
> 
> # Matplotlib version
> import matplotlib.pyplot as plt
> fig = plt.figure(figsize=(15,5))  # aspect ratio 3:1                          
>   
> ax1 = fig.add_subplot(1,1,1, adjustable='box', aspect=1)
> ax1.plot(range(10))  # axes are 1:1 within the 3:1 figure                     
>   
> plt.show()
> 
> 
> On Monday, August 23, 2021 at 11:52:26 PM UTC-4 Patrick wrote:
> Hi,
> 
> Does this behave better? Using setLimits(), since setXRange() etc is just a 
> once-off change to the view bounds.
> 
> from pyqtgraph.Qt import QtGui, QtCore
> import pyqtgraph as pg
> 
> app = pg.mkQApp("Range Example")
> 
> glw = pg.GraphicsLayoutWidget(show=True, title="GLW title")
> #glw.setBackground('w')
> glw.setWindowTitle('pyqtgraph example: Plotting')
> 
> plt = glw.addPlot(title='plot title')
> 
> _width = 2000
> _height = 6000
> glw.resize(_width/3, _height/3)
> plt.setLimits(xMin=0, xMax=_width, yMin=0, yMax=_height)
> plt.setXRange(0, _width, padding=0)
> plt.setYRange(0, _height, padding=0)
> plt.setAspectLocked(lock=True, ratio=1)
> 
> plt.plot([_width/4, _width/2, _width/2, _width/4, _width/4], [_width/4, 
> _width/4, _width/2, _width/2, _width/4])
> 
> if __name__ == '__main__':
> pg.mkQApp().exec_()
> 
> Patrick
> On Tuesday, 24 August 2021 at 6:25:45 am UTC+9:30 James wrote:
> Hi,
> 
> I'd like to force the x-range and y-range to specific values meaning that the 
> plot axes should start and stop at those limits (no padding). I also want to 
> specify a fixed aspect ratio of 1:1 (so that dx=100 takes the same screen 
> space as dy=100, i.e. a square will display with equal number of pixels in 
> length and width).
> 
> When I try the following, the displayed x-axis extends beyond the specified 
> limits. Do I need to force the ViewBox to have a specific size that is 
> consistent with the fixed aspect ratio and x/y ranges?
> 
> from pyqtgraph.Qt import QtGui, QtCore
> import pyqtgraph as pg
> 
> app = pg.mkQApp("Range Example")
> 
> glw = pg.GraphicsLayoutWidget(show=True, title="GLW title")
> glw.setBackground('w')
> glw.setWindowTitle('pyqtgraph example: Plotting')
> 
> plt = glw.addPlot(title='plot title')
> 
> _width  = 2000
> _height = 6000
> glw.resize(_width/3, _height/3)
> plt.setXRange(0, _width, padding=0)
> plt.setYRange(0, _height, padding=0)
> plt.setAspectLocked(lock=True, ratio=1)
> 
> if __name__ == '__main__':
>     pg.mkQApp().exec_()
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> -- 
> You received this message because you are subscribed to a topic in the Google 
> Groups "pyqtgraph" group.
> To unsubscribe from this topic, visit 
> https://groups.google.com/d/topic/pyqtgraph/noNWNG3RBg0/unsubscribe 
> <https://groups.google.com/d/topic/pyqtgraph/noNWNG3RBg0/unsubscribe>.
> To unsubscribe from this group and all its topics, send an email to 
> [email protected] 
> <mailto:[email protected]>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/pyqtgraph/21011612-577b-4069-8c31-4efa52c4bb33n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/pyqtgraph/21011612-577b-4069-8c31-4efa52c4bb33n%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
You received this message because you are subscribed to the Google Groups 
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pyqtgraph/A922ED27-7921-4216-A6F0-A2C9374C3F18%40gmail.com.

Reply via email to