Function Repository Resource:

CombinePlots

Source Notebook

Combine plots, enabling the creation of plots with two sets of axes and the merging of prologs and epilogs

Contributed by: Lukas Lang

ResourceFunction["CombinePlots"][g1,g2,]

works like Show, but can reorder labels/callouts and reposition frame axes.

Details and Options

ResourceFunction["CombinePlots"] combines graphics expressions while trying to move labels and callouts to the front.
ResourceFunction["CombinePlots"] by default merges the primitives inside the Prolog and Epilog options.
ResourceFunction["CombinePlots"] can reposition frame axes, allowing the creation of plots with two x/y axes.
ResourceFunction["CombinePlots"] accepts the following options:
"CombineProlog"Truewhether to merge prologs
"CombineEpilog"Truewhether to merge epilogs
"AnnotationPattern"(GraphicsGroup|Text)[___]the pattern used to match annotations
"AxesSides"Automaticon which side to put the frame axes
ResourceFunction["CombinePlots"] effectively removes all expressions matching the pattern specified by "AnnotationPattern" and inserts them on top of the remaining primitives.
The default setting of "AnnotationPattern", (GraphicsGroup|Text)[___] matches the primitives generated from Label and Callout directives.
The option "AxesSides" accepts the following settings:
Automaticdo not move frame axes
"TwoY"move the vertical frame axis of the second plot to the right
"TwoX"move the horizontal frame axis of the second plot to the top
"TwoXY"move the bottom/left frame axes of the second plot to the top/right
"MultiY"use a separate vertical frame axis for each plot alternatingly adding to the left/right side
"MultiX"use a separate horizontal frame axis for each plot alternatingly adding to the bottom/top side
"MultiXY"use a separate pair of vertical and horizontal frame axes for each plot
specuse explicit settings for different plots
"AxesSides" supports the same sequence specification as documented for Spacings.
For each plot, the setting can be one of the following:
Bottomput horizontal frame axis to the bottom
Topput horizontal frame axis to the top
Leftput vertical frame axis to the left
Rightput vertical frame axis to the right
sideAutomaticput the frame axis onto a separate axis on the specified side
sideiput the frame axis onto the axis with the specified index, counting from the inside
{sidex,sidey}position both horizontal and vertical frame axes
Directive[sidex,sidey]same as {sidex,sidey}
The option "AxesSides" settings "TwoY"/"TwoX"/"TwoXY" are effectively equivalent to settings of the form {2spec}.
The settings "MultiY"/"MultiX" are effectively equivalent to settings of the form {{side1Automatic,side2Automatic}}, and "MutilXY" is a combination of the former two.
The sides for the frame axes of plots can also be specified by wrapping plots with Axes[plot,sideSpec], similar to how Item works for Grid.
The arguments of ResourceFunction["CombinePlots"] can be (nested) lists of plots, where each level can be wrapped in Axes[plots,sideSpec]. Deeper specifications override outer ones as necessary.
The setting of "AxesSides" applies to each argument of ResourceFunction["CombinePlots"] as one. Use Axes[] type specifications for more granular control.
ResourceFunction["CombinePlots"] will use the frame axis of the first appropriate plot for each side. The values of the FrameLabel, FrameTicks, FrameStyle and FrameTicksStyle options are used to create the frame axis in the resulting plot.
ResourceFunction["CombinePlots"] effectively uses GeometricTransformation to rescale plot contents shown on secondary axes. Additional axes beyond the first axis per side are added using Inset.
ResourceFunction["CombinePlots"] sets CoordinatesToolOptions to enable extraction of coordinates from any of the axes. The format is {{{sidex,ix},{sidey,iy}}{x,y},}, with one entry for each unique horizontal/vertical axis combination. The ix,iy indicate the index of the axis on the respective side.
ResourceFunction["CombinePlots"] will always return a (possibly Legended) Graphics expression.
If there are no labels/callouts and no prolog/epilog to combine, ResourceFunction["CombinePlots"][args] is equivalent to Show[args].

Examples

Basic Examples (3) 

Combine two plots containing annotations:

In[1]:=
ResourceFunction["CombinePlots"][
 Plot[
  Callout[Sin[x], "Sin[x]", 0.8, Appearance -> "Balloon", Background -> White],
  {x, 0, 2 \[Pi]}
  ],
 Plot[
  Callout[Cos[x], "Cos[x]", 5, Appearance -> "Balloon", Background -> White
   ],
  {x, 0, 2 \[Pi]}, PlotStyle -> Directive[Thick, Red]
  ]
 ]
