2 Y Axes in Algebra of Graphics

I have been trying to figure out how to make two separate y-axes for a plot in Algebra of Graphics. This seems possible in Makie, julia - Double y-axis on left and right side of plot in Makie.jl - Stack Overflow (though I think this example is old).

How would I do this in Algebra of Graphics?

The grammar of graphics is generally opposed to dual axes because it breaks the 1-to-1 mapping between locations and values. The only situation where it’s considered safe is when the two axes are monotonic transformations of each other, such as a Fahrenheit axis and a Celsius axis over the same values. I’m guessing AoG doesn’t support that currently.

1 Like

One way to handle this logically is to plot dimensionless ratios, so there are no units and everything is on a comparable scale.

For example suppose the two things you want to plot are the angle of a linkage rod that varies over about 10 degrees, and the force applied to it, both as time series… Instead of plotting say degrees and kilonewtons you take the data and convert to degrees/max angle, and force as a fraction of peak force for a cycle… Now you have values that are all in the range of about ±1 and can plot on a single dimensionless axis

Yes, using reduced values is a great way to unlink onself from the details of the reality :wink:

Sometimes it is useful, and a theoretical physisist would happily use eV units for everything (1 kg = 5.61e35 eV , 1 s = 1.52e15 1/eV ). In practice however, there are practical reasons for using practical (and even imperially-unpractical) units. I have a good feeling for what a kN is (disclosure: it is about 1.5 of my weight), and what a ° is (I can draw an angle by hand to a few degrees exact), and data in ° and kN is informative for me on multiple levels. Having values plotted as reduced to some random “100%” takes some crucial information out of the visual representation. Sure, being old school I can multiply 30% by 1.47kN in my head, but do I need that additional mental load? And how should we plot after you shiift the gear of your machine?

Should we take a more realistic example? A common case - you have some process of interest, and there is some changing environmental parameter. E.g. you observe the course of a chemical reaction, measuring some concentration over time, whereas the temperature changes, too. To make sense of what is happening, you need both data, preferably on one single plot, and definitely in units your technician can understand.

1 Like

(Yes, I know the topic is 4-years-old)

I’ve asked a couple of AIs this question, was each time told “good children don’t do it, but if you want…”. That’s one of the solutions I found practical, reviewed and fixed:


In AlgebraOfGraphics.jl, there is no direct high-level keyword to produce a dual-axis plot because the “Grammar of Graphics” philosophy generally discourages them.

However, because the package is built on Makie.jl, you can achieve this by creating two overlapping axes in the underlying Makie Figure and drawing separate AlgebraOfGraphics layers into them.

Here is how to do it:
The Solution: Overlaying Makie Axes

You must create a Makie Figure manually, place two Axis objects in the same grid position (one with the Y-axis on the right), and then use draw! to plot your datasets into each specific axis.

using AlgebraOfGraphics, WGLMakie

# 1. Prepare Data
d1 = (x = 1:10, y = rand(10) .* 10)       # Dataset 1 (Scale A)
d2 = (x = 1:11, y = rand(11) .* 1000)     # Dataset 2 (Scale B, much larger, also differing X-range)

# 2. Define your AlgebraOfGraphics specs (layers)
# Important: Do not combine them with `+`. Keep them as separate layers.
layer1 = data(d1) * mapping(:x, :y) * visual(Lines, color=:blue)
layer2 = data(d2) * mapping(:x, :y) * visual(Scatter, color=:red)

# 3. Create a Makie Figure and Axes
fig = Figure()

xlimits = (0, 12) # ensure both plots have the same X-scale
# Create the first axis (Left Y-axis)
ax1 = Axis(fig[1, 1], 
    ylabel = "Scale A (Blue)", 
    yticklabelcolor = :blue, 
    limits = (xlimits, (0, 10)), # optionally manually setting Y-axis limits
    )

# Create the second axis (Right Y-axis) in the SAME grid position
# set `yaxisposition = :right` and ensure the background is transparent
ax2 = Axis(fig[1, 1], 
    ylabel = "Scale B (Red)", 
    yaxisposition = :right, 
    yticklabelcolor = :red, 
    backgroundcolor = :transparent,
    limits = (xlimits, (0, 1000)),
    )

# Optional: Hide the spines of the second axis so they don't overlap awkwardly
hidespines!(ax2, :l, :b, :t)
hidexdecorations!(ax2) # Hide x-ticks of the secondary axis to avoid clutter

# 4. Draw the layers into the specific axes
draw!(ax1, layer1)
draw!(ax2, layer2)

# Display the result
fig

Key Steps Explained:

  • Separate Layers: Unlike a standard AoG plot where you combine layers with +, here you keep layer1 and layer2 separate so you can direct them to different axes.
  • yaxisposition = :right: This Makie attribute moves the ticks and label of the second axis to the right side.
  • backgroundcolor = :transparent: The second axis is drawn on top of the first. If you don’t make it transparent, it will block the view of the first plot.
  • draw!(ax, layer): The mutating draw! function allows you to render an AlgebraOfGraphics specification directly into an existing Makie axis.
2 Likes