NEWS
ggbreak 0.2.2 (2026-09-22)
- the axis title of a broken plot is now drawn exactly once, whatever it comes from; the #85 entry of 0.2.0 was about the defect #53 fixed and assumed a title set with
labs(), and the report came back for a title given as the name of a position scale -- scale_x_continuous("test") -- where five things went wrong together. The labels of the figure were read off ggplot_build(plot)$plot$labels, which only holds what labs() set plus the aesthetic defaults, so a plot whose scale is named "test" reported its title as "x" and the copy hoisted above a bottom legend carried the wrong text; ggplot2::get_labs() is used now, which returns the completed labels. A window blanked its title with guides(x = guide_axis(title = NULL)), and that does not beat the name of a scale, so scale_wrap() and the cut scales printed the title once per window; the theme element is blanked instead, and only on the windows, so the figure still draws it. check_axis_title() added the title to the outer ggplot a second time as a guide axis, whose row sits below the collected legend, which is why a scale-named title came out twice, once above the legend and once below it; only the secondary-axis title is left there, because labs() cannot set it. grid.draw.ggwrap() wrote the hoisted label back with totallabs$x <- NULL, and assigning NULL drops the element rather than clearing it, so a wrap drew a stray "x" under its legend. And the title is moved out of the panel by align_assembled_figure(), so a broken plot with a legend at the bottom keeps it when patchwork or cowplot take it through ggplotGrob() instead of being handed over titleless (2026-09-22, Tue, #85)
ggbreak 0.2.1
- the vignette and the help pages now say which of the five scales can be combined: a plot can be broken on the x axis and on the y axis at the same time, and that is the only combination, so a wrapping, breaking or cutting scale cannot be used together with a different one of them, and the error that is raised when they are names both scales. The vignette also says that a broken plot is drawn by clipping rather than by cutting the data, and that what a panel hides is not written to the file, so a PDF or an SVG written from a broken plot holds no object larger than the figure and can be pasted into Adobe Illustrator (2026-09-21, Mon, #16, #31)
ggbreak 0.2.0
- a plot that carries two of the scales
ggbreak adds no longer draws something wrong; scale_wrap(n = 2) + scale_y_break(...) came out as a rendering of the break nested inside the windows of the wrap, because grid.draw() strips only its own class and hands the subplots on with the other one still on them, and aplot::plot_list() does not treat a plot with one of these classes as a plain plot -- ggfun::is.ggbreak() is TRUE for ggbreak, ggwrap and ggcut, so it calls ggbreak2ggplot() and draws it. The only sign of it was a "Coordinate system already present" message. A plot can be broken on both axes and one axis can be cut, so the pairs that cannot be drawn now say so and name the two scales; a cut on both axes is one of them, and it was worse than unsupported, because a cut is stored in a single attribute, so the second cut replaced the first and the figure was byte-identical to the single cut, with nothing said about the cut that was dropped (2026-09-20, Sun, #31)
- a broken plot no longer hands the geometry its panels hide to the device; a break is drawn by clipping, so every window is given the whole dataset and the panel hides the part that belongs to the other windows, but the hidden geometry is still drawn into the file -- a bar from 0 to 990 is a rectangle as tall as the unbroken axis in both windows, and the window that shows its top carries one reaching about 1.8 panel heights above the panel it is drawn in, which a vector device writes out and Illustrator then refuses to paste ("the requested transformation would make some objects too large"). A rectangle, a segment that runs along the axis and a rectangle drawn as a polygon are now cut back to the edge of the panel they are drawn in; the panel clips that part away anyway, so nothing is drawn differently (0 pixels over the whole rendering battery, and over the two figures of the report), and a line is left alone because the piece it hides is read off the grob to bridge the break (2026-09-20, Sun, #16)
scale_x_break() and scale_y_break() gained a bridge argument, off by default; with bridge = TRUE the piece of a line that the break hides is drawn in the space between the windows, so a line that crosses the break reads as one line instead of two. A line grob keeps the geometry of the whole line and is only clipped when it is drawn, so where a line leaves one window and enters the next can be read off the grob, and the space space opens is a cell of the assembled figure that spans exactly those two edges. The lines of geom_line(), geom_path() and geom_step() are bridged, and only for a single break on a continuous axis; a break on a discrete axis and a plot that is faceted along the broken axis are left alone. The default is unchanged, so nothing moves unless it is asked for (2026-09-20, Sun, #33)
- a broken plot is no longer misaligned with the other plots of a
patchwork or cowplot layout; the layout aligns the plots by their panel cell, and the assembled figure is one panel that also held the axis of its windows, so a plot drawn beside it was aligned against a panel that already carried the axis labels and came out wider than the plot area it sits next to -- 44 pixels on a 6 by 3 inch figure, and 0 to 1 pixel now, for the break, the cut and the wrap scales, with coord_flip(), with a dual break, with a legend and with facets. The axis of the assembled figure is moved out of the panel into the cell the layout expects an axis in, and the room it took inside the figure is kept, so nothing is drawn differently; this is applied to the gtable ggplotGrob() hands out only, and print() and ggsave() are byte-for-byte unchanged (2026-09-20, Sun, #46)
- a broken plot no longer loses its break when it is combined with other plots;
patchwork and cowplot do not draw a plot the way print() does, they call ggplotGrob(), and that builds the plot from ggplot_build() without ever reading the break, so plt2 + plt1 came out as two plain plots -- the break was dropped silently, without a warning, and the same happened to plot_grid(), to scale_wrap() and to the cut scales. ggplot_build() and ggplot_gtable() are generics even though ggplotGrob() is not, so a broken plot now tags the object it is built into and is drawn as a whole from there; a regression test covers the break, the wrapping and the cutting, and the drawing is left to print() unchanged (2026-09-20, Sun, #46)
- the axis range of a plot is no longer read off the first panel alone; with
facet_grid(scales = "free_y") every panel has a scale of its own and the first one holds the range of the first panel only, so the windows were built from that range and every point outside it was dropped (the facet whose data sat high came out empty), while a break that was inside the first panel but outside the axis of the others was accepted and one inside the others was rejected as "not in the plot range". A broken axis is shared by the facets, so the windows are drawn on the axis of all the panels together; a regression test covers both the range and the two breaks (2026-09-20, Sun)
- added regression tests that a slice of a facet grid keeps the axis that belongs to its own facet row (column), that a slice claims a share of the figure in one direction only, that the assembled figure keeps the share of the figure each window is given, and that a
facet_wrap() is left alone (2026-09-20, Sun)
- fixed the nesting of a facet grid; the first attempt dropped the x axis of a facet column, so a
scale_x_break() on a faceted plot came out with no tick labels at all, sized the panels against every facet column instead of against their own and left them too small, and did not keep the share of the figure that each window is given. The pieces are now bound into a single gtable instead of being handed to patchwork as opaque panels, and a facet_wrap() is left alone because it has no facet rows or columns to nest into and puts a strip above every panel (2026-09-20, Sun, #55, #17)
- a broken facet grid no longer separates a facet row from its other windows; the subplot of a faceted plot carries the whole facet grid, so the windows used to be stacked outside the facets and the rows came out A B A B instead of A A B B, for
facet_grid(), and with coord_flip() the facet columns are kept together instead, which is the case reported in #55 and #17 (2026-09-20, Sun, #55, #17)
- added regression tests that the windows of a facet row (column) stay together, that a plot which is not faceted along the broken axis is assembled as before, and that the legend is still drawn exactly once when the pieces are reassembled (2026-09-20, Sun)
- a theme that is set with
theme_set() no longer draws a second panel border, a second pair of axis lines or a panel background around the whole figure; those elements belong to the subplots, and the outer ggplot that carries the assembled figure was taking them from the global theme by accident, so theme_set(theme_bw()) drew a rectangle around the figure and theme_set(theme_classic()) two extra lines outside the plot (2026-09-20, Sun, #57)
- the assembled figure no longer paints an opaque background of its own;
patchwork took that background from the default theme, so a broken plot could not be superimposed on another one with annotation_custom() (it hid whatever was drawn below it) and the plot.background set on the plot never reached the figure (2026-09-20, Sun, #52)
- added regression tests that a globally set theme renders like the same theme applied to the plot, and that the assembled figure paints no background of its own (2026-09-20, Sun)
- added a regression test that the axis title of a broken plot stays above the collected legend with
theme(legend.position = "bottom"), for scale_x_break(), scale_y_break(), a dual break, coord_flip(), scale_wrap() and the cut scales; the report in #85 is the same defect that #53 fixed, the reporter was on an earlier version (2026-09-19, Sat, #85)
- drawn the axis title of a broken plot above the legend when
theme(legend.position = "bottom") is used; patchwork collects the legend at the bottom of the assembled figure, which is the panel of the outer ggplot that carries the axis title, so the legend used to be drawn on top of the title instead of underneath it (2026-09-18, Fri, #53)
patchwork and gtable are now declared in Imports; both were already needed at run time to assemble the subplots (2026-09-18, Fri)
- document how to make the ticks line up across the subplots: the
breaks argument of scale_x_break()/scale_y_break() is the place where the axis is cut, and the ticks are set with breaks in the continuous scale, which every subplot then filters to its own range (2026-09-18, Fri, #66)
- fixed adding a coord, theme, scale, facet or layer to a plot that uses
scale_wrap() or scale_x_cut()/scale_y_cut(); ggplot_add() re-dispatched to itself for ever and R died with a C stack overflow (2026-09-17, Thu)
- kept the limits that
coord_cartesian() or coord_flip() set on the axis that is not broken, so scale_y_break() no longer discards coord_cartesian(xlim = ...), and scale_x_break(), scale_wrap() and scale_x_cut()/scale_y_cut() no longer discard the limits of the other axis (2026-09-17, Thu, #59)
- honoured
theme(plot.margin = ...) when the plot is wrapped for the final draw; previously the theme_void() from ggplotify::as.ggplot() swallowed the user margin so plot.margin had no effect on a broken plot (2026-09-17, Thu, #71)
- fixed an extra blank page when a broken plot is saved with
pdf() or ggsave(); ggbreak now starts the page before it builds the subplots instead of leaving the page that building opens behind (2026-09-17, Thu, #73)
- document the breaks and cuts on a discrete axis, on a
Date or datetime axis and the use of ggrepel in the vignette (2026-09-17, Thu)
- fixed the axis losing its tick labels when
scale_wrap(), scale_x_cut() or scale_y_cut() is used together with coord_flip() (2026-09-17, Thu)
- a
Date or datetime axis is no longer drawn as numbers when the plot relies on the scale that ggplot2 creates from the data instead of calling scale_x_date(), scale_x_datetime() or their y counterparts itself (2026-09-17, Thu, #84)
- fixed
scale_x_cut() and scale_y_cut() failing with "non-numeric argument to binary operator" when the axis uses a transformed scale such as scale_y_log10() (2026-09-17, Thu)
- fixed the labels of
ggrepel::geom_text_repel() and geom_label_repel() being repeated in every subplot; a label is now only drawn in the subplot that holds its point (2026-09-17, Thu, #35)
- support
scale_x_break(), scale_y_break(), scale_x_cut() and scale_y_cut() on a discrete axis; the break points are level names and a break between two adjacent levels only inserts a gap (2026-09-16, Wed, #68)
scale_x_break(), scale_y_break(), scale_x_cut() and scale_y_cut() accept break points of a datetime axis given as Date, character or numeric, in addition to POSIXct (2026-09-16, Wed, #84)
- report an error instead of silently flipping the axis of a subplot when a break interval is not in the plot range (2026-09-16, Wed, #43)
- fixed extra lines drawn outside the plot and a duplicated axis when the plot uses a scale without
sec.axis (2026-09-16, Wed, #64)
- fixed duplicated datetime x-axis labels when using
scale_y_break() (2026-08-07, Fri, #83)
ggbreak 0.1.7 (2026-03-18)
- add test unit (2026-03-18, Wed)
- support axis break symbols (2026-03-18, Wed)
- support multiple axis break (#81, thanks @abertran3)
ggbreak 0.1.6 (2025-08-24)
- compatible with ggplot2 v=4.0.0 (2025-08-24, Sun, #80)
ggbreak 0.1.3 (2025-01-08)
- use
yulab_msg() for startup message (2025-01-08, Wed)
ggbreak 0.1.2 (2023-06-26)
- update CITATION file to use
c() and bibentry() instead of old-style personList() and citEntry() (2023-06-26, Mon)
- move
theme_fp() to the 'ggfun' package (2023-06-24, Sat)
ggbreak 0.1.1 (2022-10-15)
- update vignette with example to place legend at any position (2022-10-15, Sat)
ggbreak 0.1.0 (2022-06-01)
- fixed a bug in drawing dual axis (2022-06-01, Wed, #48, #49)
ggbreak 0.0.9 (2022-02-05)
scale_wrap() supports using categorical variable as x-axis (2022-01-16, Sun, #41)
- support double axes (2022-01-16, Sun, #40)
ggbreak 0.0.8 (2022-01-12)
- introduce
space argument (2022-01-11, Tue)
ggbreak 0.0.7 (2021-10-25)
- introduce
expand argument (2021-10-22, Fri, #30)
- add citation (2021-10-13, Wed)
ggbreak 0.0.6 (2021-10-09)
- remove xy intercept label and compatible with
xlim and ylim (2021-09-24, Fri, #29)
- import
is.ggbreak and ggbreak2ggplot from the ggfun package (2021-09-16, Thu)
- fixed x and y labels and introduced
scale_xy_expand option (2021-09-15, Wed; #26)
- apply text and title setting from pre-break graph to breaked graph (2021-09-09, Thu)
ggbreak 0.0.5 (2021-09-06)
- change according to
aplot::plot_list (2021-09-03, Fri)
ggbreak 0.0.4 (2021-08-14)
- set
expand=FALSE (2021-08-14, Sat)
- support setting e.g.
legend.position = "bottom" via theme() (2021-05-31, Mon)
- manual legend position (e.g.
legend.position = c(.1, .2)) is not supported currently
- if passing
recording = FALSE to grid.draw method, only graph object return without plotting the figure (2021-05-24, Mon)
ggbreak 0.0.3 (2021-05-21)
- compatible with
patchwork for axis break plots + gg plot (2021-05-21, Fri)
- supports setting axis tick labels (2021-05-20, Tue)
scale_x_cut and scale_y_cut functions (2021-05-18, Tue)
scale_wrap function and support of using date object as axis (2021-05-15, Sat)
- add vignette (2021-05-14, Fri)
- support
coord_flip, facet_grid and facet_wrap (2021-05-14, Fri)
- support
legend and all labels (x, y, title, subtitle, caption and tag)
ggbreak 0.0.2 (2021-05-13)
- compatible with
patchwork, now p1 + p2 (or other operations) will align two ggbreak plot (2021-05-11, Tue)
- support multiple
scale_x_break or scale_y_break and compatible with reverse axis
ggbreak 0.0.1
- initial version of ggbreak that provide
scale_x_break and scale_y_break (2021-05-10, Mon)