Repository navigation
Releases: PlotPyStack/PlotPy
Release list
v2.12.1
PlotPy Version 2.12.1
🛠️ Bug fixes:
- Images on high-DPI screens — With a display scaling factor such as 125 %, 150 % or 200 %, images were rendered at the resolution of the plot canvas and then upscaled to the screen resolution: with a 200 % scaling, images were shown with half the resolution of the screen, and with a 125 % scaling, one screen pixel row and column out of five were duplicated, which made fine image details (e.g. noise, thin lines) look irregular. Images are now rendered at the resolution of the screen; printing and exporting are not affected. Rendering images at the screen resolution takes more time: for a 2000 × 2000 image shown in a 700 × 700 plot, about 8 ms instead of 7 ms with a 125 % scaling and 19 ms instead of 7 ms with a 200 % scaling (104 ms instead of 28 ms with the anti-aliasing interpolation). The new
image/device_resolutionoption of theplotconfiguration section restores the previous behavior - Raw image items —
RawImageItemobjects were not drawn: each redraw failed withValueError: Invalid destination rectangle (expected tuple of 4 integers) - Blurry icons with display scaling — PlotPy's icons (toolbar tools, item list, curve, marker and line styles, brush patterns, ...) were 16×16 pixel PNG images, which looked blurry with a display scaling greater than 100 % (e.g. 125 %, 150 %, 200 %). They are now SVG images, which remain sharp at any display scaling. Applications requesting a PlotPy icon by its former PNG name (e.g.
get_icon("csection.png")) still get it with guidata 3.17.1 or later, whoseget_image_file_pathfalls back to the SVG image with the same name. The notices of the original artwork are provided inplotpy/data/icons/LICENSES.txt(fixes Issue #91) - Icon name conflicts — Several PlotPy icons share their names with icons of guidata or of applications (e.g.
image.svg,histogram.svg,apply.svg,delete.svg): with guidata 3.17.1, which gives precedence to the icons of applications and warns about ambiguous image names, PlotPy designates these icons explicitly (e.g."plotpy:image.svg","guidata:apply.svg"), so that its widgets keep their icons in applications. The icons that were exact copies of guidata icons (editors, file types, ...) are no longer shipped by PlotPy, which uses those of guidata (fixes Issue #93) - Image lock tool icon — The "Lock" tool of transformable images showed the "not found" icon until an image was selected: it now shows the lock icon
- Blurry Save as, Help, Open and Save items icons — With a display scaling greater than 100 % (e.g. 150 %, 200 %), the icons of these tools were blurry, as their standard Qt icon was frozen to a 16-pixel image upscaled to the toolbar icon size: they now keep all the resolutions of the icon and are shown at the same size as the other toolbar icons (fixes Issue #95)
⚡ Performance:
- Moving shapes over images — Moving or resizing a shape, a marker, a cursor or an annotation over an image, or drawing a new shape, rendered the image again for each mouse move, although it did not change. The previous rendering of the image is now drawn again instead, unless the image itself, the plot axes or the plot size change: with a 2048 × 2048 image, each mouse move takes about 4 ms instead of 7 to 68 ms depending on the interpolation, and about 10 ms instead of 17 to 175 ms with a 200 % display scaling (see the
plotpy/tests/benchmarks/test_image_interaction.pybenchmark). The newBasePlot.replot_overlaysmethod redraws a plot in this way, when only items drawn over images have changed: image items whosedraw_imagemethod is decorated withplotpy.items.image.base.reusable_renderingdraw their previous rendering again. As before, any other change of an image item (data, mask, contrast, colormap, ...) must be followed byBasePlot.replotorBasePlot.invalidate - Masked images — The mask of masked images (
MaskedImageItem,MaskedXYImageItem) is no longer rendered when it is not visible, i.e. when no pixel is masked and the unmasked area is transparent (default): rendering a masked image without masked pixels, e.g. while panning or zooming, is up to 25 % faster
v2.12.0
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_indicesreturns the indices of the points kept, the newminmax_downsampling_indicesfunction computes them, and theCurveItem.frozen_downsamplingcontext 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_fulland thelut_rangeargument ofset_datanow use data units instead of base-10 logarithms, and the newBaseImageItem.supports_zaxis_logmethod 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 overflowederrors 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. Typingnanorinfin 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
.nonedirectory of the user's configuration directory (~/.config/.noneon Linux,%USERPROFILE%\.noneon 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 (.plotpyby default) or, if the application sets the name of PlotPy's configuration withplotpy.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.noneand.plotpydirectories 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_infoand theplotpy-benchmarksscript failed withAttributeError: 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_hairlineoption of theplotconfiguration 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_linesoption of theplotconfiguration 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
developorreleasebranch are now tested against the development versions of guidata and PythonQwt, as pushes to these branches already were (closes Issue #69) - Test suite — The
SnapshotToolannotation 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
PlotPy Version 2.11.1
🛠️ Bug fixes:
hist_range_thresholddocumentation — Fixed the docstring ofplotpy.lutrange.hist_range_threshold, which stated thatpercentwas 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-rangepercentnow 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
BasePlotconstructor section: all configuration settings now go throughBasePlotOptions - Added equivalents for
canvas2plotitem/plotitem2canvas(plotpy.coords),mimedata2url(guidata.qthelpers),guiqwt.transitional(qwtpackage) and guidance foreliminate_outliersandguiqwt.signals - Completed the compatibility table with missing guiqwt modules and classes (
builder,panels,config,ImagePlot,ImageWidget,ImageDialog,ImageWindow, ...)
- Fixed outdated targets (
v2.11.0
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+Mousemoveover 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 connectsSIG_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
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
edgewidthparameter toSymbolParamfor 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 forXYImageItem(and any item with non-uniform
axis scaling) regardless of axis orientation - The
ValueErrorraised 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 bothImageItemandXYImageItem
(previouslyXYImageItemreportedshape - 1whileImageItem
reported the full oversized resolution): exporting at "Original size"
now consistently preserves the source pixel density and avoids
upsampling, regardless of the item type
- The preview no longer displays negative dimensions when the X or Y axis is
- 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
ZAxisLogToolbeing always disabled for non-ImageItemimage types (XYImageItem,MaskedImageItem,MaskedXYImageItem,TrImageItem,RGBImageItem). The Z-axis log API (get_zaxis_log_state/set_zaxis_log_state) was moved fromImageItemup toBaseImageItemso 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— Replacedmin/max/mean/std/sumwith 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
PlotPy Version 2.9.0
💥 New features:
- Added
QuiverItemfor displaying 2D vector fields (quiver plots), similar to
Matplotlib'squiver. This closes
Issue #54:- New
QuiverItemplot 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
- New
- 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_paramnow 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
ErrorBarCurveItemnow correctly returns the closest bar end coordinate.
Previously a typo (abs(y - y)/abs(x - x)instead ofabs(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_projectionraising 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
ValueErroron empty arrays and emittingRuntimeWarningon 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.pyto support multiple
Python environment contexts (WinPython, venv, etc.) with legacy support for the
WINPYDIRBASEenvironment variable
v2.8.4
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 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 raisingRuntimeError - 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 withexec()
- Use
- 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 canvas - Start the spiral at
t=2πto ensure sufficient pixel spacing between consecutive points
- The spiral test data started at
- Fixed pytest running all tests when selecting a single test from VS Code:
- Move
plotpyfromaddoptstotestpathsin[tool.pytest.ini_options]
- Move
🔧 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 building - Add
.venv*to.gitignoreto exclude virtual environment files
v2.8.3
PlotPy Version 2.8.3
💥 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 point - Previously, loading such images in DataLab caused an
IndexError: index 1 is out of bounds for axis 0 with size 1
- The
- 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
v2.8.2
Version 2.8.2
🛠️ Bug fixes:
- Fixed
RuntimeWarningwhen changing masked image data type from float to integer:MaskedImageItem.update_mask()now handles NaN and Nonefilling_valuegracefully- 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
XYImageItemandMaskedXYImageItem:- Added
IExportROIImageItemTypetoXYImageItem.types()so thatget_items_in_rectangle()can properly identify XY image items - Updated
__implements__tuples for consistency acrossXYImageItem,MaskedXYImageItem, andMaskedImageItem - The tool now correctly displays statistics for images with non-uniform coordinates
- Added
- Fixed snapshot tool failing with
SystemErroronXYImageItemandMaskedXYImageItem:- Fixed
assemble_imageitemspassing list instead of tuple to C extension function_scale_rect - Added missing
export_roimethod toXYImageItemto properly handle non-uniform coordinate transformations - Snapshots of XY images now render correctly instead of producing black images
- Fixed
Version 2.8.0
💥 New features / Enhancements:
- Curve fitting: added support for locked parameters:
- New
lockedparameter inFitParamclass to lock parameter values during automatic optimization - New
lockedfield inFitParamDataSetto 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
- New
- Configurable autoscale margin:
- Added
autoscale_margin_percentparameter toBasePlotOptionsfor intuitive percentage-based margin control - Users 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)
- Added
- Image statistics tool improvements:
- Enhanced
get_statsfunction to display delta (Δ) values for coordinate ranges - Now shows Δx, Δy, and Δz values alongside the min/max ranges for better analysis
- Enhanced
- 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 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)
- New
- 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)
- This tool is similar to the existing
- 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
- Added support for item title in parameters data set (
- New annotated X and Y range selection items:
- Added
AnnotatedXRangeandAnnotatedYRangeitems - These items provide X and Y range selection with an annotation label
- They can be created using
make.annotated_xrangeandmake.annotated_yrangefunctions
- Added
- 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 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
strftimeformat 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 CurveStatsToolnow 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
ObjectInfobase class to provide shared datetime formatting methods for code reuse
- Cursor tools (
- Added
🧹 API cleanup: removed deprecated update methods (use update_item instead)
- Removed
AnnotationParam.update_annotationmethod - Removed
AxesShapeParam.update_axesmethod - Removed
AxesParam.update_axesmethod - Removed
ImageAxesParam.update_axesmethod - Removed
LabelParam.update_labelmethod - Removed
MarkerParam.update_markermethod - Removed
RangeShapeParam.update_rangemethod - Removed
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 close - Added
handle_show_event()andhandle_close_event()methods toBaseSyncPlotfor proper timer lifecycle management - Refactored
showEvent()andcloseEvent()in bothSyncPlotWindowandSyncPlotDialogto 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_modeandlockscalesoptions for consistent scaling behavior across all code paths - The
update_plot()method now delegates all scaling logic toplot_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)
- Streamlined handling of
- 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]) / 2 - Fixed
get_pixel_coordinates()to correctly convert plot coordinates to pixel indices usingsearchsorted()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.xandXYImageItem.ystore 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
XYImageItemAPI
- Root cause:
- 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 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
- Corrected the calculation of maximum indices in
- Fixed plot update after inserting a point using the
EditPointToolon non-Windows platforms - Issue #46 - Contrast adjustment with 'Eliminate outliers' failed for float images with high dynamic range
- Issue #29 - SelectTool: Selectin...
v2.8.1
Version 2.8.1
🛠️ 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 items - Updated
__implements__tuples for consistency acrossXYImageItem,MaskedXYImageItem, andMaskedImageItem - The tool now correctly displays statistics for images with non-uniform coordinates
- Added
- Fixed snapshot tool failing with
SystemErroronXYImageItemandMaskedXYImageItem:- Fixed
assemble_imageitemspassing list instead of tuple to C extension function_scale_rect - Added missing
export_roimethod toXYImageItemto properly handle non-uniform coordinate transformations - Snapshots of XY images now render correctly instead of producing black images
- Fixed
Version 2.8.0
💥 New features / Enhancements:
- Curve fitting: added support for locked parameters:
- New
lockedparameter inFitParamclass to lock parameter values during automatic optimization - New
lockedfield inFitParamDataSetto 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
- New
- Configurable autoscale margin:
- Added
autoscale_margin_percentparameter toBasePlotOptionsfor intuitive percentage-based margin control - Users 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)
- Added
- Image statistics tool improvements:
- Enhanced
get_statsfunction to display delta (Δ) values for coordinate ranges - Now shows Δx, Δy, and Δz values alongside the min/max ranges for better analysis
- Enhanced
- 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 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)
- New
- 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)
- This tool is similar to the existing
- 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
- Added support for item title in parameters data set (
- New annotated X and Y range selection items:
- Added
AnnotatedXRangeandAnnotatedYRangeitems - These items provide X and Y range selection with an annotation label
- They can be created using
make.annotated_xrangeandmake.annotated_yrangefunctions
- Added
- 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 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
strftimeformat 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 CurveStatsToolnow 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
ObjectInfobase class to provide shared datetime formatting methods for code reuse
- Cursor tools (
- Added
🧹 API cleanup: removed deprecated update methods (use update_item instead)
- Removed
AnnotationParam.update_annotationmethod - Removed
AxesShapeParam.update_axesmethod - Removed
AxesParam.update_axesmethod - Removed
ImageAxesParam.update_axesmethod - Removed
LabelParam.update_labelmethod - Removed
MarkerParam.update_markermethod - Removed
RangeShapeParam.update_rangemethod - Removed
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 close - Added
handle_show_event()andhandle_close_event()methods toBaseSyncPlotfor proper timer lifecycle management - Refactored
showEvent()andcloseEvent()in bothSyncPlotWindowandSyncPlotDialogto 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_modeandlockscalesoptions for consistent scaling behavior across all code paths - The
update_plot()method now delegates all scaling logic toplot_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)
- Streamlined handling of
- 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]) / 2 - Fixed
get_pixel_coordinates()to correctly convert plot coordinates to pixel indices usingsearchsorted()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.xandXYImageItem.ystore 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
XYImageItemAPI
- Root cause:
- 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 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
- Corrected the calculation of maximum indices in
- Fixed plot update after inserting a point using the
EditPointToolon 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
ErrorBarCurveItemhandling of all-NaN data:- Fixed
ValueError: zero-size array to reduction operation minimum which has no identityw...
- Fixed