Skip to content

Releases: PlotPyStack/PlotPy

v2.10.0

02 Jun 14:16
v2.10.0
c5c1213

Choose a tag to compare

PlotPy Version 2.10.0

✨ New features:

  • Per-axis autoscale strategy: Added configurable autoscale behavior for each axis via the axis parameters dialog. Three strategies are available: Auto (default — compute bounds from items), Fixed range (apply user-defined Min/Max values) and Disabled (leave the axis untouched on autoscale). New API: BasePlot.set_axis_autoscale_strategy() / BasePlot.get_axis_autoscale_strategy() (closes Issue #63, partial)
  • Symbol border width: Added an edgewidth parameter to SymbolParam for customizable marker border thickness — previously the border was always 1 pixel wide

🛠️ Bug fixes:

  • Rectangular snapshot tool — Fixed the "Original size" computation (closes Issue #57):
    • The preview no longer displays negative dimensions when the X or Y axis is
      reversed
    • The "Original size" is now computed from pixel coordinates instead of axis
      units, so it is correct for XYImageItem (and any item with non-uniform
      axis scaling) regardless of axis orientation
    • The ValueError raised by the resize dialog when the selection produced
      negative dimensions on a reversed axis is gone
    • Selecting a region larger than the plotted image now reports the same
      native pixel resolution for both ImageItem and XYImageItem
      (previously XYImageItem reported shape - 1 while ImageItem
      reported the full oversized resolution): exporting at "Original size"
      now consistently preserves the source pixel density and avoids
      upsampling, regardless of the item type
  • Snapshot tool cursor — Fixed the mouse cursor remaining stuck as a cross (+) outside the plot canvas (axes, toolbar) after using the snapshot tool. The modal dialogs are now opened after Qt has released the implicit pointer grab, so the cursor is correctly restored (closes Issue #58)
  • Z-axis log tool — Fixed the ZAxisLogTool being always disabled for non-ImageItem image types (XYImageItem, MaskedImageItem, MaskedXYImageItem, TrImageItem, RGBImageItem). The Z-axis log API (get_zaxis_log_state / set_zaxis_log_state) was moved from ImageItem up to BaseImageItem so all image item types support it. This notably fixes the tool being permanently greyed out in DataLab's image panel (closes Issue #59)
  • Z-axis log data update — Fixed image data not being recomputed when calling set_data() while Z-axis log scale is active — the log-transformed data is now refreshed and the LUT range preserved in log mode
  • YRangeCursorTool — Fixed incorrect inequality display and negative ∆y when the Y-range cursors are inverted (dragging the top cursor below the bottom one). Values are now sorted and ∆y is always positive (closes Issue #55)
  • CurveStatsTool — Replaced min/max/mean/std/sum with their NaN-safe equivalents (nanmin, nanmax, nanmean, nanstd, nansum) so that signal statistics are computed correctly when the data contains NaN values

⚙️ Dependencies:

  • Bumped minimum PythonQwt version from 0.15 to 0.16 to benefit from the Qt6 performance optimizations (closes Issue #22 — see PythonQwt#93 for the full optimization log)

v2.9.0

20 Apr 08:22

Choose a tag to compare

PlotPy Version 2.9.0

💥 New features:

  • Added QuiverItem for displaying 2D vector fields (quiver plots), similar to
    Matplotlib's quiver. This closes
    Issue #54:
    • New QuiverItem plot item class supporting X, Y, U, V arrays (1D or 2D)
    • Auto-meshgrid expansion when X, Y are 1D and U, V are 2D
    • Configurable arrow scale, head size, and color
    • New make.quiver() builder method for easy item creation
    • New quiver() function in the interactive plotting interface (plotpy.pyplot)
    • Integrated with plot autoscale (initial zoom and middle-click reset)
    • Item icon displayed in the item list widget
  • Added "Invert colormap" checkbox directly in the Colormap Manager dialog. This
    closes Issue #53:
    • Reflects the current inversion state when the dialog is opened
    • Allows toggling inversion from the colormap selection widget
    • Updates the colormap preview in real-time when toggled
    • Inversion is treated as a display parameter, independent of the colormap
      definition (toggling does not mark the colormap as having unsaved changes)

🛠️ Bug fixes:

  • Fixed marker style parameters being overwritten when updating selected markers:
    • MarkerParam.update_param now correctly reads back the selected or unselected
      visual state into the matching parameter set, instead of overwriting the base
      (normal) style with the selected style
    • This preserves distinct normal and selected appearance for markers
  • Fixed error-bar curve cursor snapping: clicking near an error-bar bound on an
    ErrorBarCurveItem now correctly returns the closest bar end coordinate.
    Previously a typo (abs(y - y) / abs(x - x) instead of abs(y - yi) /
    abs(x - xi)) made the snap-to-bound branches dead code, so the closest
    coordinate was always the central curve point regardless of cursor position
  • Fixed image export via Figure.print_ (plotpy.pyplot) leaking the underlying
    QPainter: the painter is now always released, even when an axis fails to
    render. This avoids "QPainter::begin: A paint device can only be painted by
    one painter at a time" warnings, GDI/GL resource leaks, and truncated output
    files on subsequent paints
  • Fixed vector_projection raising a division-by-zero warning and returning NaN
    coordinates when the two reference points A and B coincided. The function now
    detects the degenerate zero-length AB vector and returns point B
  • Fixed scale_data_to_dtype (plotpy.io) producing NaN values when the input
    array was constant (dmax == dmin). The function now returns a finite
    constant array set to the target dtype's minimum value instead of dividing by
    zero
  • Fixed get_nan_min / get_nan_max (plotpy.mathutils.arrayfuncs) raising
    ValueError on empty arrays and emitting RuntimeWarning on all-NaN inputs.
    Both helpers now return NaN for empty or fully-NaN arrays without warnings

🔧 Other changes:

  • CI: gate PyPI deployment on test suite passing
  • Development environment: improved scripts/run_with_env.py to support multiple
    Python environment contexts (WinPython, venv, etc.) with legacy support for the
    WINPYDIRBASE environment variable

v2.8.4

14 Feb 16:56

Choose a tag to compare

PlotPy Version 2.8.4 (2026-02-14)

💥 New features:

  • Added official support for Python 3.14

🛠️ Bug fixes:

  • Fixed PySide6 compatibility issues causing segfaults in the test suite:
    • Use object instead of C++ type strings (e.g., "QMouseEvent", "QEvent", "QPointF") in Signal declarations — PySide6 segfaults with C++ type name strings
    • Check QObject validity via is_qobject_valid() before accessing widgets in __del__, closeEvent, and panel close operations — PySide6 segfaults on deleted C++ objects instead of raising RuntimeError
    • Restructure BaseSyncPlot.__init__ to defer widget operations until after Qt __init__ completes — PySide6 requires __init__ to have fully completed before the widget can be used as a parent
    • Replace deprecated exec_() calls with exec()
  • Fixed test_multiline_tool failing with PyQt6 due to smaller canvas size:
    • The spiral test data started at t=0, placing the first two points so close together that they mapped to the same pixel on PyQt6's smaller default canvas
    • Start the spiral at t=2π to ensure sufficient pixel spacing between consecutive points
  • Fixed pytest running all tests when selecting a single test from VS Code:
    • Move plotpy from addopts to testpaths in [tool.pytest.ini_options]

🔧 Other changes:

  • Add missing setuptools to requirements.txt (dev)
  • Update GitHub Actions to use latest artifact upload and download versions
  • Update cibuildwheel version to v3.3.1 for improved wheel building
  • Add .venv* to .gitignore to exclude virtual environment files

v2.8.3

18 Dec 09:42

Choose a tag to compare

PlotPy Version 2.8.3

💥 New features:

  • AnnotatedSegment new angle display:
    • Added angle display in annotation label, showing the segment's angle relative to the horizontal direction (0° to 180°)
    • This implements the equivalent feature submitted in Pull Request #51 by user @deuterium33

🛠️ Bug fixes:

  • Fixed IndexError when displaying images with a single row or column (e.g., SIF files with shape (1, N)):
    • The to_bins() function now handles single-element coordinate arrays by assuming a bin width of 1.0 centered on the point
    • Previously, loading such images in DataLab caused an IndexError: index 1 is out of bounds for axis 0 with size 1
  • Fixed circle/ellipse shape drawing with non-uniform aspect ratios:
    • Axes were not perpendicular and did not connect to the ellipse edge when plot aspect ratio differed from 1.0
    • Now uses parametric ellipse drawing that correctly handles non-perpendicular axes in pixel space
    • The ellipse properly passes through all four handle points regardless of aspect ratio or rotation
  • Fixed angle display range for AnnotatedObliqueRectangle and AnnotatedEllipse:
    • Angle is now displayed in the 0° to 180° range instead of -90° to 90° (the original implementation was also displaying 0° at vertical orientation -additionally to horizontal orientation- which was counter-intuitive)
    • This provides a more intuitive and consistent angle representation

v2.8.2

12 Nov 15:47

Choose a tag to compare

Version 2.8.2

🛠️ Bug fixes:

  • Fixed RuntimeWarning when changing masked image data type from float to integer:
    • MaskedImageItem.update_mask() now handles NaN and None filling_value gracefully
    • When converting to integer dtypes, NaN/None values are replaced with 0 instead of triggering numpy cast warnings
    • When converting to float dtypes, NaN is preserved as the fill value
    • Added comprehensive tests to validate dtype conversion scenarios

Version 2.8.1

🛠️ Bug fixes:

  • Issue #50 - Fixed ImageStatsTool displaying "No available data" for XYImageItem and MaskedXYImageItem:
    • Added IExportROIImageItemType to XYImageItem.types() so that get_items_in_rectangle() can properly identify XY image items
    • Updated __implements__ tuples for consistency across XYImageItem, MaskedXYImageItem, and MaskedImageItem
    • The tool now correctly displays statistics for images with non-uniform coordinates
  • Fixed snapshot tool failing with SystemError on XYImageItem and MaskedXYImageItem:
    • Fixed assemble_imageitems passing list instead of tuple to C extension function _scale_rect
    • Added missing export_roi method to XYImageItem to properly handle non-uniform coordinate transformations
    • Snapshots of XY images now render correctly instead of producing black images

Version 2.8.0

💥 New features / Enhancements:

  • Curve fitting: added support for locked parameters:
    • New locked parameter in FitParam class to lock parameter values during automatic optimization
    • New locked field in FitParamDataSet to configure parameter locking via the settings dialog
    • When locked, parameters retain their manually-adjusted values during auto-fit
    • Visual indicators: locked parameters show a 🔒 emoji and are grayed out with disabled controls
    • All optimization algorithms (simplex, Powell, BFGS, L-BFGS-B, conjugate gradient, least squares) fully support locked parameters
    • Enables partial optimization workflows: fix well-determined parameters, optimize uncertain ones
    • Improves fit convergence by reducing problem dimensionality
  • Configurable autoscale margin:
    • Added autoscale_margin_percent parameter to BasePlotOptions for intuitive percentage-based margin control
    • Users can now specify autoscale margins as percentages (e.g., 0.2 for 0.2%, 5.0 for 5%)
    • Replaces the previous decimal-based approach with more user-friendly percentage values
    • Default remains 0.2% (equivalent to previous 0.002) for backward compatibility
    • Includes validation to prevent unreasonable values (0-50% range)
  • Image statistics tool improvements:
    • Enhanced get_stats function to display delta (Δ) values for coordinate ranges
    • Now shows Δx, Δy, and Δz values alongside the min/max ranges for better analysis
  • Added optional "Axes" tab control in Parameters dialog:
    • New show_axes_tab option in BasePlotOptions and PlotOptions (default: True)
    • When set to False, the "Axes" tab is hidden from item parameter dialogs
    • This allows applications to provide their own axes management while using PlotPy
    • Can be configured during plot creation or changed at runtime using plot.set_show_axes_tab(False)
  • Issue #45 - Add support for new curve Y-range cursor tool YRangeCursorTool:
    • This tool is similar to the existing CurveStatsTool, but it simply shows the Y-range values (min, max and interval).
    • It can be added to the plot widget using plot_widget.manager.add_tool(YRangeCursorTool)
  • Update color configurations defaults for improved visibility
  • Item list:
    • Added a new "Rename" context menu entry to rename the selected item
    • This entry is only available for editable items
  • X and Y range selection items:
    • Added support for item title in parameters data set (RangeShapeParam)
    • This concerns the XRangeSelection and YRangeSelection items
  • New annotated X and Y range selection items:
    • Added AnnotatedXRange and AnnotatedYRange items
    • These items provide X and Y range selection with an annotation label
    • They can be created using make.annotated_xrange and make.annotated_yrange functions
  • New SyncPlotDialog class:
    • This class provides a dialog for displaying synchronized plots.
    • This is a complementary class to SyncPlotWindow, providing a modal dialog interface for synchronized plotting.
  • Native datetime axis support:
    • Added BasePlot.set_axis_datetime() method to easily configure an axis for datetime display
    • Added BasePlot.set_axis_limits_from_datetime() method to set axis limits using datetime objects directly
    • Supports customizable datetime format strings using Python's strftime format codes
    • Configurable label rotation and spacing for optimal display
    • Example: plot.set_axis_datetime("bottom", format="%H:%M:%S") for time-only display
    • Example: plot.set_axis_limits_from_datetime("bottom", dt1, dt2) to zoom to a specific time range
    • Added "datetime" as a valid scale type (alongside "lin" and "log") for axis configuration
    • Added datetime coordinate formatting support throughout PlotPy:
      • Cursor tools (VCursorTool, HCursorTool, XCursorTool) now display datetime-formatted X/Y coordinates
      • CurveStatsTool now displays datetime-formatted X coordinates for statistical computations
      • Marker labels automatically format coordinates as datetime when axis uses datetime scale
      • Coordinate display in the plot canvas now shows datetime format when appropriate
      • Refactored ObjectInfo base class to provide shared datetime formatting methods for code reuse

🧹 API cleanup: removed deprecated update methods (use update_item instead)

  • Removed AnnotationParam.update_annotation method
  • Removed AxesShapeParam.update_axes method
  • Removed AxesParam.update_axes method
  • Removed ImageAxesParam.update_axes method
  • Removed LabelParam.update_label method
  • Removed MarkerParam.update_marker method
  • Removed RangeShapeParam.update_range method
  • Removed ShapeParam.update_shape method

🛠️ Bug fixes:

  • Fixed RuntimeError in SyncPlotWindow and SyncPlotDialog when closing widgets quickly:
    • Fixed "wrapped C/C++ object of type QwtScaleWidget has been deleted" error that occurred when widgets were closed before the deferred plot rescaling operation could complete
    • Replaced QTimer.singleShot() with controllable QTimer instances that can be stopped on widget close
    • Added handle_show_event() and handle_close_event() methods to BaseSyncPlot for proper timer lifecycle management
    • Refactored showEvent() and closeEvent() in both SyncPlotWindow and SyncPlotDialog to eliminate code duplication
    • Added early exit check in rescale_plots() to prevent execution if the timer has been stopped
    • This fix ensures clean widget shutdown and prevents Qt from attempting to access deleted C++ objects
  • Cross-section panels: Fixed autoscaling logic in BaseCrossSectionPlot
    • Streamlined handling of autoscale_mode and lockscales options for consistent scaling behavior across all code paths
    • The update_plot() method now delegates all scaling logic to plot_axis_changed() to avoid code duplication and ensure consistency
    • Fixed issue where Y cross-section plots for rectangular images with non-uniform axes (e.g., Y = f(X)) were not properly scaled on initial display
    • The lockscales mode now correctly syncs the cross-section axis (CS_AXIS) to the image plot while autoscaling the intensity axis (Z_AXIS)
  • Issue #49 - Fixed multiple coordinate handling bugs in XYImageItem:
    • Root cause: XYImageItem internally stores bin edges (length n+1) but several methods were incorrectly treating them as pixel centers (length n)
    • Fixed get_x_values() and get_y_values() to correctly compute and return pixel centers from stored bin edges: (edge[i] + edge[i+1]) / 2
    • Fixed get_pixel_coordinates() to correctly convert plot coordinates to pixel indices using searchsorted() with proper edge-to-index adjustment
    • Fixed get_plot_coordinates() to return pixel center coordinates instead of bin edge coordinates
    • Fixed get_closest_coordinates() to return pixel center coordinates instead of bin edge coordinates
    • Added comprehensive docstring documentation explaining that XYImageItem.x and XYImageItem.y store bin edges, not pixel centers
    • Removed redundant pixel centering code in CrossSectionItem.update_curve_data() that was working around these bugs
    • This fixes the reported issue where using cross-section tools progressively translated image data to the bottom-right corner
    • All coordinate-related methods now properly handle the bin edge vs pixel center distinction throughout the XYImageItem API
  • Fixed index bounds calculation for image slicing compatibility:
    • Corrected the calculation of maximum indices in get_plot_coordinates to ensure proper bounds when using NumPy array slicing
    • Previously, the maximum indices were off by one, which could cause issues when extracting image data using the returned coordinates
    • Now returns indices that correctly align with Python/NumPy slicing conventions (e.g., [i1:i2+1, j1:j2+1])
    • This fixes an historic bug that could lead to off-by-one errors when users extracted image data using the coordinates provided by this function
  • Fixed plot update after inserting a point using the EditPointTool on non-Windows platforms
  • Issue #46 - Contrast adjustment with 'Eliminate outliers' failed for float images with high dynamic range
  • Issue #29 - SelectTool: Selectin...
Read more

v2.8.1

06 Nov 08:01

Choose a tag to compare

Version 2.8.1

🛠️ Bug fixes:

  • Issue #50 - Fixed ImageStatsTool displaying "No available data" for XYImageItem and MaskedXYImageItem:
    • Added IExportROIImageItemType to XYImageItem.types() so that get_items_in_rectangle() can properly identify XY image items
    • Updated __implements__ tuples for consistency across XYImageItem, MaskedXYImageItem, and MaskedImageItem
    • The tool now correctly displays statistics for images with non-uniform coordinates
  • Fixed snapshot tool failing with SystemError on XYImageItem and MaskedXYImageItem:
    • Fixed assemble_imageitems passing list instead of tuple to C extension function _scale_rect
    • Added missing export_roi method to XYImageItem to properly handle non-uniform coordinate transformations
    • Snapshots of XY images now render correctly instead of producing black images

Version 2.8.0

💥 New features / Enhancements:

  • Curve fitting: added support for locked parameters:
    • New locked parameter in FitParam class to lock parameter values during automatic optimization
    • New locked field in FitParamDataSet to configure parameter locking via the settings dialog
    • When locked, parameters retain their manually-adjusted values during auto-fit
    • Visual indicators: locked parameters show a 🔒 emoji and are grayed out with disabled controls
    • All optimization algorithms (simplex, Powell, BFGS, L-BFGS-B, conjugate gradient, least squares) fully support locked parameters
    • Enables partial optimization workflows: fix well-determined parameters, optimize uncertain ones
    • Improves fit convergence by reducing problem dimensionality
  • Configurable autoscale margin:
    • Added autoscale_margin_percent parameter to BasePlotOptions for intuitive percentage-based margin control
    • Users can now specify autoscale margins as percentages (e.g., 0.2 for 0.2%, 5.0 for 5%)
    • Replaces the previous decimal-based approach with more user-friendly percentage values
    • Default remains 0.2% (equivalent to previous 0.002) for backward compatibility
    • Includes validation to prevent unreasonable values (0-50% range)
  • Image statistics tool improvements:
    • Enhanced get_stats function to display delta (Δ) values for coordinate ranges
    • Now shows Δx, Δy, and Δz values alongside the min/max ranges for better analysis
  • Added optional "Axes" tab control in Parameters dialog:
    • New show_axes_tab option in BasePlotOptions and PlotOptions (default: True)
    • When set to False, the "Axes" tab is hidden from item parameter dialogs
    • This allows applications to provide their own axes management while using PlotPy
    • Can be configured during plot creation or changed at runtime using plot.set_show_axes_tab(False)
  • Issue #45 - Add support for new curve Y-range cursor tool YRangeCursorTool:
    • This tool is similar to the existing CurveStatsTool, but it simply shows the Y-range values (min, max and interval).
    • It can be added to the plot widget using plot_widget.manager.add_tool(YRangeCursorTool)
  • Update color configurations defaults for improved visibility
  • Item list:
    • Added a new "Rename" context menu entry to rename the selected item
    • This entry is only available for editable items
  • X and Y range selection items:
    • Added support for item title in parameters data set (RangeShapeParam)
    • This concerns the XRangeSelection and YRangeSelection items
  • New annotated X and Y range selection items:
    • Added AnnotatedXRange and AnnotatedYRange items
    • These items provide X and Y range selection with an annotation label
    • They can be created using make.annotated_xrange and make.annotated_yrange functions
  • New SyncPlotDialog class:
    • This class provides a dialog for displaying synchronized plots.
    • This is a complementary class to SyncPlotWindow, providing a modal dialog interface for synchronized plotting.
  • Native datetime axis support:
    • Added BasePlot.set_axis_datetime() method to easily configure an axis for datetime display
    • Added BasePlot.set_axis_limits_from_datetime() method to set axis limits using datetime objects directly
    • Supports customizable datetime format strings using Python's strftime format codes
    • Configurable label rotation and spacing for optimal display
    • Example: plot.set_axis_datetime("bottom", format="%H:%M:%S") for time-only display
    • Example: plot.set_axis_limits_from_datetime("bottom", dt1, dt2) to zoom to a specific time range
    • Added "datetime" as a valid scale type (alongside "lin" and "log") for axis configuration
    • Added datetime coordinate formatting support throughout PlotPy:
      • Cursor tools (VCursorTool, HCursorTool, XCursorTool) now display datetime-formatted X/Y coordinates
      • CurveStatsTool now displays datetime-formatted X coordinates for statistical computations
      • Marker labels automatically format coordinates as datetime when axis uses datetime scale
      • Coordinate display in the plot canvas now shows datetime format when appropriate
      • Refactored ObjectInfo base class to provide shared datetime formatting methods for code reuse

🧹 API cleanup: removed deprecated update methods (use update_item instead)

  • Removed AnnotationParam.update_annotation method
  • Removed AxesShapeParam.update_axes method
  • Removed AxesParam.update_axes method
  • Removed ImageAxesParam.update_axes method
  • Removed LabelParam.update_label method
  • Removed MarkerParam.update_marker method
  • Removed RangeShapeParam.update_range method
  • Removed ShapeParam.update_shape method

🛠️ Bug fixes:

  • Fixed RuntimeError in SyncPlotWindow and SyncPlotDialog when closing widgets quickly:
    • Fixed "wrapped C/C++ object of type QwtScaleWidget has been deleted" error that occurred when widgets were closed before the deferred plot rescaling operation could complete
    • Replaced QTimer.singleShot() with controllable QTimer instances that can be stopped on widget close
    • Added handle_show_event() and handle_close_event() methods to BaseSyncPlot for proper timer lifecycle management
    • Refactored showEvent() and closeEvent() in both SyncPlotWindow and SyncPlotDialog to eliminate code duplication
    • Added early exit check in rescale_plots() to prevent execution if the timer has been stopped
    • This fix ensures clean widget shutdown and prevents Qt from attempting to access deleted C++ objects
  • Cross-section panels: Fixed autoscaling logic in BaseCrossSectionPlot
    • Streamlined handling of autoscale_mode and lockscales options for consistent scaling behavior across all code paths
    • The update_plot() method now delegates all scaling logic to plot_axis_changed() to avoid code duplication and ensure consistency
    • Fixed issue where Y cross-section plots for rectangular images with non-uniform axes (e.g., Y = f(X)) were not properly scaled on initial display
    • The lockscales mode now correctly syncs the cross-section axis (CS_AXIS) to the image plot while autoscaling the intensity axis (Z_AXIS)
  • Issue #49 - Fixed multiple coordinate handling bugs in XYImageItem:
    • Root cause: XYImageItem internally stores bin edges (length n+1) but several methods were incorrectly treating them as pixel centers (length n)
    • Fixed get_x_values() and get_y_values() to correctly compute and return pixel centers from stored bin edges: (edge[i] + edge[i+1]) / 2
    • Fixed get_pixel_coordinates() to correctly convert plot coordinates to pixel indices using searchsorted() with proper edge-to-index adjustment
    • Fixed get_plot_coordinates() to return pixel center coordinates instead of bin edge coordinates
    • Fixed get_closest_coordinates() to return pixel center coordinates instead of bin edge coordinates
    • Added comprehensive docstring documentation explaining that XYImageItem.x and XYImageItem.y store bin edges, not pixel centers
    • Removed redundant pixel centering code in CrossSectionItem.update_curve_data() that was working around these bugs
    • This fixes the reported issue where using cross-section tools progressively translated image data to the bottom-right corner
    • All coordinate-related methods now properly handle the bin edge vs pixel center distinction throughout the XYImageItem API
  • Fixed index bounds calculation for image slicing compatibility:
    • Corrected the calculation of maximum indices in get_plot_coordinates to ensure proper bounds when using NumPy array slicing
    • Previously, the maximum indices were off by one, which could cause issues when extracting image data using the returned coordinates
    • Now returns indices that correctly align with Python/NumPy slicing conventions (e.g., [i1:i2+1, j1:j2+1])
    • This fixes an historic bug that could lead to off-by-one errors when users extracted image data using the coordinates provided by this function
  • Fixed plot update after inserting a point using the EditPointTool on non-Windows platforms
  • Issue #46 - Contrast adjustment with 'Eliminate outliers' failed for float images with high dynamic range
  • Issue #29 - SelectTool: Selecting Another Shape Without Unselection
    • Fixed direct selection between different shapes without requiring intermediate click on empty space
    • Users can now click directly from one shape to another for immediate selection
    • Maintains all existing functionality including multi-selection (Ctrl+click), moving, and resizing
  • Fixed ErrorBarCurveItem handling of all-NaN data:
    • Fixed ValueError: zero-size array to reduction operation minimum which has no identity w...
Read more

v2.8.0

24 Oct 14:34
Immutable release. Only release title and notes can be modified.

Choose a tag to compare

💥 New features / Enhancements:

  • Curve fitting: added support for locked parameters:
    • New locked parameter in FitParam class to lock parameter values during automatic optimization
    • New locked field in FitParamDataSet to configure parameter locking via the settings dialog
    • When locked, parameters retain their manually-adjusted values during auto-fit
    • Visual indicators: locked parameters show a 🔒 emoji and are grayed out with disabled controls
    • All optimization algorithms (simplex, Powell, BFGS, L-BFGS-B, conjugate gradient, least squares) fully support locked parameters
    • Enables partial optimization workflows: fix well-determined parameters, optimize uncertain ones
    • Improves fit convergence by reducing problem dimensionality
  • Configurable autoscale margin:
    • Added autoscale_margin_percent parameter to BasePlotOptions for intuitive percentage-based margin control
    • Users can now specify autoscale margins as percentages (e.g., 0.2 for 0.2%, 5.0 for 5%)
    • Replaces the previous decimal-based approach with more user-friendly percentage values
    • Default remains 0.2% (equivalent to previous 0.002) for backward compatibility
    • Includes validation to prevent unreasonable values (0-50% range)
  • Image statistics tool improvements:
    • Enhanced get_stats function to display delta (Δ) values for coordinate ranges
    • Now shows Δx, Δy, and Δz values alongside the min/max ranges for better analysis
  • Added optional "Axes" tab control in Parameters dialog:
    • New show_axes_tab option in BasePlotOptions and PlotOptions (default: True)
    • When set to False, the "Axes" tab is hidden from item parameter dialogs
    • This allows applications to provide their own axes management while using PlotPy
    • Can be configured during plot creation or changed at runtime using plot.set_show_axes_tab(False)
  • Issue #45 - Add support for new curve Y-range cursor tool YRangeCursorTool:
    • This tool is similar to the existing CurveStatsTool, but it simply shows the Y-range values (min, max and interval).
    • It can be added to the plot widget using plot_widget.manager.add_tool(YRangeCursorTool)
  • Update color configurations defaults for improved visibility
  • Item list:
    • Added a new "Rename" context menu entry to rename the selected item
    • This entry is only available for editable items
  • X and Y range selection items:
    • Added support for item title in parameters data set (RangeShapeParam)
    • This concerns the XRangeSelection and YRangeSelection items
  • New annotated X and Y range selection items:
    • Added AnnotatedXRange and AnnotatedYRange items
    • These items provide X and Y range selection with an annotation label
    • They can be created using make.annotated_xrange and make.annotated_yrange functions
  • New SyncPlotDialog class:
    • This class provides a dialog for displaying synchronized plots.
    • This is a complementary class to SyncPlotWindow, providing a modal dialog interface for synchronized plotting.
  • Native datetime axis support:
    • Added BasePlot.set_axis_datetime() method to easily configure an axis for datetime display
    • Added BasePlot.set_axis_limits_from_datetime() method to set axis limits using datetime objects directly
    • Supports customizable datetime format strings using Python's strftime format codes
    • Configurable label rotation and spacing for optimal display
    • Example: plot.set_axis_datetime("bottom", format="%H:%M:%S") for time-only display
    • Example: plot.set_axis_limits_from_datetime("bottom", dt1, dt2) to zoom to a specific time range
    • Added "datetime" as a valid scale type (alongside "lin" and "log") for axis configuration
    • Added datetime coordinate formatting support throughout PlotPy:
      • Cursor tools (VCursorTool, HCursorTool, XCursorTool) now display datetime-formatted X/Y coordinates
      • CurveStatsTool now displays datetime-formatted X coordinates for statistical computations
      • Marker labels automatically format coordinates as datetime when axis uses datetime scale
      • Coordinate display in the plot canvas now shows datetime format when appropriate
      • Refactored ObjectInfo base class to provide shared datetime formatting methods for code reuse

🧹 API cleanup: removed deprecated update methods (use update_item instead)

  • Removed AnnotationParam.update_annotation method
  • Removed AxesShapeParam.update_axes method
  • Removed AxesParam.update_axes method
  • Removed ImageAxesParam.update_axes method
  • Removed LabelParam.update_label method
  • Removed MarkerParam.update_marker method
  • Removed RangeShapeParam.update_range method
  • Removed ShapeParam.update_shape method

🛠️ Bug fixes:

  • Fixed RuntimeError in SyncPlotWindow and SyncPlotDialog when closing widgets quickly:
    • Fixed "wrapped C/C++ object of type QwtScaleWidget has been deleted" error that occurred when widgets were closed before the deferred plot rescaling operation could complete
    • Replaced QTimer.singleShot() with controllable QTimer instances that can be stopped on widget close
    • Added handle_show_event() and handle_close_event() methods to BaseSyncPlot for proper timer lifecycle management
    • Refactored showEvent() and closeEvent() in both SyncPlotWindow and SyncPlotDialog to eliminate code duplication
    • Added early exit check in rescale_plots() to prevent execution if the timer has been stopped
    • This fix ensures clean widget shutdown and prevents Qt from attempting to access deleted C++ objects
  • Cross-section panels: Fixed autoscaling logic in BaseCrossSectionPlot
    • Streamlined handling of autoscale_mode and lockscales options for consistent scaling behavior across all code paths
    • The update_plot() method now delegates all scaling logic to plot_axis_changed() to avoid code duplication and ensure consistency
    • Fixed issue where Y cross-section plots for rectangular images with non-uniform axes (e.g., Y = f(X)) were not properly scaled on initial display
    • The lockscales mode now correctly syncs the cross-section axis (CS_AXIS) to the image plot while autoscaling the intensity axis (Z_AXIS)
  • Issue #49 - Fixed multiple coordinate handling bugs in XYImageItem:
    • Root cause: XYImageItem internally stores bin edges (length n+1) but several methods were incorrectly treating them as pixel centers (length n)
    • Fixed get_x_values() and get_y_values() to correctly compute and return pixel centers from stored bin edges: (edge[i] + edge[i+1]) / 2
    • Fixed get_pixel_coordinates() to correctly convert plot coordinates to pixel indices using searchsorted() with proper edge-to-index adjustment
    • Fixed get_plot_coordinates() to return pixel center coordinates instead of bin edge coordinates
    • Fixed get_closest_coordinates() to return pixel center coordinates instead of bin edge coordinates
    • Added comprehensive docstring documentation explaining that XYImageItem.x and XYImageItem.y store bin edges, not pixel centers
    • Removed redundant pixel centering code in CrossSectionItem.update_curve_data() that was working around these bugs
    • This fixes the reported issue where using cross-section tools progressively translated image data to the bottom-right corner
    • All coordinate-related methods now properly handle the bin edge vs pixel center distinction throughout the XYImageItem API
  • Fixed index bounds calculation for image slicing compatibility:
    • Corrected the calculation of maximum indices in get_plot_coordinates to ensure proper bounds when using NumPy array slicing
    • Previously, the maximum indices were off by one, which could cause issues when extracting image data using the returned coordinates
    • Now returns indices that correctly align with Python/NumPy slicing conventions (e.g., [i1:i2+1, j1:j2+1])
    • This fixes an historic bug that could lead to off-by-one errors when users extracted image data using the coordinates provided by this function
  • Fixed plot update after inserting a point using the EditPointTool on non-Windows platforms
  • Issue #46 - Contrast adjustment with 'Eliminate outliers' failed for float images with high dynamic range
  • Issue #29 - SelectTool: Selecting Another Shape Without Unselection
    • Fixed direct selection between different shapes without requiring intermediate click on empty space
    • Users can now click directly from one shape to another for immediate selection
    • Maintains all existing functionality including multi-selection (Ctrl+click), moving, and resizing
  • Fixed ErrorBarCurveItem handling of all-NaN data:
    • Fixed ValueError: zero-size array to reduction operation minimum which has no identity when error bar curves contain only NaN values
    • Added proper checks in boundingRect() and draw() methods to handle empty arrays gracefully
    • Error bar curves with all-NaN data now fall back to parent class behavior instead of crashing
  • Item list: refresh tree when item parameters are changed:
    • Added SIG_ITEM_PARAMETERS_CHANGED signal to BasePlot class
    • This signal is emitted when the parameters of an item are changed using the parameters dialog, or a specific tool (e.g. the colormap selection tool, or the lock/unlock tool for image items)
    • The signal is emitted with the item as argument
    • The ItemListWidget now listens to this signal and refreshes the item list accordingly
  • Edit tools (Edit data, center image position):
    • Exclude read-only items from the list of editable items
    • It is no longer possible to use those tools on read-only items
  • Marker items (markers, cursors):
    • Setting item movable s...
Read more

v2.7.5

15 Jul 13:27

Choose a tag to compare

Version 2.7.5

🛠️ Bug fixes:

  • Issue #44 - Incorrect calculation method for "∑(y)" in CurveStatsTool: replaced spt.trapezoid with np.sum, which is more consistent with the summation operation
  • Fix update_status method in all cross-section tools (intensity profile tools):
    • Use get_items instead of get_selected_items to retrieve the image items
    • This allows the tools to work properly when no image item is selected, but there are image items in the plot
    • This closes Issue #47 - Intensity profile tools do not work when no image item is selected

Other changes:

  • Updated guidata dependency to V3.10.0
  • Using new guidata translation utility based on babel

v2.7.4

26 Apr 07:29

Choose a tag to compare

In this release, test coverage is 80%.

🛠️ Bug fixes:

  • Issue #42 - Image profiles: when moving/resizing image, profile plots are not refreshed
  • Issue #41 - Average profile visualization: empty profile is displayed when the target rectangular area is outside the image area

v2.7.3

05 Apr 10:45

Choose a tag to compare

In this release, test coverage is 80%.

🛠️ Bug fixes:

  • Issue #40 - Z-axis logarithmic scale (ZAxisLogTool tool) is not compatible with anti-aliasing interpolation
  • Fix intersection check for destination rectangle in XYImageFilterItem
  • Issue #36 - Image items are not properly scaling along Y-axis with logarithmic scale:
    • Actually, image items do not support non-linear scales (this is an historical limitation)
    • This is not documented at all, so we've added an explicit warning: a red colored message is displayed at the center of the image frame when any non-linear scale is applied to either X or Y axis
    • When dealing with non-linear scales, PlotPy provides an alternative solution: the user may rely on XYImageItem (e.g. by using make.xyimage) as this item supports arbitrary X and Y pixel coordinates
  • Issue #34 - ValueError when trying to plot 2D histogram items with PyQt6

Other changes:

  • Replace deprecated icon files with new SVG icons for selection tools