Binary Lever Rule

Quick Start

When binary mixtures separate at a low temperature, the phases & their proportions are explained by the Lever Rule. The rule is simple - but many of us are confused by it. App writing is a good way to learn: Dr Shimizu pointed out a number of my errors in early drafts of this app.

This is a beta version - it might still change.


The app was first written as tutorial material for a course given by Dr Seishi Shimizu at U York.


//One universal basic required here to get things going once loaded
window.onload = function () {
    //restoreDefaultValues(); //Un-comment this if you want to start with defaults
//Any global variables go here

//Main is hard wired as THE place to start calculating when input changes
//It does no calculations itself, it merely sets them up, sends off variables, gets results and, if necessary, plots them.
function Main() {

    //Send all the inputs as a structured object
    //If you need to convert to, say, SI units, do it here!
    const inputs = {
        A: sliders.SlideA.value / 100,
        Trel: sliders.SlideTrel.value,
        Width: (6 - sliders.SlideWidth.value) * 3,
        xStart: sliders.SlidexStart.value,

    //Send inputs off to CalcIt where the names are instantly available
    //Get all the resonses as an object, result
    const result = CalcIt(inputs)

    //Set all the text box outputs
    document.getElementById('Results').value = result.Results
    //Do all relevant plots by calling plotIt - if there's no plot, nothing happens
    //plotIt is part of the app infrastructure in
    if (result.plots) {
        for (let i = 0; i < result.plots.length; i++) {
            plotIt(result.plots[i], result.canvas[i]);

    //You might have some other stuff to do here, but for most apps that's it for CalcIt!

//Here's the app calculation
//The inputs are just the names provided - their order in the curly brackets is unimportant!
//By convention the input values are provided with the correct units within Main
function CalcIt({ A, Trel, Width, xStart }) {

    let plotData = [], pPts = [], tPts = [], xPts = [], dPts1 = [], dPts2 = [], i, j
    let x1 = 0, x2 = 1
    const iStep = 0.01
    for (i = 0; i <= 1.01; i += iStep) {
        pPts.push({ x: i, y: y })
        //Inelegant code to get more accurate x1, x2 values
        if (i>0 && y >= Trel && x1 == 0) {
            for (j = i - iStep; j <= i; j += 0.00001) {
                if (y >= Trel) { x1 = j;break }
        if (i>xStart && y <= Trel && x2 ==1){
            for (j = i - iStep; j <= i; j += 0.00001) {
                if (y <= Trel) { x2 = j;break }
    if (x1<=0.015) x1=0
    if (x2>=0.990) x2=1
    const xg1=x1 //x1>0?x1:-0.5
    const xg2=x2//<1?x2:1.5

    tPts.push({ x: 0, y: Trel }, { x: 1, y: Trel })
    xPts.push({ x: xStart, y: 0 }, { x: xStart, y: 100 })
    dPts1.push({ x: xg1, y: 0 }, { x: xg1, y: Trel })
    dPts2.push({ x: xg2, y: 0 }, { x: xg2, y: Trel })
    x1=Math.round(x1 * 100+Number.EPSILON) / 100
    x2=Math.round(x2 * 100+Number.EPSILON) / 100
    if (xStart < x1 || xStart > x2 || Trel>75) {
        Results = "Single phase"
    } else {
        const L1 = 100 * (x2 - xStart) / (x2 - x1)
        const L2 = 100 * (xStart - x1) / (x2 - x1)
        const N1 = (x2 - xStart) / (xStart - x1)
        const N2 = (xStart - x1) / (x2 - xStart)
        const N12 = N1 + N2
        const N1N12 = N1 / N12
        const N2N12 = 100 * N2 / N12
        Results = "Separates into:\nSolvent Rich Phase x=" + x1.toFixed(2) + " & Solute Rich Phase x= " + x2.toFixed(2) + "\nat ratio\nSolvent Rich : Solute Rich = " + L1.toFixed(0) + " : " + L2.toFixed(0) + "\n"
        Results += "\nSolvent Rich/Solute Rich = (" + x2.toFixed(2) + "-" + xStart.toFixed(2) + ")/(" + xStart.toFixed(2) + "-" + x1.toFixed(2) + ") =" + N1.toFixed(2)
        Results += "\nSolute Rich/Solvent Rich = (" + xStart.toFixed(2) + "-" + x1.toFixed(2) + ")/(" + x2.toFixed(2) + "-" + xStart.toFixed(2) + ") =" + N2.toFixed(2)
        Results+="\nSolvent Rich / (Solute Rich + Solvent Rich) = (" + x2.toFixed(2) + "-" + xStart.toFixed(2) + ")/(" + x2.toFixed(2) + "-" + x1.toFixed(2) + ") =" + (L1/100).toFixed(2)

    plotData.push(pPts, tPts, xPts, dPts1, dPts2)
    const prmap = {
        plotData: plotData, //An array of 1 or more datasets
        lineLabels: ["Phase Boundary", "T", "Init.", "Solv Rich", "Solute Rich"], //An array of labels for each dataset
        //hideLegend: true,
        dottedLine: [false, true, true, true, true],
        // colors: theColors,
        // showLines: showLines,
        // showPoints: showPoints,
        xLabel: "x_solute& ", //Label for the x axis, with an & to separate the units
        yLabel: "T (relative)& ", //Label for the y axis, with an & to separate the units
        y2Label: null, //Label for the y2 axis, null if not needed
        yAxisL1R2: [], //Array to say which axis each dataset goes on. Blank=Left=1
        logX: false, //Is the x-axis in log form?
        xTicks: undefined, //We can define a tick function if we're being fancy
        logY: false, //Is the y-axis in log form?
        yTicks: undefined, //We can define a tick function if we're being fancy
        legendPosition: 'top', //Where we want the legend - top, bottom, left, right
        xMinMax: [0, 1], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        yMinMax: [0, 100], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        y2MinMax: [,], //Set min and max, e.g. [-10,100], leave one or both blank for auto
        xSigFigs: 'F2', //These are the sig figs for the Tooltip readout. A wide choice!
        ySigFigs: 'F0', //F for Fixed, P for Precision, E for exponential
    return {
        Results: Results,
        plots: [prmap],
        canvas: ['canvas'],
function getY(x,A,Width){
    let y=0
    if (x <= A) {
        y = 75 * (1 - Math.pow(Width * Math.pow(A, 1.5) * (A - x), 2))
   } else {
       y = 75 * (1 - Math.pow(Width * Math.pow(1 - A, 1.5) * (A - x), 2))
return y

An interactive guide to the “lever rule”

When a solution of initial solute concentration xinit is cooled and the phases separate, one phase is solvent rich and the other is solute rich. The solute fraction in each is shown by the green and purple line.

Solubility Science Lever Rule Just as important is the amount of each phase. This is calculated via the lever rule which states that amounts of each phase in the system is like a balance. If we think in terms of arm length L and mass of component M then `L_1M_1=L_2M_2` so we get the inverse relationship: `L_1/L_2=M_2/M_1` As the diagram shows, when xinit is nearer one phase (in this case the solute-rich phase), the proportion of that phase is larger. Because of the inverse relationship on length, the amount of solvent-rich is proportional to xsolute−xinit and the amount of solute-rich is proportions to xinit−xsolvent. Each is divided by the total length, i.e. xsolute−xsolvent.

To explore this interactively:

  • Move the T bar up, above the phase boundary (orange).
  • The system is in a single phase at this temperature (light blue line).
  • Lower the temperature of the system until the temperature (light blue) hits the orange-red intercept.
  • Below this temperature, green and purple lines appear.
    • The solute mole fraction (xsolute) in the Solvent Rich Phase is in green.
    • The solute mole fraction (xsolute) in the Solute Rich Phase is in purple.
  • Moving xinit changes the mixing composition of solvent and solute in your flask.
  • If you see red, green, and purple lines, you see the Solute Rich Phase and Solvent Rich Phase in your flask.
  • The ratio between the two phases can be calculated by the lever rule, as shown in the Results box.
  • Three different ratios have been calculated.
    • The answer you should report depends on how the ratio is defined.
    • The lesson is always to ask: “the ratio of what to what?” (The ratio of X to Y is X/Y).

Expert view

Solubility Science Lever RuleWhy is there phase separation and how does the system "know" where to phase separate with the various ratios? As shown in the Metastable Zone app, the phases separate at the point where the curve of free energy, ΔG, forms a minimum (with extra subtleties around binodal and spinodal points). The picture here captures the essence, with the "tie line" between the two minima indicating that the compositions are those at the two ends of the tie line, while the proportions depend on where you are along the tie line.

The lever rule comes from the straight-line behaviour of the mixing free energy between xSolu Rich and xSolv Rich as required by thermodynamic stability, or the convex nature of the free energy. The amount of each phase at xinit is calculated by the section formula, which is mathematically the same as the lever rule.