Version 2.8¶
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
objectinstead of C++ type strings (e.g.,"QMouseEvent","QEvent","QPointF") inSignaldeclarations — PySide6 segfaults with C++ type name stringsCheck QObject validity via
is_qobject_valid()before accessing widgets in__del__,closeEvent, and panel close operations — PySide6 segfaults on deleted C++ objects instead of raisingRuntimeErrorRestructure
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 parentReplace deprecated
exec_()calls withexec()
Fixed
test_multiline_toolfailing 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 canvasStart 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
plotpyfromaddoptstotestpathsin[tool.pytest.ini_options]
🔧 Other changes:
Add missing
setuptoolstorequirements.txt(dev)Update GitHub Actions to use latest artifact upload and download versions
Update
cibuildwheelversion to v3.3.1 for improved wheel buildingAdd
.venv*to.gitignoreto exclude virtual environment files
PlotPy Version 2.8.3 (2025-12-18)¶
💥 New features:
AnnotatedSegmentnew 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
IndexErrorwhen 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 pointPreviously, 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
AnnotatedObliqueRectangleandAnnotatedEllipse: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
PlotPy Version 2.8.2 (2025-11-10)¶
🛠️ Bug fixes:
Fixed
RuntimeWarningwhen changing masked image data type from float to integer:MaskedImageItem.update_mask()now handles NaN and Nonefilling_valuegracefullyWhen 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
PlotPy Version 2.8.1 (2025-11-06)¶
🛠️ Bug fixes:
Issue #50 - Fixed ImageStatsTool displaying “No available data” for
XYImageItemandMaskedXYImageItem:Added
IExportROIImageItemTypetoXYImageItem.types()so thatget_items_in_rectangle()can properly identify XY image itemsUpdated
__implements__tuples for consistency acrossXYImageItem,MaskedXYImageItem, andMaskedImageItemThe tool now correctly displays statistics for images with non-uniform coordinates
Fixed snapshot tool failing with
SystemErroronXYImageItemandMaskedXYImageItem:Fixed
assemble_imageitemspassing list instead of tuple to C extension function_scale_rectAdded missing
export_roimethod toXYImageItemto properly handle non-uniform coordinate transformationsSnapshots of XY images now render correctly instead of producing black images
PlotPy Version 2.8.0 (2025-10-24)¶
💥 New features / Enhancements:
Curve fitting: added support for locked parameters:
New
lockedparameter inFitParamclass to lock parameter values during automatic optimizationNew
lockedfield inFitParamDataSetto configure parameter locking via the settings dialogWhen 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_percentparameter toBasePlotOptionsfor intuitive percentage-based margin controlUsers can now specify autoscale margins as percentages (e.g.,
0.2for 0.2%,5.0for 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_statsfunction to display delta (Δ) values for coordinate rangesNow 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_taboption inBasePlotOptionsandPlotOptions(default:True)When set to
False, the “Axes” tab is hidden from item parameter dialogsThis 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
XRangeSelectionandYRangeSelectionitems
New annotated X and Y range selection items:
Added
AnnotatedXRangeandAnnotatedYRangeitemsThese items provide X and Y range selection with an annotation label
They can be created using
make.annotated_xrangeandmake.annotated_yrangefunctions
New
SyncPlotDialogclass: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 displayAdded
BasePlot.set_axis_limits_from_datetime()method to set axis limits using datetime objects directlySupports customizable datetime format strings using Python’s
strftimeformat codesConfigurable label rotation and spacing for optimal display
Example:
plot.set_axis_datetime("bottom", format="%H:%M:%S")for time-only displayExample:
plot.set_axis_limits_from_datetime("bottom", dt1, dt2)to zoom to a specific time rangeAdded
"datetime"as a valid scale type (alongside"lin"and"log") for axis configurationAdded datetime coordinate formatting support throughout PlotPy:
Cursor tools (
VCursorTool,HCursorTool,XCursorTool) now display datetime-formatted X/Y coordinatesCurveStatsToolnow displays datetime-formatted X coordinates for statistical computationsMarker labels automatically format coordinates as datetime when axis uses datetime scale
Coordinate display in the plot canvas now shows datetime format when appropriate
Refactored
ObjectInfobase class to provide shared datetime formatting methods for code reuse
🧹 API cleanup: removed deprecated update methods (use update_item instead)
Removed
AnnotationParam.update_annotationmethodRemoved
AxesShapeParam.update_axesmethodRemoved
AxesParam.update_axesmethodRemoved
ImageAxesParam.update_axesmethodRemoved
LabelParam.update_labelmethodRemoved
MarkerParam.update_markermethodRemoved
RangeShapeParam.update_rangemethodRemoved
ShapeParam.update_shapemethod
🛠️ Bug fixes:
Fixed
RuntimeErrorinSyncPlotWindowandSyncPlotDialogwhen 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 controllableQTimerinstances that can be stopped on widget closeAdded
handle_show_event()andhandle_close_event()methods toBaseSyncPlotfor proper timer lifecycle managementRefactored
showEvent()andcloseEvent()in bothSyncPlotWindowandSyncPlotDialogto eliminate code duplicationAdded early exit check in
rescale_plots()to prevent execution if the timer has been stoppedThis fix ensures clean widget shutdown and prevents Qt from attempting to access deleted C++ objects
Cross-section panels: Fixed autoscaling logic in
BaseCrossSectionPlotStreamlined handling of
autoscale_modeandlockscalesoptions for consistent scaling behavior across all code pathsThe
update_plot()method now delegates all scaling logic toplot_axis_changed()to avoid code duplication and ensure consistencyFixed 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:
XYImageIteminternally stores bin edges (length n+1) but several methods were incorrectly treating them as pixel centers (length n)Fixed
get_x_values()andget_y_values()to correctly compute and return pixel centers from stored bin edges:(edge[i] + edge[i+1]) / 2Fixed
get_pixel_coordinates()to correctly convert plot coordinates to pixel indices usingsearchsorted()with proper edge-to-index adjustmentFixed
get_plot_coordinates()to return pixel center coordinates instead of bin edge coordinatesFixed
get_closest_coordinates()to return pixel center coordinates instead of bin edge coordinatesAdded comprehensive docstring documentation explaining that
XYImageItem.xandXYImageItem.ystore bin edges, not pixel centersRemoved redundant pixel centering code in
CrossSectionItem.update_curve_data()that was working around these bugsThis 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
XYImageItemAPI
Fixed index bounds calculation for image slicing compatibility:
Corrected the calculation of maximum indices in
get_plot_coordinatesto ensure proper bounds when using NumPy array slicingPreviously, 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
EditPointToolon non-Windows platformsIssue #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
ErrorBarCurveItemhandling of all-NaN data:Fixed
ValueError: zero-size array to reduction operation minimum which has no identitywhen error bar curves contain only NaN valuesAdded proper checks in
boundingRect()anddraw()methods to handle empty arrays gracefullyError 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_CHANGEDsignal toBasePlotclassThis 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
ItemListWidgetnow 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 state now also sets the resizable state:
The PlotPy event system won’t prevent the user from moving the item by dragging the handles if the item is just not movable: it has to be not resizable, which is not intuitive.
This is now fixed
Range selection items (
XRangeSelection,YRangeSelection):Handles are now displayed only when the item is resizable
If the item is set as not resizable (using the
set_resizablemethod), the handles will be hidden
Fixed cursor label formatting error with percentage symbols:
Fixed
ValueError: unsupported format character '=' (0x3d)when cursor labels contain percentage signs followed by format specifiers (e.g., “Crossing at 20.0% = %g”)The issue occurred because old-style string formatting (
label % value) treated the%in percentage displays as format specifiersAdded robust fallback mechanism that tests label format once during cursor creation and uses regex-based replacement when needed
Performance optimized: format validation is done once at cursor creation time, not on every callback execution
Affects
vcursor,hcursor, andxcursormethods inCurveMarkerBuilder
Other changes:
API breakage: renamed annotations
AnnotatedShape.get_infosmethod toget_infoUpdated dependencies following the latest security advisories (NumPy >= 1.22)
Added
pre-commithook to runruff(bothruff checkandruff format) on commitAdded missing
buildoptional dependency to development dependencies inpyproject.tomlVisual Studio Code tasks:
Major overhaul (cleanup and simplification)
Removal of no longer used batch files