Out[1]=

If Show is used instead, the annotations of the first plot are covered by the contents of the second one:

In[2]:=
Show[
 Plot[
  Callout[Sin[x], "Sin[x]", 0.8, Appearance -> "Balloon", Background -> White],
  {x, 0, 2 \[Pi]}
  ],
 Plot[
  Callout[Cos[x], "Cos[x]", 5, Appearance -> "Balloon", Background -> White],
  {x, 0, 2 \[Pi]}, PlotStyle -> Directive[Thick, Red]
  ]
 ]
Out[2]=

Use CombinePlots to combine Prolog and Epilog contents:

In[3]:=
ResourceFunction["CombinePlots"][
 Graphics[
  {Green, Disk[{0, 0}]},
  Prolog -> {Red, Disk[{0, 1}]},
  Epilog -> {Blue, Disk[{1, 0}]},
  PlotRange -> 2
  ],
 Graphics[
  {},
  Prolog -> {Red, Disk[{0, -1}]},
  Epilog -> {Blue, Disk[{-1, 0}]}
  ]
 ]
Out[3]=

Show only keeps the Prolog/Epilog of the first Graphics:

In[4]:=
Show[
 Graphics[
  {Green, Disk[{0, 0}]},
  Prolog -> {Red, Disk[{0, 1}]},
  Epilog -> {Blue, Disk[{1, 0}]},
  PlotRange -> 2
  ],
 Graphics[
  {},
  Prolog -> {Red, Disk[{0, -1}]},
  Epilog -> {Blue, Disk[{-1, 0}]}
  ]
 ]
Out[4]=

Use CombinePlots to create a plot with two vertical axes:

In[5]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10}, Frame -> True],
 Plot[
  100 x^4, {x, 0, 10},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 "AxesSides" -> "TwoY"
 ]
Out[5]=

Scope (1) 

Merge arbitrary plots into plots with two y axes:

In[6]:=
ResourceFunction["CombinePlots"][
 BarChart[RandomReal[{0, 1}, 5], Frame -> True],
 DiscretePlot[
  n!, {n, 1, 5},
  PlotStyle -> Red, Frame -> True, FrameStyle -> Red, PlotMarkers -> Style["\[Bullet]", FontSize -> 20]
  ],
 "AxesSides" -> "TwoY", Frame -> True
 ]
Out[6]=

Options (17) 

CombineProlog (2) 

With the default setting "CombineProlog"True, the graphics primitives of each Prolog are combined:

In[7]:=
ResourceFunction["CombinePlots"][
 Graphics[
  {Green, Disk[{0, 0}]},
  Prolog -> {Red, Disk[{0, 1}]},
  Epilog -> {Blue, Disk[{1, 0}]},
  PlotRange -> 2
  ],
 Graphics[
  {},
  Prolog -> {Red, Disk[{0, -1}]},
  Epilog -> {Blue, Disk[{-1, 0}]}
  ]
 ]
Out[7]=

Only take the Prolog of the first Graphics, mimicking the behavior of Show:

In[8]:=
ResourceFunction["CombinePlots"][
 Graphics[
  {Green, Disk[{0, 0}]},
  Prolog -> {Red, Disk[{0, 1}]},
  Epilog -> {Blue, Disk[{1, 0}]},
  PlotRange -> 2
  ],
 Graphics[
  {},
  Prolog -> {Red, Disk[{0, -1}]},
  Epilog -> {Blue, Disk[{-1, 0}]}
  ],
 "CombineProlog" -> False
 ]
Out[8]=

CombineEpilog (2) 

With the default setting "CombineEpilog"True, the graphics primitives of each Epilog are combined:

In[9]:=
ResourceFunction["CombinePlots"][
 Graphics[
  {Green, Disk[{0, 0}]},
  Prolog -> {Red, Disk[{0, 1}]},
  Epilog -> {Blue, Disk[{1, 0}]},
  PlotRange -> 2
  ],
 Graphics[
  {},
  Prolog -> {Red, Disk[{0, -1}]},
  Epilog -> {Blue, Disk[{-1, 0}]}
  ]
 ]
