Releases: JetBrains/lets-plot-kotlin
v4.13.0
[4.13.0] - 2026-03-20
This release is 100% compatible with Lets-Plot v 4.9.0,
GeoTools v 33.2
Added
-
Plot Annotations:
-
New
labelsparameter ingeomSmooth()designed to display statistical summaries of the fitted model directly on the plot.
This parameter accepts asmoothLabels()object, which provides access to model-specific variables like$R^2$ , the regression equation and others [#1388].See: example notebook.
-
Plot tags. A tag can be specified via
labs(tag = ...)and styled using theme parameters [#1407].See: example notebook and updated Plot Layout Diagrams.
-
Plot tags customization parameters in
theme():-
plotTag- sets the tag style viaelementText(). -
plotTagLocation- specifies the area used for positioning the tag. -
plotTagPosition- specifies the position of the tag within the selected area. -
plotTagPrefix- text added before the tag value. -
plotTagSuffix- text added after the tag value.
See: example notebook.
-
-
-
Geometries:
-
New
geomBracket(),geomBracketDodge()[#1114].See: example notebook.
-
geomImshow():-
Support for custom colormaps [#780].
-
New
cguideparameter: use to customize the colorbar for grayscale images.See: example notebook.
-
-
-
Color Scales:
-
New
palette()method for color scales: generates a list of hex color codes that can be used withscaleColorManual()orscaleFillManual()to maintain consistent colors across multiple plots [#1444].See: example notebook.
-
New
overflowparameter inscaleColorBrewer()/scaleFillBrewer(): controls how colors are generated when more colors are needed than the palette provides.
Options:"interpolate"("i"),"cycle"("c"),"generate"("g").See: example notebook.
-
-
Positional Scales:
-
New
breakWidthparameter that specifies a fixed distance between axis breaks.See examples:
-
Support for axis minor ticks via
axisMinorTicksandaxisMinorTicksLengthparameters intheme()[#1379].See: example notebook.
-
-
gggrid(): interactive pan/zoom now propagates across subplots with shared axes (sharex/sharey) [#1413].See: example notebook.
-
Swing Apps:
Support for plot default interactions and custom toolbar component.
For more details, see Interactions demo in the "lets-plot-mini-apps" repository.
Changed
-
Kotlin: v2.2.20 (was v1.9.25).
-
Artifact changes in the core Lets-Plot library (v4.9.0):
- New artifact for JVM Swing applications:
org.jetbrains.lets-plot:lets-plot-swing.
This artifact provides theSwingPlotPanelclass, which can be used to display plots in Swing applications instead of the now-obsoleteDefaultPlotPanelBatik.
For details, see the jvm-swing-app example in the "lets-plot-mini-apps" repository. - [BREAKING]: Removed JavaFX artifacts.
Theorg.jetbrains.lets-plot:lets-plot-jfxartifact is no longer available.
Replace it with neworg.jetbrains.lets-plot:lets-plot-swingdependency and useSwingPlotPanelinstead ofDefaultPlotPanelJfx.
For details, see the jvm-javafx-app example in the "lets-plot-mini-apps" repository. - [BREAKING]: Removed
plot-image-exportmodule.
Theorg.jetbrains.lets-plot:lets-plot-image-exportartifact is no longer available.
ThePlotImageExportutility has been moved to theplatf-awtmodule:org.jetbrains.letsPlot.awt.plot.PlotImageExport.
The requiredorg.jetbrains.lets-plot:platf-awtdependency is likely already present in your project.
- New artifact for JVM Swing applications:
-
[BREAKING]: ColorBrewer palettes: changed default behavior when the requested number of colors exceeds the palette's maximum size.
Now defaults to"interpolate"for sequential/diverging palettes and"generate"for qualitative palettes.
Previously, depending on the palette type, this either resulted in duplicate colors or random additional colors.
Use the newoverflowparameter to explicitly control this behavior. -
Missing values in
geomAreaRidges()create gaps in geometries instead of being interpolated over. -
Discrete color scales (Brewer, Manual) now produce a
colorbarguide when used with continuous data.
Previously they produced alegendguide regardless of the data type.
Fixed
- Drop commons-io dependency [#1421].
- Unexpected replacement of double curly brackets with a single curly bracket [#1433].
- geom_imshow: unclear error message when mixing transparencies [#1088].
- geom_imshow and scale_y_reverse [#1210].
- Nice to be able to get a list of colors from a color scale object [#1444].
- Allow tooltips param to accept list [#1455].
- Allow grouped tooltips for plots with multiple univariate geoms [#1460].
- Fixed a regression in
geomTextRepel()/geomLabelRepel(): points with empty labels were incorrectly skipped
before building the repel obstacle set, so they were not included in collision avoidance and labels could overlap
dense point clusters.
v4.12.1
v4.12.0
[4.12.0] - 2025-12-02
This release is 100% compatible with Lets-Plot v 4.8.1,
GeoTools v 33.2
Added
-
Geometries:
-
geomPointDensity()[#1370].See: example notebook.
-
Geoms with 1-to-1 statistics (such as
geomQQ(),geomSina()) preserve the mapping to original data after statistical transformation.See: example notebook.
-
geomHistogram(): custom bin bounds (parameterbreaks) [#1382].See: example notebook.
-
-
Plot Layout:
-
The legend automatically wraps to prevent overlap - up to 15 rows for vertical legends and 5 columns for horizontal ones [#1235].
See: example notebook.
-
gggrid(): support for shared legends (parameterguides).See: example notebook.
-
-
Plot Theme:
-
flavorStandard()sets the theme's default color scheme [#1277].
Use to override other flavors or to make defaults explicit.See: example notebook.
-
themeGray()as an alias forthemeGrey(). -
New
themefunctions for setting legend justification:legendJustificationTop(),legendJustificationRight(),
legendJustificationBottom(), andlegendJustificationLeft().See: example notebook.
-
Support for inward axis ticks.
See: example notebook.
-
-
Markdown:
- Support for
targetattribute for links. - Links now open in a new tab by default [#1397].
- Support for
-
ggtb():sizeZoominandsizeBasisparameters for geometry scaling [#1369].See: example notebook.
-
New
outputparameter for the library descriptor to control output types stored in notebook cells [LPK-277].
Thanks to AndreiKingsley for the contribution!%use lets-plot(output="js, png")Available output types:
js- Classic Web output: HTML+JSktnb- Kotlin Notebook Swing-based renderingsvg- Static SVG outputpng- Static PNG output
Default:
"js, ktnb, svg"Note: Static images (SVG/PNG) are hidden when
jsorktnboutputs are present, and only displayed in environments where JavaScript is not executed (e.g., GitHub).This option can be helpful when a Kotlin Notebook file size becomes a problem.
For example, when working with large datasets where plot interactivity is not a priority, storing only static output (SVG or PNG) can significantly reduce file size. -
CenteredPlotPanelhelper class for displaying plots centered in Swing applications.
Changed
-
[BREAKING] Explicit
groupaesthetic now overrides default grouping behavior instead of combining with it [#1401].See: example notebook.
Important
Previously, setting group="variable" would group by both the explicit variable AND any discrete
aesthetics (color, shape, etc.).
Now it groups ONLY by the explicit variable, matching ggplot2 behavior.
Use group=listOf(var1, var2, ...) to group by multiple variables explicitly,
and group=emptyList<Any>() to disable any grouping.
-
Missing values in
geomLine(), geomPath(), geomRibbon(), andgeomArea()create gaps in geometries instead of being interpolated over [LPK-269],[#818], [#1406].See: example notebook.
-
theme: theexponentFormatdefault value changed to"pow"- superscript powers of 10 (was e-notation). -
The multi-layer line plot now shows tooltips for each series simultaneously, in the same way that a single-layer plot with color mapped to series does.
Fixed
- Group by multiple columns [LPK-136].
geomPieon geospatial plot withmapJoinfailes to render without explicitgroupaesthetic.geomDensity2D: NullPointerException when weight aesthetic contains None values [#1399].- Tooltip shows duplicate lines when as_discrete is applied twice to the same var [#1400].
geomSina: incorrect shape in legend [#1403].geomDensity2D: Incorrect processing of weighted statistics when None value occurs in the x or y column.facetWrap: indescriptive error when the specified facet variable is not present in the dataset [#1409].- Integer numbers in facet strip titles are displayed as float [#1386].
- Error when using
scaleIdentity(aesthetic="shape")[#1212]. ggsave: theme optionface="italic"doesn't work [#1391].- Fail early if string format is incorrect [#1410].
statECDF()takes a very long time for even moderately sized datasets [#1424].- inconsistencies in theme/flavor inheritance in
gggrid()subplots.
v4.11.2
[4.11.2] - 2025-09-12
This release is 100% compatible with Lets-Plot v 4.7.3,
GeoTools v 33.2
Changed
ggsave(): large plot dimensions without units now require explicitunitspecification.
When plot size exceeds 20 without specifying units (e.g.,ggsave(p, w=300, h=400)),
we ask to specify units explicitly:
ggsave(p, w=300, h=400, unit="px")orggsave(p, w=3, h=4, unit="in").
Fixed
ggtb()support in Swing/Batik frontend [LPK-265].- Multiline support for axis labels in polar coordinates.
- When the plot size in
ggsave()is specified in pixels,dpinow affects
only the physical size, not the pixel dimensions as before. - Blocking
SwingUtilities.invokeAndWait()call on plot image export (JVM app)
v4.11.1
[4.11.1] - 2025-09-02
This release is 100% compatible with Lets-Plot v 4.7.2,
GeoTools v 33.2
Added
-
Facets Layout:
-
New
strip_spacing,strip_spacing_x, andstrip_spacing_yparameters intheme()to control spacing between the facet strip (title bar) and the plot panel. -
New
panel_spacing,panel_spacing_x, andpanel_spacing_yparameters intheme()to control spacing between plot panels in faceted plots, [#1380].See: example notebook.
-
-
ggsave():w,handunitparameters support [#281],
[#1368].
See: example notebook.
Changed
-
facetWrap()now drops factor levels that do not appear in the data (i.e., empty panels) by default [#1322].
To keep unused factor levels, use the newdropparameter, i.e.,drop=false.See: example notebook.
-
Facets Layout:
- Removed extra spacing between facet strips and plot panels in
facetWrap()andfacetGrid().
- Removed extra spacing between facet strips and plot panels in
-
ggsave(): removed Batik dependency (now uses lets-plot's built-in rasterizer).
Fixed
- Tooltip for a line have higher priority than points, even if the point is specified first in the layer list [#1060].
geomRibbon(): tooltip appears in the wrong place on flipped ribbon [#1334].- Coordinate limits do not work on reversed scales [#1365]
- Misaligned axis labels and ticks in polar coordinates.
- Display order of fill categories not being set correctly in stacked plots? [#1367]
- Unclear error when using
geomRectwith discrete scales [#1287] xlim()breaks defaultscaleXDateTime()[#1348]scaleXReversebreaks datetime formatting [#1257]theme(plotTitle="blank")doesn't work withgggrid[#1349]- theme: error parsing color value pen [#1216]
- Incorrect appearance of stacked density plot in polar coordinates [#1375]
v4.11.0
[4.11.0] - 2025-07-25
This release is 100% compatible with Lets-Plot v 4.7.0,
GeoTools v 33.2
Added
-
Time Series Plotting [#278],
[discussion],
[#678],
[LPK-129]:- Support temporal data types from
kotlinx.datetime,java.time, andjava.util. - Support for timezone-aware
java.time.ZonedDateTimeandjava.time.OffsetDateTimeobjects.
See examples:
- Support temporal data types from
-
Geometries:
-
geomSina()[#1298].See: example notebook.
-
geomTextRepel()andgeomLabelRepel()[#1092].See: example notebook.
-
-
Layer Labels (Annotations):
-
Support in
geomCrossbar()See: example notebook.
-
Support in
waterfallPlot()viarelativeLabelsandabsoluteLabelsparameters.See: example notebook.
-
New
inheritColor()option in annotations' configuration (see example notebooks above)
-
-
waterfallPlot()- support for combining waterfall bars with other geometry layers [#1344].See: example notebook.
-
Plot Layout:
- New
axisTextSpacing,axisTextSpacingX, andaxisTextSpacingYparameters intheme()to control spacing between axis ticks and labels. - See new Plot Layout Diagrams showing various layout options and their effects on plot appearance.
- New
-
More variants to specify a color by name:
- all HTML/CSS colors;
- various naming styles, e.g.,
"dark-gray","darkgrey","dark_grey","DARKGRAY", etc.; - grayscale colors from
"gray0"(black) to"gray100"(white);
-
sizeUnitparameter ingeomPoint(),geomText/Label()andgeomPie()accepts two new values:"min"and"max"[#260]."min"sets the size unit to the smaller of the unit steps along the x and y axes, while"max"sets it to the larger.
This allows for more flexible relative sizing of points, pies and text in plots.See: example notebook.
Changed
-
Continuous data on discrete scales:
Continuous data when used with discrete positional scales is no longer transformed to discrete data.
Instead, it remains continuous, allowing for precise positioning of continuous elements relative to discrete ones.
This resolves issues where combining discrete and continuous data in the same plot was difficult or impossible: [#1279].See: example notebook.
Tip
New way of handling continuous data on discrete scales could potentially break existing plots.
If you want to restore a broken plot to its original form, you can use the asDiscrete() function to annotate continuous data as discrete.
- [BREAKING]
geomBoxplot(): when y-oriented, it now uses aestheticsxlower/xmiddle/xupperinstead oflower/middle/upper[#1319]. - [BREAKING]
waterfallPlot(): special "flow_type" value forlabel=elementText(color=...)replaced with "inherit". Seelabelin the documentation. - [DEPRECATED] The
positionDodgeV()function and the"dodgev"value for thepositionparameter are deprecated and will be removed in future releases. - Plot layout: reduced margins and spacing for title, caption, axes, and legend.
- Updated RGB values for
"lightgray"and"green". To restore the previous colors, use"gray75"and"lime", respectively. waterfallPlot(): the appearance of the legend has been improved.geomViolin(): tooltips are not shown in the centerline of the violin ifshowHalf != 0.geomCrossbar(): the midline is not shown in the legend whenfattenis set to 0, or when there is no mapping for it.geomPointrange(): the midpoint will not be drawn if theyaesthetic is set tonull.geomBand(): thealphaaesthetic only affects the inner part of the geometry, as ingeomRect().geomBand(): show tooltip over the whole band, not just at the edges.
Fixed
- AWT: plot prevents wheel events from bubbling up to the parent component.
geomBoxplot: unable to draw a y-oriented plot withstat = Stat.identity[#1319].- Can't add a layer which uses continuous data to a plot where other layers use discrete input [#1323].
- Multiline legend labels were not vertically centered with their keys [#1331].
- Poor alignment in legend between columns [#1332].
- Ordered data was re-ordered by
geomBoxplot[#1342]. - Sec: CVE-2024-47554 (commons-io) [#1231]
- java.util.zip.ZipException: duplicate entry: letsPlotKotlinAPI/version.properties [#279]
v4.10.0
[4.10.0] - 2025-03-20
This release is 100% compatible with Lets-Plot v 4.6.1,
GeoTools v 32.1
Added
-
Grouping plots:
-
ggbunch()function: combining plots with custom layout.See demos:
-
Support for plot title, subtitle, caption, margins and insets in
gggrid()andggbunch().
-
-
Geometries:
-
geomHex()[#556].See example notebook.
-
Parameters
widthUnitingeomErrorBar(),geomBoxplot(),geomCrossbar()[#1288].widthUnitandheightUnitingeomTile()andgeomHex().
See example notebook.
-
Parameters
startanddirectioningeomPie()[#1280].See example notebook.
-
-
Texts and labels:
-
hjustandvjustparameters for axis labels [#1227],[#1230].See: example notebook.
-
Multiline support for axis labels [#948].
See: example notebook.
-
Markdown support for plot title, subtitle, caption, and axis labels [#1256].
See example notebook.
-
-
In the
nudgeposition adjustment -
the ability to specify absolute shift values fornudge:unitparameter inpositionNudge().nudgeUnitparameter ingeomText()andgeomLabel()
See example notebook.
-
Theme:
-
Parameters
legendTicksandlegendTicksLengthfor fine-grained control over colorbar tick marks [#1262].See: example notebook.
-
-
Aliases for transparent color:
""(blank string),"blank"and"transparent"color [#1281].
Changed
- [DEPRECATED] class
GGBunchis deprecated. Please useggbunch()function instead. - [BREAKING] The
heightparameter has been deprecated for thegeomErrorBar. - Axis breaks: the minimum distance between axis labels was reduced to avoid unsuitable layouts.
- Axis breaks: changed default
lower_exp_boundto -7 andupper_exp_boundto 6 (same as intheme(...)). - Axis labels: changed default justification for rotated labels.
- Axis labels: changed orientation of automatic vertical labels.
- [BREAKING] geoms
tile, bin2d, contour, contourf, density2d, density2df: default coordinate system changed from 'fixed' to 'cartesian'. - [BREAKING] tiles in
geomBin2d()are sized according to thebinwidthvalue, not the maximum possible. - [BREAKING] In Lets-Plot JS API v 4.6.0 (only Lets-Plot/JS users): signature of "buildPlotFromXXX" functions changed, see current Kotlin/JS declarations:
- [BREAKING] In Lets-Plot v 4.6.0, Maven artifacts:
- artifacts
platf-awt,platf-batik,platf-jfx-swingare no longer published with a "-jvm" suffix.
Before, these artifacts could be used in dependencies either with or without the "-jvm" suffix. Now only without suffix. - artifact "org.jetbrains.lets-plot:deprecated-in-v4-jvm" is removed.
- artifacts
Fixed
- Incorrectly rendered Area chart [#1295].
- Tooltip should not cover and hide the geometry that it provides info for [#1275].
- General purpose
scaleContinuous: can't use theexpandparameter [#1285]. - Error when using
stat='summary'if the data contains NaN values [#1301]. - Broken
plotBackgroundingggrid[#1124]. plotBackgroundnot inheriting fromrect[#1278]gggrid: allow title and other labels for the entire figure [#715].ggbunch: overall title [#321].- Expand discrete axis according to tile size with
geomTile[#1284].
v4.9.3
[4.9.3] - 2024-12-16
This release is 100% compatible with Lets-Plot v 4.5.2,
GeoTools v 32.1
Changed
- Number formatting:
- We have aligned our specifications with D3.js (rather than Python):
gformat type with~(e.g.~g) now truncates trailing zeros, and without~it doesn't. - The default number formatter now respects
theme(exponent_format=...)settings and does not use 's' format type for large numbers.
- We have aligned our specifications with D3.js (rather than Python):
- Legends with more than 200 items are now not rendered.
Fixed
- Bad precision in the default tooltip format when using coord limits [#1134].
- Display integer values without fractional part in tooltips [#1186].
- Suboptimal tooltip positioning in facets [#1187].
- Incorrect Y-axis layout with facets and panel_inset [#1194].
- Grouped plot hits the limit of 1000 and doesn't render with not-friendly exception [#1224].
- Kandy toPNG reports NullPointerException [#1228]
- Wrong formatting when type='g' for small values [#1238].
- Formatting when type='g' for large values throws exception [#1239].
- Wrong formatting when type='s' with explicit precision [#1240].
- Extra trim in formatted number when type='g' [#1241].
- Axis breaks are badly formatted if explicitly set [#1245].
- Badly formatted zero break for the "~g" format [#1246].
- How to adjust the vertical position of geom_text when using position_dodge [#1248].
- Incorrect result for format(9.999, ".2f") [#1251].
- Tooltips overlapping when not enough vertical space for them [#1254].
- Plot limited to 1000 lines (Internal error: IllegalStateException : Too many groups: 1099) [#1261].
- Nice to have tooltip to inherit formatting configured for axis [LPK-229].