Skip to content

Releases: PlotPyStack/PlotPy

v2.12.0

Choose a tag to compare

@PierreRaybaut PierreRaybaut released this 30 Oct 09:20
v2.12.0
775f245

Version 2.12

PlotPy Version 2.12.0

✨ New features:

  • Min/max curve downsampling — Curve downsampling now keeps, by default, the minimum and the maximum of each group of 2 × N points (N being the downsampling factor), instead of one point out of N: narrow peaks and the envelope of noisy signals are preserved, with about as many points as before. The new Downsampling method curve parameter (CurveParam.dsamp_method) restores the former method ("stride"). CurveItem.get_dsamp_indices returns the indices of the points kept, the new minmax_downsampling_indices function computes them, and the CurveItem.frozen_downsampling context keeps them while points are edited (closes Issue #83)

🛠️ Bug fixes:

  • Z-axis logarithmic scale — With the Z-axis logarithmic scale enabled (ZAxisLogTool), the color bar, the contrast adjustment panel and the LUT range used logarithms of the image values instead of the image values themselves. The color bar now shows the original image values on a logarithmic scale, with the same colors as the image, consistently with the cursor values. In the contrast adjustment panel, the range now matches the histogram, so that the "Full range", "Eliminate %", "Min." and "Max." actions no longer show the image with a single color. Cross sections and exported images with the LUT applied now follow the logarithmic color mapping. Images with values lower than 1 (e.g. between 0 and 1) are no longer shown with a single color: values lower than or equal to zero are now shown with the lowest color of the colormap. Enabling the logarithmic scale sets the LUT range to the full range of the positive values, and disabling it restores the previous LUT range. The Z-axis log tool is now disabled for image items which do not support it (RGB images, 2D histograms, quadrilateral grids and image filters). API change: with the logarithmic scale, get_lut_range, set_lut_range, get_lut_range_full and the lut_range argument of set_data now use data units instead of base-10 logarithms, and the new BaseImageItem.supports_zaxis_log method tells whether an image item supports the logarithmic scale (closes Issue #63)
  • Editing points of downsampled curves — With downsampling enabled, moving a curve point modified another point of the curve data than the one shown, since the handle of a drawn point was used as an index into the full data
  • Curve fitting dialog — Running the automatic fit no longer raises OverflowError: argument 1 overflowed errors when a fitted value ends up far outside the range of its slider (e.g. with the Powell method on a fit range restricted to the tail of a peak). These errors left the slider of the parameter unresponsive, and the values of the following parameters were not displayed. Such values are now shown with a warning icon, whose tooltip gives the slider range, while the slider stays at its nearest end. Typing nan or inf in a parameter field now restores the previous value instead of raising errors, and the number of slider steps must be at least 2 in the parameter properties dialog (closes Issue #76)
  • Cross-section panels with many hidden images — X/Y cross-section panels kept one curve for every image ever displayed, even after it was hidden, so plots containing hundreds of hidden images became progressively slower to refresh. Curves are now only kept for visible images, and are recreated when a hidden image is shown again
  • Cross sections of images added or shown again — When an image was added to the plot, or shown again after having been hidden, while a cross-section marker or shape was active, its X/Y cross-section curves remained empty (image added) or showed the cross section at a former position of the marker (image shown again) until the marker was moved. These curves are now computed as soon as the image is shown, unless the auto-refresh of the cross-section panel is disabled. The shade under the cross-section curves no longer fades as hidden images accumulate in the plot (closes Issue #89)
  • Custom colormaps location — Custom colormaps were saved in a .none directory of the user's configuration directory (~/.config/.none on Linux, %USERPROFILE%\.none on Windows), shared by all applications whatever their own configuration directory, and this directory was created as soon as colormaps were loaded. Custom colormaps are now saved in PlotPy's configuration directory (.plotpy by default) or, if the application sets the name of PlotPy's configuration with plotpy.config.CONF.set_application (e.g. "MyApp/plotpy"), in the configuration directory of this application, from which they are reloaded even if the name is set after PlotPy was imported. The first time, custom colormaps saved in the former .none and .plotpy directories are copied to the new location, without modifying the former files. Looking up the location of PlotPy's configuration files no longer creates any directory (closes Issue #70)
  • Anti-aliasing interpolation — With the anti-aliasing interpolation, replacing the data of an image by data of another type (e.g. 16-bit integers by floating-point numbers) made the next drawing of the image fail, which aborted the application with PyQt5. Exporting an image area with its interpolation but without its contrast settings (e.g. with the rectangle snapshot tool) failed with TypeError: AA Mask data type must be ... errors when the Z-axis logarithmic scale was enabled, or after such a data type change. Images are now drawn and exported whatever their data type and their Z-axis scale (closes Issue #89)
  • Python and libraries information — plotpy.widgets.about.get_python_libs_info and the plotpy-benchmarks script failed with AttributeError: module 'guidata.widgets.about' has no attribute 'get_python_libs_info' (closes Issue #89)

⚡ Performance:

  • Plot refresh — Refreshing a plot no longer recomputes the plot layout when the title and axis styles did not change
  • Item tools and item list — Updating the status of item-related tools and of the item list panel is no longer quadratic in the number of plot items
  • Image creation — Creating an image item no longer recomputes the colormap lookup table when the same colormap, inversion and transparency settings were already used: the table (more than 1000 colormap evaluations) is computed once and reused, which saves a few milliseconds per image
  • Curves on high-DPI screens — With a display scaling factor such as 125 % or 150 %, curves and error bars of width 1 were drawn wider than one screen pixel, which made their rendering up to several hundred times slower on noisy signals (about 800 ms instead of 3 ms for a 2000-point curve at 150 %). Curves and error bars of width 1 or less are now drawn one screen pixel wide on screen; printing and exporting are not affected. The new curve/cosmetic_hairline option of the plot configuration section restores the previous behavior (closes Issue #80)
  • Thick curves — Curves wider than one screen pixel are now drawn on screen as several one-pixel strokes, slightly offset from each other, which looks almost the same as before but is 30 to 50 times faster on noisy curves: a 2000-point curve of width 2 takes about 10 ms instead of 370 ms to draw with antialiasing. Dash patterns are scaled as before. Printing and exporting, curves with a translucent color and curves wider than 8 screen pixels still use the original pen. The new curve/fast_thick_lines option of the plot configuration section restores the previous behavior (closes Issue #82)

⚙️ Dependencies:

  • Python 3.10 or later is now required, and wheels are no longer built for Python 3.9. Python 3.9 users must keep an earlier compatible release (PlotPy 2.11.x) (closes Issue #74)

🔧 Other changes:

  • Continuous integration — PlotPy is now also tested with PyQt6 and PySide6 (Python 3.10 and 3.14) on each push and pull request, and with PyQt6 before each PyPI release. Pull requests targeting the develop or release branch are now tested against the development versions of guidata and PythonQwt, as pushes to these branches already were (closes Issue #69)
  • Test suite — The SnapshotTool annotation test no longer hangs when run on its own, on Windows or with Qt 6: it waited indefinitely for the snapshot dialog to be closed

v2.11.1

Choose a tag to compare

@ThomasMalletCodra ThomasMalletCodra released this 01 Oct 14:54
v2.11.1
300efd3

PlotPy Version 2.11.1

🛠️ Bug fixes:

  • hist_range_threshold documentation — Fixed the docstring of plotpy.lutrange.hist_range_threshold, which stated that percent was the share of the histogram mass to retain, whereas it is the share to eliminate (half on each side). The error message raised for an out-of-range percent now matches the accepted range [0, 100]

📚 Documentation:

  • Migrating from guiqwt — Updated the migration guide to match the current API:
    • Fixed outdated targets (BasePlotWidget, BasePlot) and the contour demo script path
    • Updated the BasePlot constructor section: all configuration settings now go through BasePlotOptions
    • Added equivalents for canvas2plotitem/plotitem2canvas (plotpy.coords), mimedata2url (guidata.qthelpers), guiqwt.transitional (qwt package) and guidance for eliminate_outliers and guiqwt.signals
    • Completed the compatibility table with missing guiqwt modules and classes (builder, panels, config, ImagePlot, ImageWidget, ImageDialog, ImageWindow, ...)

v2.11.0

Choose a tag to compare

@ThomasMalletCodra ThomasMalletCodra released this 18 Aug 08:05
v2.11.0
7d28ac9

PlotPy Version 2.11.0

✨ New features:

  • Enhance contour builder with style parameters — Add color, linestyle and linewidth parameters to ContourLine item class

🛠️ Bug fixes:

  • Image cross sections — Restored live cross-section updates when using Alt+Mousemove over an image. This regression had been introduced in v2.1.0: the X/Y cross-section panels no longer received marker-change updates because method resolution order was shadowing the mixin hook that connects SIG_MARKER_CHANGED (closes Issue #68)

  • Empty Label ledend box crash prevent — When plot items list is empty, LegendBoxItem could crashes while clicking on it. Fix and tests added

v2.10.0

Choose a tag to compare

@ThomasMalletCodra ThomasMalletCodra released this 02 Jun 14:16
v2.10.0
c5c1213

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

Choose a tag to compare

@ThomasMalletCodra ThomasMalletCodra released this 20 Apr 08:22

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

Choose a tag to compare

@PierreRaybaut PierreRaybaut released this 14 Feb 16:56

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

Choose a tag to compare

@PierreRaybaut PierreRaybaut released this 18 Dec 09:42

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

Choose a tag to compare

@PierreRaybaut PierreRaybaut released this 12 Nov 15:47

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

Choose a tag to compare

@PierreRaybaut PierreRaybaut released this 06 Nov 08:01

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

Choose a tag to compare

@PierreRaybaut PierreRaybaut released this 24 Oct 14:34
Immutable release. Only release title and notes can be modified.

💥 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