Out[9]=

Only take the Epilog of the first Graphics, mimicking the behavior of Show:

In[10]:=
ResourceFunction["CombinePlots"][
 Graphics[
  {Green, Disk[{0, 0}]},
  Prolog -> {Red, Disk[{0, 1}]},
  Epilog -> {Blue, Disk[{1, 0}]},
  PlotRange -> 2
  ],
 Graphics[
  {},
  Prolog -> {Red, Disk[{0, -1}]},
  Epilog -> {Blue, Disk[{-1, 0}]}
  ],
 "CombineEpilog" -> False
 ]
Out[10]=

AnnotationPattern (3) 

The default setting of "AnnotationPattern" matches primitives generated for Callout and Label wrappers:

In[11]:=
ResourceFunction["CombinePlots"][
 Plot[
  Labeled[
   Callout[Sin[x], "Sin[x]", 0.8, Appearance -> "Balloon", Background -> White],
   Style["A label", Background -> White], 3.8
   ],
  {x, 0, 2 \[Pi]}
  ],
 Plot[
  Callout[Cos[x], "Cos[x]", 5, Appearance -> "Balloon", Background -> White],
  {x, 0, 2 \[Pi]}
  ]
 ]
Out[11]=

Bring only Text primitives to the front:

In[12]:=
ResourceFunction["CombinePlots"][
 Plot[
  Labeled[
   Callout[Sin[x], "Sin[x]", 0.8, Appearance -> "Balloon", Background -> White],
   Style["A label", Background -> White], 3.8
   ],
  {x, 0, 2 \[Pi]}
  ],
 Plot[
  Callout[Cos[x], "Cos[x]", 5, Appearance -> "Balloon", Background -> White],
  {x, 0, 2 \[Pi]}
  ],
 "AnnotationPattern" -> _Text
 ]
Out[12]=

Bring only GraphicsGroup primitives to the front:

In[13]:=
ResourceFunction["CombinePlots"][
 Plot[
  Labeled[
   Callout[Sin[x], "Sin[x]", 0.8, Appearance -> "Balloon", Background -> White],
   Style["A label", Background -> White], 3.8
   ],
  {x, 0, 2 \[Pi]}
  ],
 Plot[
  Callout[Cos[x], "Cos[x]", 5, Appearance -> "Balloon", Background -> White],
  {x, 0, 2 \[Pi]}
  ],
 "AnnotationPattern" -> _GraphicsGroup
 ]
Out[13]=

AxesSides (10) 

With the default setting "AxesSides"Automatic, all plots share the same axes:

In[14]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10}, Frame -> True],
 Plot[
  100 x^4, {x, 0, 10},
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ]
 ]
Out[14]=

Use a secondary vertical axis for the second plot:

In[15]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10}, Frame -> True],
 Plot[
  100 x^4, {x, 0, 10},
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 "AxesSides" -> "TwoY"
 ]
Out[15]=

The different axes can have different ScalingFunctions:

In[16]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10}, Frame -> True],
 Plot[
  100 x^4, {x, 0, 10},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 "AxesSides" -> "TwoY"
 ]
Out[16]=

Create a plot with a secondary horizontal axis:

In[17]:=
ResourceFunction["CombinePlots"][
 Plot[Cos[x], {x, 0, 10}, Frame -> True],
 Plot[
  Sin[x], {x, 0, 30},
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 "AxesSides" -> "TwoX"
 ]
Out[17]=

Use both secondary x and y axes:

In[18]:=
ResourceFunction["CombinePlots"][
 Plot[Cos[x], {x, 0, 10}, Frame -> True],
 Plot[
  1 + 10 Sin[x]^2, {x, 0, 30},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 "AxesSides" -> "TwoXY"
 ]
Out[18]=

Use a separate vertical axis for each plot, and label each of them:

In[19]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10},
  Frame -> True, FrameStyle -> Black, PlotStyle -> Black,
  FrameLabel -> {None, "Black Axis"}],
 Plot[
  100 x^4, {x, 0, 10},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red,
  FrameLabel -> {None, "Red Axis"}
  ],
 Plot[
  x^4, {x, 0, 10},
  Frame -> True, FrameStyle -> Blue, PlotStyle -> Blue,
  FrameLabel -> {None, "Blue Axis"}
  ],
 Plot[
  100 x^4, {x, 0, 10},
  ScalingFunctions -> "Reciprocal",
  Frame -> True, FrameStyle -> Darker@Green, PlotStyle -> Darker@Green,
  FrameLabel -> {None, "Green Axis"}
  ],
 "AxesSides" -> "MultiY"
 ]
Out[19]=

Put the contents of multiple plots on the secondary axis:

In[20]:=
ResourceFunction["CombinePlots"][
 Plot[Cos[x], {x, 0, 10}, Frame -> True],
 {
  Plot[
   1 + 10 Sin[x]^2, {x, 0, 10},
   ScalingFunctions -> "Log",
   Frame -> True, FrameStyle -> Red, PlotStyle -> Red
   ],
  Plot[
   2 + 10 Cos[x]^2, {x, 0, 10},
   ScalingFunctions -> "Log",
   PlotStyle -> Orange
   ]
  },
 "AxesSides" -> "TwoY"
 ]
Out[20]=

Move the vertical axis of all plots to the right:

In[21]:=
ResourceFunction["CombinePlots"][
 Plot[Cos[x], {x, 0, 10}, Frame -> True],
 Plot[
  2 Sin[x], {x, 0, 10},
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 "AxesSides" -> Right
 ]
Out[21]=

Use Axes[plot,sideSpec] to specify the sides on which to put axes:

In[22]:=
ResourceFunction["CombinePlots"][
 Axes[Plot[Cos[x], {x, 0, 10}, Frame -> True], Right],
 Plot[
  1 + 10 Sin[x]^2, {x, 0, 10},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ]
 ]
Out[22]=

Put one plot on the secondary vertical axis, and another one on both the secondary horizontal and vertical axes:

In[23]:=
ResourceFunction["CombinePlots"][
 Plot[Cos[x], {x, 0, 10}, Frame -> True],
 Plot[
  1 + 10 Sin[x]^2, {x, 0, 10},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Red, PlotStyle -> Red
  ],
 Plot[
  {2 + 10 Sin[x]^2, 2 + 10 Sin[x]^2}, {x, 0, 30},
  ScalingFunctions -> "Log",
  Frame -> True, FrameStyle -> Blue, PlotStyle -> {Blue, Directive[Red, Dashed]}
  ],
 "AxesSides" -> {Automatic, Right, Directive[Right, Top]}
 ]
Out[23]=

Possible Issues (2) 

CombinePlots only moves the Frame type axis. Normal Axes are not supported:

In[24]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10}],
 Plot[100 x^4, {x, 0, 10}, PlotStyle -> Red, AxesStyle -> Red],
 "AxesSides" -> "TwoY"
 ]
Out[24]=

Specify FrameTrue to fix the issue:

In[25]:=
ResourceFunction["CombinePlots"][
 Plot[x^2, {x, 0, 10}, Frame -> True],
 Plot[100 x^4, {x, 0, 10}, Frame -> True, PlotStyle -> Red, FrameStyle -> Red],
 "AxesSides" -> "TwoY"
 ]
Out[25]=

Publisher

Lukas Lang

Version History

  • 2.1.1 – 21 June 2023
  • 2.1.0 – 19 May 2023
  • 2.0.2 – 27 September 2022
  • 2.0.1 – 19 February 2021
  • 2.0.0 – 20 December 2019
  • 1.0.0 – 24 October 2019

Related Resources

Author Notes

Changes from version 2.1.0 to 2.1.1:

Fix options not being carried over to resulting plot if the first plot was a Legended expression
Fix CoordinatesToolOptions not being properly simplified
Fix PlotRangeClipping not being applied properly
Fix padding computation being incorrect on sides with no primary frame axis

Changes from version 2.0.2 to 2.1.0:

Added support for more than two axes & added convenience settings "MultiY","MultiX","MultiXY" to "AxesSides"
Fix plot markers on secondary axes being scaled incorrectly

Changes from version 2.0.0 to 2.0.2:

Fixed CombinePlots not working when invoked from wolframscript or in the cloud
Fixed an issue where the PlotRangePadding was applied twice

Changes from version 2.0.0 to 2.0.1:

Fixed issues when a non-default kernel is used.
Fixed issues with certain WindowSize settings.

Uses adapted version of GraphicsInformation (link) from Mathematica Stack Exchange user Carl Woll.

License Information