<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Tobia Cavalli</title>
    <link>https://tobiacavalli.com/</link>
    <description>Recent content on Tobia Cavalli</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <managingEditor>tobiablogs@proton.me (Tobia Cavalli)</managingEditor>
    <webMaster>tobiablogs@proton.me (Tobia Cavalli)</webMaster>
    <copyright>Copyright © Tobia Cavalli</copyright>
    <lastBuildDate>Mon, 30 Mar 2026 00:00:00 +0200</lastBuildDate>
    <atom:link href="https://tobiacavalli.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Systems engineering in materials design</title>
      <link>https://tobiacavalli.com/essays/systems-engineering-materials-design/</link>
      <pubDate>Mon, 30 Mar 2026 00:00:00 +0200</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/essays/systems-engineering-materials-design/</guid>
      <description>The PSPP framework and the systems concepts behind it. If the chain from processing to performance is causal in both directions, it can be read backward, turning material substitution into a design problem.</description>
      <content:encoded><![CDATA[<figure><img src="/essays/systems-engineering-materials-design/systems.svg" alt="Cover image" width="800" height="800" loading="eager" decoding="async" fetchpriority="high" /><figcaption><span class="figure-number"></span>Illustration by <a
  href="https://unsplash.com/@sliceform"
    target="_blank" rel="noopener noreferrer">@sliceform</a
></figcaption>
</figure><p>Every few years, international political tensions disrupt the global supply of
rare earths, and every time this results in a scramble to find more ore or to
build refineries faster.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> China controls around 70% of rare-earth
processing, but even if you solved that bottleneck tomorrow, you would still
have a problem: rare earths are not interchangeable commodities.</p>
<p>Neodymium, for example, is central in permanent magnets, which drive wind
turbines and electric motors. The problem is that this element cannot be
swapped with a different element, because that would force you to redesign the
corresponding alloy. A different alloy needs different processing. Different
processing produces a different structure, different magnetic properties, and
different performance in the final device. One substitution, and the whole
application doesn&rsquo;t work anymore. Why?</p>
<p>The cascade from composition through processing through structure to
performance is not specific to magnets. All materials work this way. We tend to
think of a material as a property on a datasheet, but it is really a web of
cause-and-effect relationships that goes from atoms to applications. There is a
framework that maps these relationships as a system:
<strong>process-structure-properties-performance</strong>, or <strong>PSPP</strong>. The rest of this
post is about what this framework looks like and where it comes from.</p>
<h2 id="what-is-a-material">
  <a class="heading-anchor" href="#what-is-a-material" aria-hidden="true" tabindex="-1">#</a>
  What is a material?
</h2><p>Before exploring how systems thinking enters materials science, I think it
helps to be precise about what a material is. However, when I turned to
standard textbooks looking for a definition, I couldn’t find one.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> They
classify materials, describe their properties, discuss their history, but never
say what the word actually means.</p>
<p>So I searched further for a working definition of &ldquo;material&rdquo;, and to my
surprise, I found that defining the term is not at all straightforward.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>
<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> As I understand the problem, three factors make this harder than I
initially assumed:</p>
<ol>
<li>The word &ldquo;material&rdquo; is treated as a primitive &mdash; a word everyone
understands well enough that it doesn&rsquo;t need a formal definition.</li>
<li>The field is interdisciplinary, and no single discipline has felt the need
to own the definition.</li>
<li>There is no clear boundary between a &ldquo;chemical&rdquo; and a &ldquo;material.&rdquo; The
distinction depends on length scale, but where do you draw the line? Is a
single molecule of polyethylene a material? What about a monolayer or a
colloidal suspension?<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></li>
</ol>
<p>Eventually I found two definitions that I could work with. In <em>Materials
Chemistry</em>, Fahlman defines a material as:<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></p>
<div class="callout callout-note">
      <p class="callout-title">Definition</p>
      <p>Any solid-state substance or device that may be used to address a current or
future societal need.</p>
    </div><p><em>Nature Materials</em> gives a similar definition, but with a broader scope:<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></p>
<div class="callout callout-note">
      <p class="callout-title">Definition</p>
      <p>[&hellip;] substances in the condensed states (liquid, solid, colloidal) designed
or manipulated for technological ends.</p>
    </div><p>These definitions, together with the broader discussion cited earlier, point to
three features that seem to be common to all materials:</p>
<ol>
<li>They are condensed-state substances.</li>
<li>Their properties emerge from the interactions, assembly, and defect
structure of their constituent subunits.</li>
<li>They are created or designed for a specific purpose.</li>
</ol>
<p>In other words, a material is not raw matter sitting in the ground: <strong>it is
matter that someone has processed with an end in mind</strong>. The definition itself
encodes a relationship between processing, structure, and purpose, and this
entanglement is not just a matter of semantics, because the concept cannot be
reduced to a single property or a single scale. If the definition is this
entangled, perhaps the right answer is not a sharper definition but a better
framework to think about materials.</p>
<h2 id="three-questions-and-a-chain">
  <a class="heading-anchor" href="#three-questions-and-a-chain" aria-hidden="true" tabindex="-1">#</a>
  Three questions and a chain
</h2><p>The study of materials is often divided into three disciplines: <strong>materials
science</strong>, <strong>materials engineering</strong>, and <strong>materials design</strong>. However, this
division is cleaner on paper than in practice. A more useful way to think about
them is as three questions, each building on the last.</p>
<p>The first question is <strong>why.</strong> Why does this material behave the way it does?
This is materials science, which investigates the relationships between a
material&rsquo;s structure and its properties. A materials scientist synthesizes a
new material and asks what gives it its characteristics.</p>
<p>The second question is <strong>how.</strong> How do we make a material behave the way we
want? This is materials engineering: designing or manipulating the structure to
produce a predetermined set of properties. Where the scientist asks why
something works, the engineer asks how to produce it and make it work
differently.</p>
<p>The third question is <strong>which.</strong> Which material and which process satisfy a
specific need? The answer takes different forms depending on the starting
point:</p>
<ul>
<li>Materials <strong>discovery</strong> screens all possibilities.</li>
<li>Materials <strong>design</strong> explores a specific region of the design space, often
adding new materials or properties to it.</li>
<li>Materials <strong>selection</strong> picks the best candidate from a space that is already
known.</li>
</ul>
<p>All three sit close to the application and depend on the answers to the other
two questions.</p>
<p>A material&rsquo;s properties depend on the spatial organization of its constituents
at every hierarchical level, from atomic arrangement up to macroscopic form.
But structure is not static. At any moment, a material carries structural
features that have not yet reached thermodynamic equilibrium. These features
reflect not only what it is made of, but how it was made and what it has
endured in service. Processing stays with the material long after it is
produced.</p>
<p>This causal chain &mdash; processing determines structure, structure determines
properties, properties determine performance &mdash; is the central paradigm of
materials science and engineering, and it is known as
<strong>process-structure-properties-performance (PSPP)</strong>.<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup> <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup> The diagram
below shows how it works:</p>
<figure><img src="/essays/systems-engineering-materials-design/pspp.svg" alt="Process-structure-properties-performance diagram" width="800" height="158" loading="lazy" decoding="async" /><figcaption><span class="figure-number"></span>The PSPP framework: processing determines structure, structure determines properties, properties determine performance.</figcaption>
</figure><p>Materials science typically works the chain from left to right: you start with
a process and ask what properties come out. This is the forward problem. You
pick apart individual links and examine them in isolation, like how does this
heat treatment change the grain size, and how does grain size affect hardness?
Each link gets its own experiments, its own models.</p>
<p>Materials design goes the other way. You start with what you need the material
to do and work backward: what properties would deliver that performance, what
structures would produce those properties, and what processing would create
those structures? This is the inverse problem, and it only becomes tractable if
you can hold the full chain in view at once.</p>
<h2 id="materials-as-systems">
  <a class="heading-anchor" href="#materials-as-systems" aria-hidden="true" tabindex="-1">#</a>
  Materials as systems
</h2><p>So far, PSPP looks like a causal chain where one thing leads to the next. But
that picture is too simple. PSPP treats a material as a <strong>system</strong>, and that
word carries specific meaning.</p>
<p>A system is an arrangement of <strong>elements</strong>, <strong>interconnections</strong>, and a
<strong>function</strong> that work together to fulfill a <strong>purpose</strong>.<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup> The elements can
be tangible (atoms, grains, phases) or abstract (a model, a design constraint).
The interconnections define how elements influence each other. The function is
what the system is designed (or has evolved) to do.</p>
<p>A system&rsquo;s behavior over time is tracked through <strong>stocks</strong> and <strong>flows</strong>. A
stock is a measurable quantity that accumulates. Flows are the rates at which a
stock changes: inflows add to it, outflows subtract. When inflows and outflows
balance, the system reaches dynamic equilibrium. In a material, structure is
the central stock. Every processing step &mdash; every heat treatment, every
deformation pass, every hour in service &mdash; is a flow that deposits or removes
structural features. The microstructure you observe at any moment is the
cumulative record of everything the material has experienced.</p>
<p>Consistent behavior patterns in a system arise from <strong>feedback loops</strong>:
circular relationships where the system&rsquo;s output influences its own behavior.
Materials are full of them. Grain growth during annealing slows as grains
coarsen, because larger grains have less boundary energy driving further
growth. Crack propagation accelerates as a crack lengthens, because the stress
concentration at the tip increases with crack size. These loops (some
stabilizing, some reinforcing) are what give materials their characteristic
responses to time and environment.</p>
<p>What makes a system more than the sum of its parts is <strong>emergence</strong>: the
interactions between components produce behaviors that no single component
exhibits alone. A pile of iron atoms is not steel. The arrangement matters, and
the properties that result from that arrangement cannot be deduced by studying
iron and carbon in isolation.</p>
<p>A material is a hierarchically organized system composed of subsystems, each
operating at a different length scale. At the atomic scale: bonding and crystal
structure. At the microstructural scale: grain size, phase distribution, and
defect populations. At the macroscopic scale: geometry, surface condition, and
manufacturing history. Each level has its own characteristic structures and its
own models, but none is self-contained, and changes at one scale propagate up
and down the hierarchy.</p>
<h2 id="from-smith-to-systems-engineering">
  <a class="heading-anchor" href="#from-smith-to-systems-engineering" aria-hidden="true" tabindex="-1">#</a>
  From Smith to systems engineering
</h2><p>The idea that materials behave as systems did not arrive all at once. In his
cornerstone article on materials design, Olson traces the origins of this idea
to the metallurgist and historian of science Cyril Stanley Smith, who was among
the first to describe materials as hierarchical systems.<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup> Clarence Zener
extended Smith&rsquo;s picture by adding the path dimension: processing history. In
any real material, some structural features have not had time to equilibrate.
The system is never at rest, and it carries the memory of how it was made.</p>
<p>Morris Cohen then introduced the principle of <strong>reciprocity</strong> between structure
and properties: properties can be rationalized in terms of structure, but
structure can equally be rationalized in terms of the properties it produces.
If the structure&ndash;property link runs both ways, then tools built to explain can
also be turned around to design.</p>
<p>What was still missing was a way to integrate these insights into something
operational. That came from systems engineering. The first step is analysis to
identify the problem and decompose it into component subsystems and their
interactions. This step is followed by synthesis: develop models for each
subsystem, integrate them to generate candidate solutions, build prototypes,
and test. Feedback from testing drives iterative redesign until the objectives
are met. Applied to materials, each scale becomes a subsystem with its own
models, its own experiments, and its own interface to the scales above and
below.</p>
<h2 id="reading-the-chain-backward">
  <a class="heading-anchor" href="#reading-the-chain-backward" aria-hidden="true" tabindex="-1">#</a>
  Reading the chain backward
</h2><p>For most of its history, materials development advanced through testing
compositions, adjusting processes, and accumulating know-how. Serendipity
played a significant role in this process, and still does.<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup> <sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup> If we
wanted a better magnet, we made magnets and tested them until something worked.</p>
<p>But if the links between processing, structure, properties, and performance are
causal in both directions, then the chain can be read backward. Start with a
need. Translate it into performance requirements, then into target properties,
then into the structures that would produce them, and finally into the
processing routes that would create those structures.</p>
<p>This changes what the rare-earth problem actually is. Without PSPP, a supply
disruption is a procurement problem: find more ore, build more refineries,
secure the chain. With PSPP, it is a design problem: identify which scales are
coupled to the element you are losing, which feedback loops constrain
substitution, and which processing routes are available for candidate
replacements. Those are different questions, and they lead to different
responses and different timescales.</p>
<p>The practical tools for carrying out this inversion &mdash; computational modeling,
materials informatics, integrated computational materials engineering &mdash; are
subjects for future posts. What matters here is the shift in how we ask the
question.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Tewari, S. China controls the rare earths the world buys - can Trump’s new deals change that? BBC News. <a
  href="https://www.bbc.com/news/articles/cj6ny24j0r3o"
    target="_blank" rel="noopener noreferrer">https://www.bbc.com/news/articles/cj6ny24j0r3o</a
>
 (accessed 2026-03-28).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Callister, W. D.; Rethwisch, D. G. <em>Materials Science and Engineering: An Introduction</em>, 10th ed.; Wiley: Hoboken, 2020.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Ashby, M. F.; Shercliff, H.; Cebon, D. <em>Materials: Engineering, Science, Processing and Design</em>, 4th ed.; Butterworth-Heinemann: Oxford, UK, 2019.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Moss, S. What Is a Material? <em>MRS Bull.</em> <strong>2012</strong>, <em>37</em> (1), 95–96. <a
  href="https://doi.org/10.1557/mrs.2011.353"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1557/mrs.2011.353</a
>
.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Day, P.; Interrante, L.; West, A. Chemistry International &ndash; Newsmagazine for IUPAC. <em>Chemistry International</em>. IUPAC 2009. <a
  href="https://publications.iupac.org/ci/2009/3103/1_day.html"
    target="_blank" rel="noopener noreferrer">https://publications.iupac.org/ci/2009/3103/1_day.html</a
>
 (accessed 2026-03-26).&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Marschallek, B. E.; Jacobsen, T. Classification of Material Substances: Introducing a Standards-Based Approach. <em>Mater. Des.</em> <strong>2020</strong>, <em>193</em>, 108784. <a
  href="https://doi.org/10.1016/j.matdes.2020.108784"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1016/j.matdes.2020.108784</a
>
.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Defining scientific concepts is a difficult task. Chang&rsquo;s <em>Inventing Temperature</em> (Oxford University Press, 2004) is a great account of the difficulty of defining the scientific concept of &ldquo;temperature&rdquo;. See <a
  href="https://doi.org/10.1093/0195171276.001.0001"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1093/0195171276.001.0001</a
>
.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Fahlman, B. D. <em>Materials Chemistry</em>; Springer International Publishing: Cham, 2023. <a
  href="https://doi.org/10.1007/978-3-031-18784-1"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1007/978-3-031-18784-1</a
>
.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Aims &amp; Scope | Nature Materials. Nature Materials. <a
  href="https://www.nature.com/nmat/aims"
    target="_blank" rel="noopener noreferrer">https://www.nature.com/nmat/aims</a
>
 (accessed 2026-03-28).&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Olson, G. B. Computational Design of Hierarchically Structured Materials. <em>Science</em> <strong>1997</strong>, <em>277</em> (5330), 1237–1242. <a
  href="https://doi.org/10.1126/science.277.5330.1237"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1126/science.277.5330.1237</a
>
.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Agrawal, A.; Choudhary, A. Perspective: Materials Informatics and Big Data: Realization of the &ldquo;Fourth Paradigm&rdquo; of Science in Materials Science. <em>APL Mater.</em> <strong>2016</strong>, <em>4</em> (5), 053208. <a
  href="https://doi.org/10.1063/1.4946894"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1063/1.4946894</a
>
.&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>D. H. Meadows and D. Wright, <em>Thinking in systems: A Primer</em>, Chelsea Green Publishing, White River Junction, VT, 2015.&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Olson, G. B. Designing a New Material World. <em>Science</em> <strong>2000</strong>, <em>288</em> (5468), 993–998. <a
  href="https://doi.org/10.1126/science.288.5468.993"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1126/science.288.5468.993</a
>
.&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Fink, T. M. A.; Reeves, M.; Palma, R.; Farr, R. S. Serendipity and Strategy in Rapid Innovation. <em>Nat. Commun.</em> <strong>2017</strong>, <em>8</em> (1), 2002. <a
  href="https://doi.org/10.1038/s41467-017-02042-w"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1038/s41467-017-02042-w</a
>
.&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>McDowell, D. L.; Kalidindi, S. R. The Materials Innovation Ecosystem: A Key Enabler for the Materials Genome Initiative. <em>MRS Bull.</em> <strong>2016</strong>, <em>41</em> (4), 326–337. <a
  href="https://doi.org/10.1557/mrs.2016.61"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1557/mrs.2016.61</a
>
.&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Getting started with mixture experiments</title>
      <link>https://tobiacavalli.com/guides/getting-started-mixture-experiments/</link>
      <pubDate>Tue, 05 Aug 2025 00:00:00 +0200</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/guides/getting-started-mixture-experiments/</guid>
      <description>An introduction to mixture experimental design through a polymer yarn formulation example: simplex lattice design, Scheffé polynomials, response surface interpretation, and software recommendations.</description>
      <content:encoded><![CDATA[<h2 id="what-are-mixture-experiments">
  <a class="heading-anchor" href="#what-are-mixture-experiments" aria-hidden="true" tabindex="-1">#</a>
  What are mixture experiments?
</h2><p>Design of experiments (DOE) provides many tools for studying physical
systems. All share the goal of efficiently identifying how specific
variables (<em>factors</em>) control the properties (<em>responses</em>) of a system.
<strong>Factorial designs</strong> and <strong>fractional factorial designs</strong> are two
well-known approaches, but they assume that factors can be varied
independently. In many chemical systems, this assumption fails.</p>
<p><strong>Mixtures</strong> are one such case. The response depends on the relative
proportions of the ingredients, not on their absolute quantities. This
constraint applies to pharmaceutical formulations, glass development,
polymer blends, food products &mdash; any system where the components'
proportions must sum to 1. <strong>Mixture designs</strong> are built specifically
for these systems.</p>
<h2 id="a-simplex-example">
  <a class="heading-anchor" href="#a-simplex-example" aria-hidden="true" tabindex="-1">#</a>
  A simplex example
</h2><p>The following example, adapted from John Cornell&rsquo;s &ldquo;A Primer on
Experiments with Mixtures,&rdquo; shows what a simple mixture design and
analysis looks like. Suppose you produce a polymer-based yarn used
for draperies and want to improve its toughness.</p>
<p>Your current formulation is a blend of polyethylene (PE) and
polypropylene (PP). A colleague suggests that substituting
polypropylene with polystyrene (PS) might help. You want to know if
and how this substitution affects the yarn&rsquo;s mechanical properties, and
you want an efficient way to find out.</p>
<h3 id="planning-and-designing-the-experiments">
  <a class="heading-anchor" href="#planning-and-designing-the-experiments" aria-hidden="true" tabindex="-1">#</a>
  Planning and designing the experiments
</h3><p>First, you need to choose a property that you can measure &mdash; your response
variable <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span>. You decide to take a closer look at the elongation of fibers
produced with different polymer blends, which measures how much you can
lengthen your fibers before they break.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>Next, you need to plan your experiments (in DOE terminology: you need to plan
your <em>experimental runs</em>). How are you going to vary the proportions of PE, PP,
and PS? You need to ensure that you cover the experimental region while
minimizing the number of experiments that you&rsquo;ll run.</p>
<p>Mixture designs are built for situations where the components must sum
to a constant &mdash; typically 100% or 1. The experimental space is
represented using simplex-based geometries (triangular for 3
components, tetrahedral for 4, etc.) and each experimental run is
optimally placed inside the simplex, ensuring that the compositional
space is properly explored.</p>
<p>The simplest mixture design is the <strong>Simplex Lattice Design (SLD)</strong>. In this
type of design, each <em>factor</em> (in this case, PE, PP, and PS) can take <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">m+1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>
values (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo separator="true">,</mo><mn>1</mn><mi mathvariant="normal">/</mi><mi>m</mi><mo separator="true">,</mo><mn>2</mn><mi mathvariant="normal">/</mi><mi>m</mi><mo separator="true">,</mo><mo>…</mo><mo separator="true">,</mo><mi>m</mi><mi mathvariant="normal">/</mi><mi>m</mi></mrow><annotation encoding="application/x-tex">0, 1/m, 2/m, \dots, m/m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">1/</span><span class="mord mathnormal">m</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2/</span><span class="mord mathnormal">m</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner">…</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">m</span><span class="mord">/</span><span class="mord mathnormal">m</span></span></span></span>) where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi></mrow><annotation encoding="application/x-tex">m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> represents the number of
levels. A level is the specific value that a factor takes in a given
run. The value of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi></mrow><annotation encoding="application/x-tex">m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> is also important for later
modeling, because it defines the order of the polynomial that can be fitted to
the data: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">m=1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> means you&rsquo;ll only be able to fit first order polynomials,
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">m=2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> second order, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>=</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">m=3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span> third order, and so on.</p>
<p>You decide to keep it simple and explore only pure or binary blend
compositions, meaning that each factor is going to take two levels (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">m=2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>).
This setup includes three points for each component: 1 for a single-component,
0.5 for the binary blend, and 0 for blends that do not include that component.
This allows you to fit a second-order polynomial and see how pairs of
components interact.</p>
<p>Calculating the proportions and plotting them, the design looks like
this:</p>
<figure><img src="/guides/getting-started-mixture-experiments/design_points.svg" alt="SLD design" width="800" height="746" loading="lazy" decoding="async" /><figcaption><span class="figure-number"></span>Simplex Lattice Design (SLD) for a
three-component system. The triangle shows the entire compositional space
defined by the three components (polyethylene, polypropylene, and polystyrene).
The red dots indicate the experimental runs required to map the entire space.</figcaption>
</figure><h3 id="analyzing-the-results">
  <a class="heading-anchor" href="#analyzing-the-results" aria-hidden="true" tabindex="-1">#</a>
  Analyzing the results
</h3><p>You prepare the 6 polymer blends, spin them into yarns, and measure
their elongation. Using shorthand notation &mdash; <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">x_{1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> for
polyethylene, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">x_{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> for polystyrene, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">x_{3}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> for polypropylene
&mdash; and averaging three replicates per run, the results are:</p>
<table>
  <thead>
      <tr>
          <th>Design point</th>
          <th style="text-align: right"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">x_{1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></th>
          <th style="text-align: right"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">x_{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></th>
          <th style="text-align: right"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">x_{3}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></th>
          <th style="text-align: right">Average elongation</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td style="text-align: right">1</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">11.7</td>
      </tr>
      <tr>
          <td>2</td>
          <td style="text-align: right">1/2</td>
          <td style="text-align: right">1/2</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">15.3</td>
      </tr>
      <tr>
          <td>3</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">1</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">9.4</td>
      </tr>
      <tr>
          <td>4</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">1/2</td>
          <td style="text-align: right">1/2</td>
          <td style="text-align: right">10.5</td>
      </tr>
      <tr>
          <td>5</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">1</td>
          <td style="text-align: right">16.4</td>
      </tr>
      <tr>
          <td>6</td>
          <td style="text-align: right">1/2</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">1/2</td>
          <td style="text-align: right">16.9</td>
      </tr>
  </tbody>
</table>
<p>At this point, you&rsquo;ll want to fit this data into a model that can be used to
extrapolate the behavior of the system. There is one problem, though. Consider
a standard polynomial with an intercept <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{0}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>y</mi><mo>=</mo><msub><mi>β</mi><mn>0</mn></msub><mo>+</mo><msub><mi>β</mi><mn>1</mn></msub><msub><mi>x</mi><mn>1</mn></msub><mo>+</mo><msub><mi>β</mi><mn>2</mn></msub><msub><mi>x</mi><mn>2</mn></msub><mo>+</mo><msub><mi>β</mi><mn>3</mn></msub><msub><mi>x</mi><mn>3</mn></msub><mo>+</mo><mo>…</mo></mrow><annotation encoding="application/x-tex">
y = \beta_{0} + \beta_{1}x_{1} + \beta_{2}x_{2} + \beta_{3}x_{3} + \dots
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.123em;"></span><span class="minner">…</span></span></span></span></span><p>Where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{3}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> are the regression
coefficients of each component. In mixture space, when all components approach
zero we have <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>1</mn></msub><mo>→</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x_{1} \rightarrow 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>2</mn></msub><mo>→</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x_{2} \rightarrow 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>3</mn></msub><mo>→</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x_{3}
\rightarrow 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span>. However, this violates the mixture constraint, since the sum
of all components <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mo>∑</mo><mi>i</mi></msub><msub><mi>x</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">\sum_{i} x_{i}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0497em;vertical-align:-0.2997em;"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.162em;"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2997em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> must equal 1. There is no point
in mixture space where all <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mi>i</mi></msub><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x_{i} = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span>, so the intercept
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{0}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> has no physical meaning.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>The solution is to use Scheffé polynomials, special polynomial forms
that respect the mixture constraint. For a ternary
mixture system, the second-order Scheffé polynomial is:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>y</mi><mo>=</mo><msub><mi>β</mi><mn>1</mn></msub><msub><mi>x</mi><mn>1</mn></msub><mo>+</mo><msub><mi>β</mi><mn>2</mn></msub><msub><mi>x</mi><mn>2</mn></msub><mo>+</mo><msub><mi>β</mi><mn>3</mn></msub><msub><mi>x</mi><mn>3</mn></msub><mo>+</mo><msub><mi>β</mi><mn>12</mn></msub><msub><mi>x</mi><mn>1</mn></msub><msub><mi>x</mi><mn>2</mn></msub><mo>+</mo><msub><mi>β</mi><mn>13</mn></msub><msub><mi>x</mi><mn>1</mn></msub><msub><mi>x</mi><mn>3</mn></msub><mo>+</mo><msub><mi>β</mi><mn>23</mn></msub><msub><mi>x</mi><mn>2</mn></msub><msub><mi>x</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">
y = \beta_{1}x_{1} + \beta_{2}x_{2} + \beta_{3}x_{3} + \beta_{12}x_{1}x_{2} +
\beta_{13}x_{1}x_{3} + \beta_{23}x_{2}x_{3}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">12</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">13</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">23</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span><p>Here, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{3}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> represent the expected
response when component 1, 2, and 3 respectively comprise 100% of the mixture,
whereas the terms <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>12</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{12}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">12</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>13</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{13}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">13</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>β</mi><mn>23</mn></msub></mrow><annotation encoding="application/x-tex">\beta_{23}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">23</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> represent
binary interactions. These latter terms have physical meaning and represent
synergistic or antagonistic effects between components.</p>
<p>The fitted model becomes:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>y</mi><mo>=</mo><mn>11.7</mn><mo>⋅</mo><msub><mi>x</mi><mn>1</mn></msub><mo>+</mo><mn>9.4</mn><mo>⋅</mo><msub><mi>x</mi><mn>2</mn></msub><mo>+</mo><mn>16.4</mn><mo>⋅</mo><msub><mi>x</mi><mn>3</mn></msub><mo>+</mo><mn>19.0</mn><mo>⋅</mo><msub><mi>x</mi><mn>1</mn></msub><msub><mi>x</mi><mn>2</mn></msub><mo>+</mo><mn>11.4</mn><mo>⋅</mo><msub><mi>x</mi><mn>1</mn></msub><msub><mi>x</mi><mn>3</mn></msub><mo>−</mo><mn>9.6</mn><mo>⋅</mo><msub><mi>x</mi><mn>2</mn></msub><msub><mi>x</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">
y = 11.7 \cdot x_{1} + 9.4 \cdot x_{2} + 16.4 \cdot x_{3} + 19.0 \cdot
x_{1}x_{2} + 11.4 \cdot x_{1}x_{3} -9.6 \cdot x_{2}x_{3}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">11.7</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">9.4</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">16.4</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">19.0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">11.4</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">9.6</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span><p>With six experiments, you now have a model that describes the
elongation for <strong>any binary blend</strong> of the three polymers. Plotting the
model over the simplex shows the full picture:</p>
<figure><img src="/guides/getting-started-mixture-experiments/rsm_contour.svg" alt="Polymer response surface" width="800" height="830" loading="lazy" decoding="async" /><figcaption><span class="figure-number"></span>Response surface modeled on the
collected data</figcaption>
</figure><p>This type of visualization is called a <strong>response surface</strong>. It shows
how a response (the elongation) changes across the entire
compositional space. Each point within the triangle represents a unique
three-component composition, while the distances from the three sides
correspond to the proportions of each component. The contour lines show predicted elongation values, revealing trends
that would not be obvious from the raw data alone.</p>
<p>The results show that your colleague&rsquo;s intuition was partially right.
The PE-PS combination has a strong synergistic effect: the binary blend
achieves 15.3 elongation, 45% higher than the simple average of the
pure components (10.55). But in absolute terms, the PE-PP blend still
wins. The highest elongation values (16-17 range) occur along the PE-PP
edge, with the maximum near the 50:50 PE:PP blend (16.9 from design
point 6). PS-PP combinations show antagonistic behavior, particularly
in the lower-right region of the triangle.</p>
<p>The model provides clear guidance for optimization. If maximum
elongation is the primary goal, aim for compositions between 40-60% PE
and 40-60% PP with minimal PS content. If other considerations require
PS, keep it below 20% while maintaining high PE content to take
advantage of the PE-PS synergy. The relatively flat response surface
around the PE-PP optimum also suggests these formulations will be
robust to minor mixing variations during production.</p>
<h2 id="where-to-learn-more">
  <a class="heading-anchor" href="#where-to-learn-more" aria-hidden="true" tabindex="-1">#</a>
  Where to learn more
</h2><p>This example covered the simplest case. Several important topics were
left out:</p>
<ul>
<li>Modeling ternary interactions.</li>
<li>Designing experiments with more than three mixture components.</li>
<li>Restricting the experimental region by adding further constraints.</li>
<li>Coupling mixture designs with process factors.</li>
</ul>
<p>The following resources cover these and more.</p>
<div class="callout callout-note">
      <p class="callout-title">Note</p>
      <p>I am not affiliated with any of the following publishers or software companies.</p>
    </div><h3 id="books">
  <a class="heading-anchor" href="#books" aria-hidden="true" tabindex="-1">#</a>
  Books
</h3><ul>
<li><strong>&ldquo;Experiments with Mixtures&rdquo; by John Cornell</strong>
(<a
  href="https://doi.org/10.1002/9781118204221"
    target="_blank" rel="noopener noreferrer">10.1002/9781118204221</a
>
): The most
thorough reference on mixture designs available. Published in 2002 and
showing its age in some aspects, but still unmatched in depth. Assumes
strong statistical foundations; some chapters are heavily mathematical.</li>
<li><strong>&ldquo;A Primer on Experiments with Mixtures&rdquo; by John Cornell</strong>
(<a
  href="https://doi.org/10.1002/9781118204221"
    target="_blank" rel="noopener noreferrer">10.1002/9781118204221</a
>
): Cornell&rsquo;s
shorter, more accessible version of the above. Covers much of the same
content in a more direct way.</li>
<li><strong>&ldquo;Formulation Simplified&rdquo; by Mark Anderson, Patrick Whitcomb, and Martin
Bezener</strong> (<a
  href="https://doi.org/10.4324/9781315165578"
    target="_blank" rel="noopener noreferrer">10.4324/9781315165578</a
>
):
A hands-on introduction aimed at practitioners who want to get started
without heavy mathematical detail. Published 2018.</li>
<li><strong>&ldquo;Response Surfaces, Mixtures, and Ridge Analyses&rdquo; by George Box and Norman
Draper</strong> (<a
  href="https://doi.org/10.1002/0470072768"
    target="_blank" rel="noopener noreferrer">10.1002/0470072768</a
>
): Covers
advanced response surface modeling topics. Not limited to mixture designs,
but useful for complex systems.</li>
<li><strong>&ldquo;Design and Analysis of Experiments&rdquo; by Douglas Montgomery</strong> (<a
  href="https://www.wiley.com/en-us/Design&#43;and&#43;Analysis&#43;of&#43;Experiments%2C&#43;10th&#43;Edition-p-9781119492443"
    target="_blank" rel="noopener noreferrer">Link to
publisher
website</a
>
)
and <strong>&ldquo;Design and Analysis of Experiments&rdquo; by Angela Dean, Daniel Voss, and
Danel Draguljić</strong>
(<a
  href="https://doi.org/10.1007/978-3-319-52250-0"
    target="_blank" rel="noopener noreferrer">10.1007/978-3-319-52250-0</a
>
):
Both these books provide broad and thorough introductions to DOE
fundamentals, from planning to designing and modeling. Among the various
approaches, they also include short chapters on the basics of mixture
experiments.</li>
</ul>
<h3 id="software">
  <a class="heading-anchor" href="#software" aria-hidden="true" tabindex="-1">#</a>
  Software
</h3><p>There are two main options for running mixture analyses, each with
different tradeoffs between ease-of-use and cost:</p>
<ol>
<li>A proprietary DOE program with a graphical interface.</li>
<li>R or Python with dedicated libraries.</li>
</ol>
<h4 id="commercial-solutions">
  <a class="heading-anchor" href="#commercial-solutions" aria-hidden="true" tabindex="-1">#</a>
  Commercial solutions
</h4><p>Several GUI-based DOE platforms support mixture designs:</p>
<ul>
<li><a
  href="https://www.minitab.com/en-us/"
    target="_blank" rel="noopener noreferrer">Minitab</a
>
,</li>
<li><a
  href="https://www.statease.com/software/design-expert/"
    target="_blank" rel="noopener noreferrer">Design-Expert</a
>
</li>
<li><a
  href="https://www.ibm.com/products/spss"
    target="_blank" rel="noopener noreferrer">SPSS</a
>
</li>
<li><a
  href="https://www.jmp.com/en/home"
    target="_blank" rel="noopener noreferrer">JMP</a
>
</li>
<li><a
  href="https://www.sas.com"
    target="_blank" rel="noopener noreferrer">SAS</a
>
</li>
<li><a
  href="https://www.ncss.com"
    target="_blank" rel="noopener noreferrer">NCSS</a
>
</li>
</ul>
<p>These are GUI-based statistical platforms with built-in DOE
functionality. Each has a learning curve, but they are generally
straightforward to use once set up.</p>
<p>I avoid this kind of software for two reasons:</p>
<ol>
<li><em>They&rsquo;re expensive</em>. For example, at the time of writing a single one-year
license subscription for Design-Expert costs 1140 USD, while a single
one-year license subscription for Minitab is priced at 1851 USD.</li>
<li><em>They provide black-box solutions</em>. Being closed-source means you can&rsquo;t
inspect what a certain function in the program actually does. This might not
be a concern for you now, but it might be in the future when you need to
understand exactly how a result was obtained.</li>
</ol>
<h4 id="free-coding-alternatives">
  <a class="heading-anchor" href="#free-coding-alternatives" aria-hidden="true" tabindex="-1">#</a>
  Free coding alternatives
</h4><p>Everything these programs do can be replicated in code, with greater
flexibility and full reproducibility. For mixture designs, the two
main options are <strong>R</strong> (<a
  href="https://www.r-project.org"
    target="_blank" rel="noopener noreferrer">R Project</a
>
) and
<strong>Python</strong> (<a
  href="https://www.python.org"
    target="_blank" rel="noopener noreferrer">Python.org</a
>
).</p>
<p>R was built for statistics; Python is a general-purpose language that
has become a standard for data analysis. The tradeoff is
straightforward: full control over the analysis, at the cost of
learning to program. Both provide dedicated libraries that cover most
of what commercial software offers.</p>
<ul>
<li>R libraries: R has a
<a
  href="https://cran.r-project.org/web/views/ExperimentalDesign.html"
    target="_blank" rel="noopener noreferrer">mature DOE ecosystem</a
>
.
For mixture work specifically, the <code>mixexp</code> package
(<a
  href="https://cran.r-project.org/web/packages/mixexp/index.html"
    target="_blank" rel="noopener noreferrer">documentation</a
>
,
<a
  href="https://www.jstatsoft.org/article/view/v072c02"
    target="_blank" rel="noopener noreferrer">JSS article</a
>
) handles
design generation, analysis, and basic response surface plots. All plots
and analyses in this post were done in R using <code>mixexp</code> and the
<code>Ternary</code> package
(<a
  href="https://ms609.github.io/Ternary/"
    target="_blank" rel="noopener noreferrer">documentation</a
>
).
The <a
  href="cornell-plot.R">R script used for this post</a
>
 is available.</li>
<li>Python libraries: Python&rsquo;s DOE ecosystem is less developed than R&rsquo;s
for mixture designs. The available options:
<ul>
<li><a
  href="https://github.com/sebhaan/DoEgen"
    target="_blank" rel="noopener noreferrer">DoEgen</a
>
: The most complete
Python DOE library, actively developed.</li>
<li><a
  href="https://github.com/statease/dexpy"
    target="_blank" rel="noopener noreferrer">dexpy</a
>
: Based on Design-Expert,
developed by Stat-Ease. Supports SLD, simplex-centroid designs, and
D-optimal designs. Not updated since 2018.</li>
<li><a
  href="https://github.com/JosiahMcMillan/ExperimentsPyDesign"
    target="_blank" rel="noopener noreferrer">ExperimentsPyDesign</a
>
:
Covers various experimental designs, though mixture support is
limited to simple SLD.</li>
</ul>
</li>
</ul>
<p>The polymer yarn example used six runs to map an entire ternary
compositional space. Traditional one-factor-at-a-time (OFAT)
approaches would need far more experiments and still miss the
interaction effects that drove the key findings.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This is where domain knowledge matters. Measuring the fibers&rsquo; color
would tell you nothing about toughness. The choice looks obvious here,
but picking the right response becomes non-trivial for more complex or
completely new systems.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>The mixture constraint creates perfect multicollinearity. If you know the
values of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">q-1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> components in a <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi></mrow><annotation encoding="application/x-tex">q</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span></span></span></span>-component mixture, the last
component is completely determined: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mi>q</mi></msub><mo>=</mo><mn>1</mn><mo>−</mo><msubsup><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mrow><mi>q</mi><mo>−</mo><mn>1</mn></mrow></msubsup><msub><mi>x</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">x_{q} = 1 - \sum_{i=1}^{q-1} x_{i}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">q</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1.2537em;vertical-align:-0.2997em;"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.954em;"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">q</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2997em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>.
This means that the design matrix is singular, and therefore the
coefficients cannot be estimated through standard least squares.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Compiling CREST on macOS with M-series Chips</title>
      <link>https://tobiacavalli.com/guides/compiling-crest-macos-m1/</link>
      <pubDate>Fri, 14 Mar 2025 00:00:00 +0100</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/guides/compiling-crest-macos-m1/</guid>
      <description>The standard CREST build fails on Apple Silicon because cmake links against the Accelerate framework. Compiling against openblas and lapack instead fixes it.</description>
      <content:encoded><![CDATA[<img src="/guides/compiling-crest-macos-m1/crest_logo_hu_7fe2377fc0b4503.webp"
         srcset="/guides/compiling-crest-macos-m1/crest_logo_hu_7fe2377fc0b4503.webp 200w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="200"
         height="200"
         alt="CREST logo"
         loading="eager"
         decoding="async" fetchpriority="high" /><p><a
  href="https://crest-lab.github.io/crest-docs/"
    target="_blank" rel="noopener noreferrer">CREST (Conformer-Rotamer Ensemble Sampling
Tool)</a
>
 is a program for exploring
molecular conformations. Developed by the Grimme group at the University of
Bonn, it automates the search for low-energy conformers and rotamers, which is
particularly useful for flexible molecules that can adopt many
configurations.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>The official CREST documentation provides clear installation instructions, but
following them on a Mac with an M-series chip leads to problems. By default,
<code>cmake</code> links against Apple&rsquo;s Accelerate framework. On Arm-based Macs (M1, M2,
etc.), this either fails or produces binaries that segfault at runtime. The
solution is to compile against <code>openblas</code> and <code>lapack</code> instead of Accelerate.</p>
<h2 id="building-against-openblas-and-lapack">
  <a class="heading-anchor" href="#building-against-openblas-and-lapack" aria-hidden="true" tabindex="-1">#</a>
  Building against openblas and lapack
</h2><p>Let&rsquo;s start by getting the source code. Download the latest release of CREST
<a
  href="https://crest-lab.github.io/crest-docs/page/installation/install_basic.html#option-3-compiling-from-source"
    target="_blank" rel="noopener noreferrer">following the instructions on the official
documentation</a
>
.
Be sure to clone the repository and update the necessary submodules. This can be
done by running <code>git submodule update --init</code> after <code>git clone</code>, as explained
<a
  href="https://github.com/crest-lab/crest/issues/333"
    target="_blank" rel="noopener noreferrer">here</a
>
 (credit to Jingdan Chen
for pointing this out).</p>
<p>Now we need to get the right libraries: <code>cmake</code>, <code>gcc</code>, <code>openblas</code> and <code>lapack</code>.
Doing this with Homebrew is straightforward:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">brew install gcc cmake openblas lapack</span></span></code></pre></div><p>Next, we need to tell <code>cmake</code> where to find these libraries. This is where the
official docs don&rsquo;t work when applied on a Mac. CREST&rsquo;s documentation suggests
doing this with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">FC</span><span class="o">=</span>gfortran <span class="nv">CC</span><span class="o">=</span>gcc</span></span></code></pre></div><p>On a Mac with an Arm chip, this resolves to macOS&rsquo;s default compilers,
which will link against Accelerate. Point to the Homebrew-installed
compilers instead:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">FC</span><span class="o">=</span>gfortran-14 <span class="nv">CC</span><span class="o">=</span>gcc-14</span></span></code></pre></div><div class="callout callout-warning">
      <p class="callout-title">Warning</p>
      <p>Check which specific version of <code>gcc</code> Homebrew installed on your system. In my
case, this was version 14, but you might have a different one. You can check
with <code>brew info gcc</code>.</p>
    </div><p>Now tell <code>cmake</code> where to find the <code>lapack</code> and <code>openblas</code> libraries you
installed with Homebrew. Without this, <code>cmake</code> falls back to the macOS system
libraries. Look for the path where Homebrew installed them, and run:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cmake -DCMAKE_PREFIX_PATH<span class="o">=</span><span class="s2">&#34;/opt/homebrew/opt/lapack;/opt/homebrew/opt/openblas&#34;</span> -B _build</span></span></code></pre></div><p>With everything configured correctly, you can finish the compilation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">make -C _build</span></span></code></pre></div><p>This builds CREST in the <code>_build</code> directory, linked against <code>openblas</code> and
<code>lapack</code>.</p>
<h2 id="troubleshooting">
  <a class="heading-anchor" href="#troubleshooting" aria-hidden="true" tabindex="-1">#</a>
  Troubleshooting
</h2><p>If the build fails, check these first:</p>
<ul>
<li>Verify which version of <code>gcc</code> you have installed. Typing <code>gfortran-14</code> when
you have version 13 will produce confusing errors. Run <code>brew info gcc</code> to
confirm.</li>
<li>Confirm the paths to <code>lapack</code> and <code>openblas</code> match your Homebrew
configuration. They may differ depending on how Homebrew is set up on your
system.</li>
<li>If you see errors about missing dependencies, make sure all submodules are
initialized (<code>git submodule update --init</code>).</li>
</ul>
<p>The entire problem comes down to which math libraries <code>cmake</code> links against. The
error messages do not make this obvious, and I spent a couple of hours on it
before finding the fix. Hopefully this saves you the same trouble.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Pracht, P.; Bohle, F.; Grimme, S. Automated Exploration of the Low-Energy
Chemical Space with Fast Quantum Chemical Methods. <em>Phys. Chem. Chem.
Phys.</em> <strong>2020</strong>, <em>22</em> (14), 7169–7192.
<a
  href="https://doi.org/10.1039/C9CP06869D"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1039/C9CP06869D</a
>
.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Pracht, P.; Grimme, S.; Bannwarth, C.; Bohle, F.; Ehlert, S.; Feldmann,
G.; Gorges, J.; Müller, M.; Neudecker, T.; Plett, C.; Spicher, S.;
Steinbach, P.; Wesołowski, P. A.; Zeller, F. CREST—A Program for the
Exploration of Low-Energy Molecular Chemical Space. <em>J. Chem. Phys.</em>
<strong>2024</strong>, <em>160</em> (11), 114110. <a
  href="https://doi.org/10.1063/5.0197592"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1063/5.0197592</a
>
.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>The discovery of the rare earth elements</title>
      <link>https://tobiacavalli.com/essays/from-yttria-to-promethium/</link>
      <pubDate>Sun, 10 Nov 2024 00:00:00 +0100</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/essays/from-yttria-to-promethium/</guid>
      <description>How chemists identified the 17 rare earth elements over more than a century and a half, from Gadolin&amp;rsquo;s discovery of yttria in 1794 to the isolation of promethium in 1947.</description>
      <content:encoded><![CDATA[<p>Rare earth elements are central to modern technology: smartphones, electric
vehicles, and wind turbines all depend on them. Finnish chemist Johan Gadolin
identified the first of them, yttrium, in 1794. Their importance became clear
only in the mid-20th century, more than 150 years later.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>The family consists of scandium, yttrium, and the 15 lanthanides, which sit
between barium and hafnium on the periodic table. Identifying the remaining 16
would take more than a century after Gadolin&rsquo;s work.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<figure><img src="/essays/from-yttria-to-promethium/periodic_table_rees_hu_4f799981b6d4d631.webp"
         srcset="/essays/from-yttria-to-promethium/periodic_table_rees_hu_84fb04db96ea8a8f.webp 400w, /essays/from-yttria-to-promethium/periodic_table_rees_hu_4f799981b6d4d631.webp 800w, /essays/from-yttria-to-promethium/periodic_table_rees_hu_b4910eaebd9eac10.webp 1200w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="533"
         alt="Periodic table with the 17 rare earth elements highlighted: scandium, yttrium, and the 15 lanthanides."
         loading="eager"
         decoding="async" fetchpriority="high" /><figcaption><span class="figure-number"></span>The 17 rare earth elements highlighted on the periodic table: scandium and yttrium in the d-block, and the 15 lanthanides forming the row between barium and hafnium.</figcaption>
</figure><p>At the time, chemists were identifying new elements at a rapid pace. Rare
earths were the most difficult to characterize. Extracted from minerals like
yttria and ceria, they did not fit any of the patterns chemists had developed
for other elements.</p>
<h2 id="neither-rare-nor-earths">
  <a class="heading-anchor" href="#neither-rare-nor-earths" aria-hidden="true" tabindex="-1">#</a>
  Neither rare nor earths
</h2><p>The name &ldquo;rare earths&rdquo; reflects the assumptions of the chemists who first
encountered these substances, not what we now know about them. When chemists
first isolated them in the late 1700s, they obtained them as oxides, which
were then called &ldquo;earths&rdquo; (from the French <em>terre</em> and German <em>Erde</em>).<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>
The minerals containing them, yttria and ceria, were known only from a single
location, the village of Ytterby in Sweden, and their apparent scarcity there
gave the family the other half of its name.<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<p>Rare earths are not actually rare. They are more abundant in Earth&rsquo;s crust
than mercury or cadmium. The difficulty is that they occur in trace
concentrations across many minerals rather than in concentrated deposits, like
a thousand euros in cents scattered across a beach instead of a single
ten-euro bill in your pocket.</p>
<figure><img src="/essays/from-yttria-to-promethium/rees_abundance_hu_9dd33965483b3f01.webp"
         srcset="/essays/from-yttria-to-promethium/rees_abundance_hu_44eae800a51ebde.webp 400w, /essays/from-yttria-to-promethium/rees_abundance_hu_9dd33965483b3f01.webp 800w, /essays/from-yttria-to-promethium/rees_abundance_hu_11de3d7f6396ebc2.webp 1200w, /essays/from-yttria-to-promethium/rees_abundance_hu_1588e924e1d8f161.webp 1600w, /essays/from-yttria-to-promethium/rees_abundance_hu_a18a61e16b9a9078.webp 2100w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="494"
         alt="Plot of the natural abundance (in ppm) of each rare earth element in Earth’s crust."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>The abundance of each rare earth element in Earth&rsquo;s crust, in parts per million. Many of them are more common than gold or platinum, but they occur dispersed across many minerals rather than in concentrated deposits.</figcaption>
</figure><p>The real difficulty was not scarcity but chemical similarity. The 15
lanthanides have nearly identical electron configurations, which makes
separating them like sorting a mix of dark blue and navy blue marbles by
color. Specialized techniques are needed to tell them apart.</p>
<p>This chemical similarity also explains why yttria and ceria are not unique
sources. The same elements were later found in monazite, a mineral that would
become the main industrial source for rare earths. What seemed at first to be
a Swedish curiosity is a family of elements distributed throughout Earth&rsquo;s
crust.</p>
<h2 id="first-discoveries">
  <a class="heading-anchor" href="#first-discoveries" aria-hidden="true" tabindex="-1">#</a>
  First discoveries
</h2><p>Chemistry advanced rapidly in the late 18th and early 19th centuries. Boyle,
Lavoisier, and Dalton established that the elements are the simplest
substances, those that cannot be broken down further by chemical means. By
the mid-19th century, nearly 70 of the 90 naturally occurring elements had
been identified.<sup id="fnref1:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>The rare earths were the exception to this rapid progress. The two minerals
containing them, yttria and ceria, had been identified by 1787, but the
elements within them could not be reliably separated for more than 160 years,
and the last of them, promethium, was not isolated until 1947. Even Dmitri
Mendeleev and Julius Lothar Meyer, who built the first periodic tables in the
1860s, could not fit them into their classification. The puzzle was only
resolved by the development of atomic theory in the 20th century, which
showed why the lanthanides in particular have nearly identical chemical
properties.</p>
<h3 id="yttria">
  <a class="heading-anchor" href="#yttria" aria-hidden="true" tabindex="-1">#</a>
  Yttria
</h3><p>In 1787, Carl Axel Arrhenius, a Swedish army officer and amateur geologist,
collected an unusual black mineral near the village of Ytterby and called it
simply &ldquo;black stone.&rdquo;<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> Swedish chemist Bengt Reinhold Geijer published the
first report on it in 1788, but the decisive analysis came in 1794, when
Finnish chemist Johan Gadolin found that nearly 38% of the stone consisted of
an unknown &ldquo;earth&rdquo; (now known to be an oxide), along with iron and silicate.</p>
<p>In 1795, Swedish chemist Anders Ekeberg confirmed Gadolin&rsquo;s findings and named
the oxide &ldquo;yttria&rdquo; after Ytterby. Like most chemists at the time, Ekeberg
treated the new &ldquo;earth&rdquo; as an element in its own right, a misconception that
persisted until 1808, when Humphry Davy&rsquo;s electrolysis experiments showed that
yttria was a compound. The metallic element within it would later be isolated
and named yttrium.</p>
<p>The black stone continued to yield results. In 1802, Ekeberg identified yttria
in another mineral, yttrotantalite, and from it isolated tantalum. German
chemist Martin Heinrich Klaproth and French chemist Louis Nicolas Vauquelin
independently confirmed Gadolin&rsquo;s analysis. Klaproth then named the original
mineral &ldquo;gadolinite&rdquo; in his honor.</p>
<h3 id="ceria">
  <a class="heading-anchor" href="#ceria" aria-hidden="true" tabindex="-1">#</a>
  Ceria
</h3><p>A second Swedish mineral, cerite, had been suspected of containing an unknown
&ldquo;earth&rdquo; since the mid-1700s, but confirming it took decades. In 1803, two
independent teams reported the result almost simultaneously. The Swedish
chemists Jöns Jacob Berzelius and Wilhelm Hisinger were one, and the German
chemist Martin Heinrich Klaproth, who had earlier confirmed Gadolin&rsquo;s work on
yttria, was the other. Both teams published their findings in the <em>Neues
Allgemeines Journal der Chemie</em> in the same year.</p>
<p>A naming dispute followed. Klaproth proposed &ldquo;ochroite earth,&rdquo; while
Berzelius and Hisinger proposed &ldquo;ceria,&rdquo; after the dwarf planet Ceres, which
had been discovered two years earlier. Ceria won, largely due to Hisinger&rsquo;s standing as
an industrialist and patron of science, though most of the analytical work had
likely been done by the young Berzelius.</p>
<p>The two teams interpreted the result differently. Klaproth treated the new
&ldquo;earth&rdquo; as an element in its own right, the same misconception that had
attached to yttria. Berzelius correctly identified it as the oxide of a new
element, an interpretation consistent with the work that would later make him
one of the founders of modern chemistry: precise atomic mass calculations, the
formalization of atomic theory, and the modern system of chemical symbols.
Klaproth, already known for the discovery of uranium and zirconium, continued
his work on strontium, titanium, and tellurium.</p>
<p>The yttria and ceria discoveries set a pattern that would repeat throughout
the 19th century: the rare earths rarely came alone, and characterizing them
required collaboration across national boundaries.</p>
<h2 id="mosanders-investigation">
  <a class="heading-anchor" href="#mosanders-investigation" aria-hidden="true" tabindex="-1">#</a>
  Mosander&rsquo;s investigation
</h2><p>It took two decades for chemists to realize that the original &ldquo;earths&rdquo; were
not pure elements but metal oxides. Ceria became cerium oxide, yttria became
yttrium oxide. The reclassification was straightforward, but the trouble
began with the atomic masses.</p>
<p>Measurements of the atomic masses of these supposedly pure elements varied
between samples, which had no good explanation if the elements really were
pure. The most plausible interpretation was that they were mixtures.</p>
<p>Carl Gustaf Mosander, assistant to Jöns Jacob Berzelius, took up the problem
in the 1820s and worked on it for the next two decades. He began with cerium,
subjecting it to a long series of reactions. In one experiment he heated
cerium oxide with sodium and chlorine to obtain metallic cerium, and he
noticed that cerium compounds varied in color and density depending on their
mineral source. He concluded that cerium oxide must contain at least one
additional element. His colleague Friedrich Wöhler urged him to publish, but
Mosander refused to commit to a result until he was certain of it, a caution
that frustrated his colleagues but was essential to the discoveries that
followed.</p>
<h2 id="two-earths-become-six">
  <a class="heading-anchor" href="#two-earths-become-six" aria-hidden="true" tabindex="-1">#</a>
  Two earths become six
</h2><p>In 1839, after years of work, Mosander confirmed that cerium oxide was not a
single substance. He isolated a new element from it and named it lanthanum,
from the Greek for &ldquo;to escape notice.&rdquo;<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> Two years later, in 1841, he
identified a third element in cerium oxide and named it didymium, from the
Greek for &ldquo;twin,&rdquo; because its chemistry resembled that of lanthanum. Wöhler
and Berzelius found the name unusual, but the result stood. Didymium would
itself turn out to be a mixture in the 1880s, when it was resolved into
praseodymium and neodymium.</p>
<p>Mosander&rsquo;s analytical methods were as important as the elements he isolated.
He developed techniques for repeated crystallization and gravimetric analysis
that required extreme care, and in 1843 Berzelius documented them in detail,
showing how Mosander had separated cerium, lanthanum, and didymium from what
had appeared to be a single substance.</p>
<p>Mosander then applied the same methods to yttrium oxide, working from
gadolinite. In 1843 he isolated two more elements, erbium and terbium, with
yttrium as the remaining fraction. He used oxalate precipitation to separate
them, exploiting differences in reactivity and in the color and crystal form
of the precipitates. What had begun as two &ldquo;earths,&rdquo; cerium and yttrium, was
now six elements, and the rare earths were not what chemists had first taken
them to be.</p>
<h2 id="spectral-analysis">
  <a class="heading-anchor" href="#spectral-analysis" aria-hidden="true" tabindex="-1">#</a>
  Spectral analysis
</h2><p>Mosander&rsquo;s separation methods were slow. A single result could require months
or years of repeated crystallizations and precise measurements, and as
organic chemistry advanced through the middle of the 19th century, work on
the rare earths slowed.</p>
<p>In 1859, Robert Bunsen and Gustav Kirchhoff introduced spectral analysis.
Heated elements emit light at characteristic wavelengths, and the resulting
pattern of spectral lines is unique to each element. Identification could now
be made directly from the spectrum, without the long sequence of separation
steps that Mosander had relied on.</p>
<p>The technique arrived just as Dmitri Mendeleev and Julius Lothar Meyer were
independently developing the periodic table in the late 1860s. Their table
organized the elements by atomic weight and chemical properties, exposing
relationships between them and even predicting the existence of elements that
had not yet been found.</p>
<p>The two tools were complementary. The periodic table identified gaps where
new elements should exist, and spectral analysis allowed chemists to look
for them directly. The slow crystallization work of Mosander&rsquo;s generation
gave way to a faster mode of discovery.</p>
<h2 id="a-new-generation">
  <a class="heading-anchor" href="#a-new-generation" aria-hidden="true" tabindex="-1">#</a>
  A new generation
</h2><p>Spectral analysis and the periodic table brought a new generation of chemists
to the rare earths. Swiss chemist Jean Charles Galissard de Marignac built on
Mosander&rsquo;s methods to recalculate the atomic weights of cerium, lanthanum,
and didymium with much greater precision. His measurements arrived shortly
after the 1860 Karlsruhe Congress, where the need for standardized atomic
weights had been the central question, and they helped European chemists
converge on consistent values.</p>
<p>Another Swiss chemist, Marc Delafontaine, worked on Mosander&rsquo;s discoveries,
in particular terbium. Several chemists had worked on isolating it, which
makes the discovery hard to attribute to a single individual, but
Delafontaine&rsquo;s systematic studies clarified its properties. He then turned to
didymium, the &ldquo;twin&rdquo; element Mosander had identified, and noticed subtle
differences in its spectral lines that suggested it was not a single element.</p>
<p>The French chemist Paul Émile Lecoq de Boisbaudran later confirmed this.
Working with samarskite, a mineral rich in rare earths, he used spectral
analysis to show that didymium was a mixture. It would eventually be resolved
into praseodymium and neodymium. The pattern set by Mosander&rsquo;s lanthanum and
his original didymium repeated itself: an element that had been treated as
single turned out to be several.</p>
<h2 id="the-final-discoveries">
  <a class="heading-anchor" href="#the-final-discoveries" aria-hidden="true" tabindex="-1">#</a>
  The final discoveries
</h2><p>In 1885, Austrian chemist Carl Auer von Welsbach succeeded where others had
failed and separated didymium into two elements. One gave green oxides, which
he named praseodidymium (&ldquo;green twin&rdquo;), and the other gave pink oxides, which
he named neodidymium (&ldquo;new twin&rdquo;). They are now known as praseodymium and
neodymium.</p>
<p>Von Welsbach pursued the practical applications as well as the chemistry. His
incandescent gas mantle, which used rare-earth salts, mainly thorium and
cerium, to produce bright light from a gas flame, was the basis of the
lighting company Osram and made him commercially successful. It is one of the
earliest cases of rare-earth research moving directly into industrial use.</p>
<p>In 1896, Eugène-Anatole Demarçay identified europium in samarium samples and
named it after Europe. At the end of the 19th century, von Welsbach and the
French chemist Georges Urbain independently showed that ytterbium contained
two elements. The names they proposed (Urbain&rsquo;s neoytterbium and lutetium,
von Welsbach&rsquo;s aldebaranium and cassiopeium) gave rise to a dispute that
lasted for decades. In Germany, &ldquo;cassiopeium&rdquo; remained in use in place of
lutetium until the Second World War.</p>
<p>Element 61 was the last gap. It was filled in 1947, when scientists at the
Manhattan Project isolated traces of it from uranium fission products and
named it promethium, after the Titan who brought fire to humanity. Promethium
is highly radioactive and occurs in nature only in trace amounts.</p>
<p>With promethium, the family was complete. What had begun in the 1780s with
two unidentified &ldquo;earths&rdquo; had become a chemical family of 17 elements. The
history of their discovery is less a story of breakthroughs than of patient,
generational work: a small number of chemists, working in close communication
across national borders, slowly resolved a chemistry that had no good
analytical handle until the 20th century gave them one.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Critical Metals Handbook, 1st ed.; Gunn, G., Ed.; John Wiley &amp; Sons,
2013.
<a
  href="https://doi.org/10.1002/9781118755341"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1002/9781118755341</a
>
.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Höppe, H. Rare-Earth Elements: Solid State Materials: Chemical, Optical
and Magnetic Properties; De Gruyter Graduate; De Gruyter: Berlin, DE, 2024.
<a
  href="https://doi.org/10.1515/9783110680829"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1515/9783110680829</a
>
.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Voncken, J. H. L. The Rare Earth Elements; SpringerBriefs in Earth
Sciences; Springer: Cham, CH, 2016.
<a
  href="https://doi.org/10.1007/978-3-319-26809-5"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1007/978-3-319-26809-5</a
>
.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Gschneidner, K. A.; Eyring, L. <em>Handbook on the Physics and Chemistry of
Rare Earths: Two-Hundred-Year Impact of Rare Earths on Science</em>; Handbook
on the Physics and Chemistry of Rare Earths; Elsevier Science: Amsterdam,
NL, 1988; Vol. 11.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Rowlatt, J. Rare Earths: Neither Rare, nor Earths. <em>BBC News</em>. March 23,
2014.
<a
  href="https://www.bbc.com/news/magazine-26687605"
    target="_blank" rel="noopener noreferrer">https://www.bbc.com/news/magazine-26687605</a
>

(accessed 2024-08-18).&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Klinger, J. M. A Historical Geography of Rare Earth Elements: From
Discovery to the Atomic Age. <em>Extr. Ind. Soc.</em> <strong>2015</strong>, <em>2</em> (3), 572–580.
<a
  href="https://doi.org/10.1016/j.exis.2015.05.006"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1016/j.exis.2015.05.006</a
>
.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Not to be confused with Svante Arrhenius, the Swedish Nobel Prize winner
who was born in 1859.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p><em>Episodes from the History of the Rare Earth Elements</em>; Evans, C. H.,
Ed.; Springer Netherlands: Dordrecht, NL, 1996.
<a
  href="https://doi.org/10.1007/978-94-009-0287-9"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1007/978-94-009-0287-9</a
>
.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>The case for history in scientific training</title>
      <link>https://tobiacavalli.com/essays/looking-back-to-move-forward/</link>
      <pubDate>Sun, 03 Nov 2024 00:00:00 +0100</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/essays/looking-back-to-move-forward/</guid>
      <description>The ways good science has been dismissed and bad science accepted repeat, and only the historical record makes the patterns visible.</description>
      <content:encoded><![CDATA[<p>Scientists are trained to look forward, not back. The history of the field
enters graduate training as a handful of first-lecture anecdotes, and after
that it disappears from the syllabus. A working researcher who knows
something about how their field developed is better equipped than one who
does not, and that claim is not obvious.</p>
<p>Casadevall and Fang made the case for it in a 2015 editorial in <em>Infection
and Immunity</em>.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> Their argument was that historical awareness shapes
better research: without it, researchers repeat old mistakes and overlook
old discoveries. What does the history of a field give a working researcher
that the current technical literature does not?</p>
<h2 id="ideas-do-not-survive-on-technical-merit-alone">
  <a class="heading-anchor" href="#ideas-do-not-survive-on-technical-merit-alone" aria-hidden="true" tabindex="-1">#</a>
  Ideas do not survive on technical merit alone
</h2><p>The history of science is full of cases where the best available evidence
lost to social forces: institutional authority, political protection, or
inertia. Thomas Kuhn built his account of scientific progress around this
observation in <em>The Structure of Scientific Revolutions</em>.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>Ignaz Semmelweis is the standard example. In the 1840s he found that poor
hygiene among doctors was causing deadly infections in maternity wards, and
that a simple handwashing protocol cut mortality. The medical establishment
rejected the findings and destroyed his career, not because the data was
wrong but because the conclusion threatened the authority of senior
physicians.</p>
<figure><img src="/essays/looking-back-to-move-forward/galileo_san_marco_tower_hu_e682b7bd10fa433a.webp"
         srcset="/essays/looking-back-to-move-forward/galileo_san_marco_tower_hu_8dc5dcef6ad69657.webp 400w, /essays/looking-back-to-move-forward/galileo_san_marco_tower_hu_e682b7bd10fa433a.webp 800w, /essays/looking-back-to-move-forward/galileo_san_marco_tower_hu_9b59d99fc4afcaa7.webp 1024w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="340"
         alt="Plate in memory of Galileo at San Marco’s square in
Venice"
         loading="eager"
         decoding="async" fetchpriority="high" /><figcaption><span class="figure-number"></span>I took this photo on the tower of San
Marco&rsquo;s square in Venice. The plate says: Galileo Galilei with his telescope
from here on August 21, 1609, broadened man&rsquo;s horizons</figcaption>
</figure><p>Galileo&rsquo;s case is usually told as a clash between science and religion, but
politics mattered just as much. His telescope observations and his defense
of Copernican cosmology became publishable in part because the Venetian
Republic gave him political cover. Without that cover, the work might not
have spread far beyond his own notebooks.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>Stephen Toulmin called a related pattern the &ldquo;Alexandrian Trap&rdquo;:
researchers become so invested in the formal structure of their arguments
that they lose contact with what the arguments are about. The same thing
has happened many times in the history of science, and a researcher who
has seen it before is more likely to recognize it now.</p>
<p>The common thread is that scientific ideas do not survive on technical
merit alone. They have to pass through the institutions, careers, and
allegiances of the people who evaluate them, and those filters are still in
place.</p>
<h2 id="how-scientists-are-trained-to-ignore-history">
  <a class="heading-anchor" href="#how-scientists-are-trained-to-ignore-history" aria-hidden="true" tabindex="-1">#</a>
  How scientists are trained to ignore history
</h2><p>Most scientists are trained to see the history of their own field as
irrelevant to their work. Science is taught as a sequence of results, and
history gets reduced to a handful of anecdotes: Newton&rsquo;s apple, Fleming&rsquo;s
moldy petri dish, Kekulé&rsquo;s dream of the benzene ring. The context that
produced those results, and the failures that shaped the methods used to
produce them, falls out of the syllabus.</p>
<p>The contrast with law is instructive. A law student spends years reading
old cases because legal practice is explicitly shaped by precedent, and an
argument cannot be made without knowing what has been argued before. A
scientist is usually trained the opposite way, told to evaluate current
evidence on its own terms and to treat history as background color.</p>
<p>The cost is that the same lessons keep being relearned. A researcher who
stumbles into the trap Semmelweis fell into will not recognize the pattern
unless someone has taught it. The same holds for the political suppression
of correct work, the premature abandonment of productive lines, and the
slow acceptance of findings that should have been obvious at the time. None
of this shows up in the current literature. It is in the historical record.</p>
<h2 id="the-case-against-looking-back">
  <a class="heading-anchor" href="#the-case-against-looking-back" aria-hidden="true" tabindex="-1">#</a>
  The case against looking back
</h2><p>The counterargument is that science thrives by ignoring its history. Unlike
law, where precedent is binding, science progresses by overturning earlier
views, and being too attached to the history of a field encourages
deference to ideas that should be discarded. A physicist who has
internalized all of classical mechanics may have a harder time taking a
radical departure from it seriously.</p>
<p>The view is consistent with how experimental science claims to work. A
hypothesis is tested against evidence and either survives or does not, and
the historical circumstances under which it was proposed do not change the
outcome of the test. By that standard, history is at best irrelevant to the
experiment and at worst a source of bias that gives too much weight to what
was once believed.</p>
<p>This forward-only view has two problems. A hypothesis never gets evaluated
in a vacuum: the judgment of which results are worth publishing, which data
is clean enough to trust, and which directions are worth pursuing is not
mechanical. Those judgments are made by researchers whose intuitions were
built from experience, and experience is a kind of private history. The
second problem is that the failure modes of past research are not random.
They repeat, and a researcher who has studied them can see them coming.</p>
<h2 id="what-history-gives-a-researcher">
  <a class="heading-anchor" href="#what-history-gives-a-researcher" aria-hidden="true" tabindex="-1">#</a>
  What history gives a researcher
</h2><p>Casadevall and Fang&rsquo;s point is that science does not happen in a vacuum.
Every result is produced inside a social and institutional context that
shapes what questions were asked, what methods were used, and what findings
got through peer review. A researcher who knows how that context has shaped
past work is better equipped to recognize how it is shaping current work.</p>
<p>The practical effect is on judgment. A researcher familiar with how
institutional pressures shaped Galileo&rsquo;s and Semmelweis&rsquo;s work is more
likely to notice the same forces in a modern grant committee. A researcher
who has seen productive research programs abandoned prematurely is less
quick to give up on their own. A researcher who has studied how past
discoveries were actually made is less likely to believe they came from
isolated genius, which makes collaboration easier and setbacks less
discouraging.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>Historical study also corrects a bias in how credit is distributed.
Contributions from women and from scientists outside the dominant European
and American institutions become visible only when someone goes back and
reads the original literature. The same pattern holds for ethics: the rules
that get written into codes of conduct were usually learned after something
went wrong, and the case files for those events are in the historical
record, not in the current methods section.</p>
<p>Looking back and looking forward are not in competition. The history of a
field is the longest-running dataset about how research actually gets done
in it, and ignoring that dataset means ignoring the one closest to hand.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Casadevall, A.; Fang, F. C. (A)Historical Science. <em>Infect. Immun.</em>
<strong>2015</strong>, <em>83</em> (12), 4460–4464.
<a
  href="https://doi.org/10.1128/IAI.00921-15"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1128/IAI.00921-15</a
>
.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Kuhn, T. S.; Hacking, I. <em>The Structure of Scientific Revolutions</em>, 4th
ed.; University of Chicago Press: Chicago, IL, USA, 2012.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Rossi, P. <em>The Birth of Modern Science</em>; The making of Europe; Blackwell:
Oxford, UK, 2001.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>For a concrete example, see my review of Vannevar Bush&rsquo;s
<a
  href="/blog/review-pieces-of-the-action/"><em>Pieces of the Action</em></a
>
, a
first-person account of running a large-scale research program during
World War II.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>The structure and metastability of glass</title>
      <link>https://tobiacavalli.com/essays/glass-structure-stability/</link>
      <pubDate>Sun, 27 Oct 2024 00:00:00 +0200</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/essays/glass-structure-stability/</guid>
      <description>Glass is amorphous, metastable, and undergoes a gradual rather than sharp transition from liquid to solid. This post covers the structure, the thermodynamics, and the glass transition.</description>
      <content:encoded><![CDATA[<p>Glass is in windows, containers, optical fibers, lenses, and the substrates
of most electronic displays. Its atomic structure differs from that of most
solids: in crystals, atoms are arranged in a periodic lattice, but in glass
they are not.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> This disorder is the source of much of what is distinctive about
glass, including its gradual softening with temperature instead of a sharp
melting point and its isotropic mechanical response. Glass is also out of
thermodynamic equilibrium: its structure is slowly relaxing toward a more
stable arrangement, but the process is too slow to observe at ordinary
temperatures.</p>
<h2 id="crystalline-and-amorphous-solids">
  <a class="heading-anchor" href="#crystalline-and-amorphous-solids" aria-hidden="true" tabindex="-1">#</a>
  Crystalline and amorphous solids
</h2><p>Solids fall into two structural categories: crystalline and amorphous. In
crystalline solids, such as diamond or metallic copper, atoms occupy a highly
ordered, repeating lattice. In amorphous solids, including glass, the atoms
are disordered, resembling a liquid frozen in place rather than a regular
lattice.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<figure><img src="/essays/glass-structure-stability/states_of_matter_hu_fd9307fbd2ad746b.webp"
         srcset="/essays/glass-structure-stability/states_of_matter_hu_49917eeeacb6116f.webp 400w, /essays/glass-structure-stability/states_of_matter_hu_fd9307fbd2ad746b.webp 800w, /essays/glass-structure-stability/states_of_matter_hu_f2a14e5369d7c9ff.webp 908w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="423"
         alt="Three drinking glasses, each containing one of the classical states of water (ice, liquid, vapor), with diagrams of atomic arrangement below."
         loading="eager"
         decoding="async" fetchpriority="high" /><figcaption><span class="figure-number"></span>Three drinking glasses showing the three classical states of matter: ice (solid), water (liquid), and vapor (gas). The diagrams below show the atomic arrangement of each state: tightly packed in the solid, loosely arranged but still in contact in the liquid, and widely dispersed in the gas. Adapted from <a
  href="https://tinyurl.com/2svcj8dn"
    target="_blank" rel="noopener noreferrer">https://tinyurl.com/2svcj8dn</a
></figcaption>
</figure><p>The periodic arrangement gives crystalline solids two characteristic
properties. They have a sharp melting point: at the right temperature, the
entire lattice breaks down at once. They are also anisotropic, meaning their
mechanical properties depend on the direction of an applied force, because
some directions in the lattice are stronger than others.</p>
<p>Glass differs in both respects. Because there is no lattice to break, it does
not have a sharp melting point and softens gradually as temperature rises,
transitioning from rigid to fluid over a range. The disordered atomic
arrangement has no preferred direction, so glass is isotropic: its mechanical
properties are the same along every axis.</p>
<p>The contrast is sharpest in silica (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mrow><mi mathvariant="normal">S</mi><mi mathvariant="normal">i</mi><mi mathvariant="normal">O</mi></mrow><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\mathrm{SiO}_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord"><span class="mord mathrm">SiO</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>). In its crystalline
form, silica is quartz, with a sharp melting point and anisotropic mechanical
properties. In its amorphous form, the same chemical composition produces a
glass with no melting point and isotropic properties.</p>
<figure><img src="/essays/glass-structure-stability/silica_structure_hu_62ede1dc0583664b.webp"
         srcset="/essays/glass-structure-stability/silica_structure_hu_f773cf6af0a67541.webp 400w, /essays/glass-structure-stability/silica_structure_hu_62ede1dc0583664b.webp 800w, /essays/glass-structure-stability/silica_structure_hu_37e2310baadb2af9.webp 908w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="324"
         alt="Side-by-side schematic of the atomic arrangement of amorphous silica (left, disordered) and crystalline silica or quartz (right, ordered)."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>Amorphous silica (left), the basis of most oxide glasses, contrasted with crystalline silica or quartz (right). The composition is identical, and only the atomic arrangement differs.</figcaption>
</figure><p>Glass is not limited to silica. Many other substances, including metals and
polymers, can form amorphous structures when cooled rapidly enough to suppress
crystallization. What they all share is the absence of long-range order in the
atomic arrangement.</p>
<h2 id="metastability">
  <a class="heading-anchor" href="#metastability" aria-hidden="true" tabindex="-1">#</a>
  Metastability
</h2><p>Glass is <strong>metastable</strong>: it sits in a local energy minimum that is not the
global minimum, but the energy barrier separating the two is too large to
cross under ordinary conditions. For almost any glass-forming substance, the
global minimum is a crystalline arrangement.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<p>Crystallization requires atoms to settle into the periodic positions of a
lattice, and that takes time. When a melt is cooled fast enough, there is not
enough time for them to do so, and the resulting solid carries the disordered
arrangement it had in the liquid state. The faster the cooling, the more
frozen-in disorder.</p>
<p>Compared to a crystal of the same composition, a glass has a larger
<strong>molar volume</strong> (its atoms are not packed as tightly), higher <strong>entropy</strong>
(the disordered arrangement has more accessible microstates), and higher
<strong>enthalpy</strong> and <strong>Gibbs free energy</strong>. All of these reflect the same fact:
glass is in a higher-energy state, but the activation energy required to
reach the lower-energy crystalline state is too large to cross at ordinary
temperatures.</p>
<h2 id="the-glass-transition">
  <a class="heading-anchor" href="#the-glass-transition" aria-hidden="true" tabindex="-1">#</a>
  The glass transition
</h2><p>The transformation from a glass-forming liquid into a glass is called the
<strong>glass transition</strong>, and the process of carrying it out (cooling a liquid
fast enough to bypass crystallization) is called <strong>vitrification</strong>. Unlike the
melting transition of a crystal, which happens at a single sharp temperature,
the glass transition is gradual: as a liquid is cooled, its viscosity rises,
and over some temperature range it becomes so viscous that, on the timescales
of observation, it stops flowing. The temperature at which this happens is
called the <strong>glass transition temperature</strong>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>.<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span> is not a thermodynamic constant of the material but a quantity that
depends on the cooling rate. Faster cooling traps the atoms at a higher
temperature, before they have time to relax into lower-energy arrangements,
and produces a higher <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>. Slower cooling gives them more time to relax
and produces a lower <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>. The same substance can have different glass
transition temperatures depending on its thermal history.</p>
<figure><img src="/essays/glass-structure-stability/glass_phase_transition_hu_6f137481fbe0f278.webp"
         srcset="/essays/glass-structure-stability/glass_phase_transition_hu_f5de481d110ca51b.webp 400w, /essays/glass-structure-stability/glass_phase_transition_hu_6f137481fbe0f278.webp 800w, /essays/glass-structure-stability/glass_phase_transition_hu_177f64dea3378793.webp 1200w, /essays/glass-structure-stability/glass_phase_transition_hu_55255351c7da21d4.webp 1600w, /essays/glass-structure-stability/glass_phase_transition_hu_d85ba4ceaae0cf2a.webp 2100w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="494"
         alt="Phase diagram showing the four states of a glass-forming substance against temperature: liquid, supercooled liquid, glass, and crystal, with the melting temperature and glass transition temperature marked."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>The four states of a glass-forming substance plotted against temperature: liquid, supercooled liquid, glass, and crystal. The melting temperature <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>m</mi></msub></mrow><annotation encoding="application/x-tex">T_m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is the boundary between solid crystal and liquid, and the glass transition temperature <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span> is the boundary between supercooled liquid and glass.</figcaption>
</figure><p>This time-dependence is the central distinction between glass and crystalline
solids. Crystals melt at a fixed temperature (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>m</mi></msub></mrow><annotation encoding="application/x-tex">T_m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>), and the transition is
sharp. Glasses do not melt at all in the strict sense. They pass continuously
between rigid solid and viscous liquid, and the location of the transition
depends on time as much as on temperature.</p>
<h2 id="supercooled-liquids">
  <a class="heading-anchor" href="#supercooled-liquids" aria-hidden="true" tabindex="-1">#</a>
  Supercooled liquids
</h2><p>A liquid cooled below its freezing point without crystallizing is a
<strong>supercooled liquid</strong>. As it cools further, its atomic structure continues to
rearrange through a process called <strong>structural relaxation</strong>, which slows as
the temperature drops. The characteristic timescale for this rearrangement is
the <strong>relaxation time</strong>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>τ</mi><mi>s</mi></msub></mrow><annotation encoding="application/x-tex">\tau_s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1132em;">τ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1132em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, which increases sharply as the liquid
approaches the glass transition.</p>
<p>When the cooling rate exceeds the structural relaxation rate, the atomic
arrangement is frozen in: continued cooling produces no further structural
change, and the supercooled liquid becomes a glass. The temperature at which
this happens is called the <strong>fictive temperature</strong>, and for many materials it
coincides with <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>.</p>
<h2 id="conclusion">
  <a class="heading-anchor" href="#conclusion" aria-hidden="true" tabindex="-1">#</a>
  Conclusion
</h2><p>Glass is structurally disordered, thermodynamically out of equilibrium, and
stable on human timescales. These features, together with the glass transition
that connects the liquid and solid states, are common to all glasses, whether
oxide, metallic, or polymeric. What varies between systems is the chemistry
that sets the relaxation timescales and the value of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>T</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">T_g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Mysen, B.; Richet, P. <em>Silicate Glasses and Melts</em>, 2nd ed.; Elsevier:
Amsterdam, NL, 2019.
<a
  href="https://doi.org/10.1016/C2018-0-00864-6"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1016/C2018-0-00864-6</a
>
.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Vogel, W. <em>Glass Chemistry</em>; Springer: Berlin, DE, 1994.
<a
  href="https://doi.org/10.1007/978-3-642-78723-2"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1007/978-3-642-78723-2</a
>
.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Schmelzer, J. W. P.; Gutzow, I. S. <em>Glasses and the Glass Transition</em>;
John Wiley &amp; Sons: Weinheim, DE, 2011.
<a
  href="https://doi.org/10.1002/9783527636532"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1002/9783527636532</a
>
.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Zanotto, E. D.; Mauro, J. C. The Glassy State of Matter: Its Definition
and Ultimate Fate. <em>J. Non-Cryst. Solids</em> <strong>2017</strong>, <em>471</em>, 490&mdash;495.
<a
  href="https://doi.org/10.1016/j.jnoncrysol.2017.05.019"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1016/j.jnoncrysol.2017.05.019</a
>
.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Montazerian, M.; Zanotto, E. D. The Glassy State. In <em>Encyclopedia of
Materials: Technical Ceramics and Glasses</em>; Elsevier, 2021; Vol. 2, pp
448&mdash;461.
<a
  href="https://doi.org/10.1016/B978-0-12-803581-8.11728-X"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1016/B978-0-12-803581-8.11728-X</a
>
.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Vannevar Bush on managing large-scale R&amp;D</title>
      <link>https://tobiacavalli.com/essays/review-pieces-of-the-action/</link>
      <pubDate>Tue, 22 Oct 2024 00:00:00 +0200</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/essays/review-pieces-of-the-action/</guid>
      <description>Vannevar Bush ran the Office of Scientific Research and Development during World War II. His memoir of that work is a management manual for anyone running large-scale research programs.</description>
      <content:encoded><![CDATA[<img src="/essays/review-pieces-of-the-action/book_cover_bush_pieces_of_the_action_hu_8aedfb34b0a9ccee.webp"
         srcset="/essays/review-pieces-of-the-action/book_cover_bush_pieces_of_the_action_hu_e4de3be40d674069.webp 400w, /essays/review-pieces-of-the-action/book_cover_bush_pieces_of_the_action_hu_8aedfb34b0a9ccee.webp 800w, /essays/review-pieces-of-the-action/book_cover_bush_pieces_of_the_action_hu_ed36ca692358c30a.webp 1000w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="1200"
         alt="Pieces of the action book cover"
         loading="eager"
         decoding="async" fetchpriority="high" /><h2 id="bush-and-the-osrd">
  <a class="heading-anchor" href="#bush-and-the-osrd" aria-hidden="true" tabindex="-1">#</a>
  Bush and the OSRD
</h2><p>Vannevar Bush ran the Office of Scientific Research and Development (OSRD)
during World War II. The OSRD coordinated the American wartime scientific
effort between government laboratories, universities, and private industry,
operating at a scale and under time pressure that had no peacetime
precedent. <em>Pieces of the Action</em> is Bush&rsquo;s memoir of that work, written as
a management manual rather than as a history. It is opinionated and
concerned mainly with the practical question of how to run technical
people at scale.</p>
<h2 id="why-rd-is-hard-to-manage">
  <a class="heading-anchor" href="#why-rd-is-hard-to-manage" aria-hidden="true" tabindex="-1">#</a>
  Why R&amp;D is hard to manage
</h2><p>R&amp;D is hard to manage because the goal is not fixed at the start.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> A
conventional project can be broken into steps and scheduled. A research
project usually cannot. New results reshape the direction, unexpected
failures close off promising routes, and the endpoint is often different
from the one originally intended.</p>
<p>That same uncertainty is what makes R&amp;D valuable. The technologies that
turn out to matter come from work that could not have been planned in
advance, which is why R&amp;D is worth doing. The management problem is how
to allow enough slack for the unexpected to happen without losing all
direction.</p>
<p>The scale of modern R&amp;D investment is easy to illustrate. Amazon, Alphabet,
Meta, Apple, and Microsoft spent over $200 billion on research and
development in 2022 alone. But spending is not the bottleneck. What
separates a productive research program from an unproductive one is
whether the organization has a working method for deciding which problems
to pursue and which to drop.</p>
<p>That method lives in the judgment of experienced researchers and managers
rather than in any formal process, which makes it hard to build and harder
to transfer between organizations. Companies good at R&amp;D train their
people to recognize problems worth working on, to approach them
methodically, and to iterate toward solutions. Companies bad at R&amp;D treat
research as a budget line and assume that outputs will follow.</p>
<h2 id="context-and-case-studies">
  <a class="heading-anchor" href="#context-and-case-studies" aria-hidden="true" tabindex="-1">#</a>
  Context and case studies
</h2><p>R&amp;D management is also heavily context-dependent. The traditional
project-management constraints of time, cost, and scope (the &ldquo;iron
triangle&rdquo;) apply to any research project but are not sufficient.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> A
project that succeeds on all three can still fail on factors the iron
triangle does not measure: team culture, the politics of the stakeholders,
the development methodology, and how the work transitions from a
laboratory prototype into production.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>What works for one project often does not work for another, because the
context differs in ways that cannot be captured by a generic methodology.
A manager who wants to apply the lessons of a past success has to identify
which parts of the original success were context-dependent and which were
not. That separation is itself the skill being applied.</p>
<p>Fields that deal with context-dependent problems, such as law, medicine,
and business management, have developed the case study as a way of
carrying forward lessons that do not generalize cleanly into rules. The
method originated in legal education under Christopher Columbus
Langdell.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> A case study preserves the context that a general
principle would strip out, and lets the reader decide which aspects of
the situation are load-bearing and which are incidental.</p>
<p><em>Pieces of the Action</em> is, in this sense, a case study of the largest
coordinated R&amp;D effort in modern history. Bush is not trying to prove a
general theory of how research should be managed. He is reporting what he
did, why he did it, and what he thought worked. The reader who wants
general principles has to extract them, and that is how the book is meant
to be read.</p>
<h2 id="read-it">
  <a class="heading-anchor" href="#read-it" aria-hidden="true" tabindex="-1">#</a>
  Read it
</h2><p>The wartime R&amp;D effort produced radar, the proximity fuse, guided
missiles, jet engines, and the scaled production of penicillin. Bush ran
the American side of that effort as head of the OSRD. He was not the
inventor of any of these technologies, but he was the administrator who
decided what to fund, who should work on what, how the work should be
divided between academic and industrial laboratories, and when to push a
project from research into production.</p>
<p>The book covers both sides of that job. Bush was an engineer himself,
which gives the technical discussion credibility, but the technical
material is not what makes the book unusual. The unusual part is the
managerial material: specific, opinionated advice on how to run
committees, how to work around the politics of wartime bureaucracy, how
to allocate research freedom without losing focus, and how to remove
people whose arrogance or rigidity slows everyone else down. An entire
chapter is dedicated to that last problem, and Bush calls the people in
question <em>tyros</em>.</p>
<p>Read it. The technical details are dated, but the management problems are
not, and few people have Bush&rsquo;s combination of first-hand experience with
large-scale coordinated research and willingness to be specific about
what actually worked.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Wingate, L. M. <em>Project Management for Research and Development: Guiding
Innovation for Positive R&amp;D Outcomes</em>; Levin, G., Series Ed.; Best
Practices and Advances in Program Management; CRC Press: Boca Raton, FL,
USA, 2015.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><em>The Standard for Project Management and a Guide to the Project
Management Body of Knowledge (PMBOK Guide)</em>, 7th ed.; Project Management
Institute, Inc.: Newtown Square, PA, USA, 2017.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Some would say it is a <em>wicked problem</em>. For more on this, see: Senge, P.
M. <em>The Fifth Discipline: The Art and Practice of the Learning
Organization</em>, 2nd ed.; Doubleday/Currency: New York, NY, USA, 2006.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><em>The Case Study Teaching Method</em>.
<a
  href="https://casestudies.law.harvard.edu/the-case-study-teaching-method/"
    target="_blank" rel="noopener noreferrer">https://casestudies.law.harvard.edu/the-case-study-teaching-method/</a
>

(accessed 2024-08-26).&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Crowe, S.; Cresswell, K.; Robertson, A.; Huby, G.; Avery, A.; Sheikh, A.
The Case Study Approach. <em>BMC Med. Res. Methodol.</em> <strong>2011</strong>, <em>11</em> (1), 100.
<a
  href="https://doi.org/10.1186/1471-2288-11-100"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1186/1471-2288-11-100</a
>
.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Installing ORCA on macOS Arm64</title>
      <link>https://tobiacavalli.com/guides/installing-orca-macos/</link>
      <pubDate>Sun, 22 Sep 2024 00:00:00 +0200</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/guides/installing-orca-macos/</guid>
      <description>Installing and configuring ORCA 6.0.0 on Apple Silicon Macs, including Open MPI compilation for parallel calculations.</description>
      <content:encoded><![CDATA[<img src="/guides/installing-orca-macos/orca_logo.svg" alt="Orca logo" width="800" height="522" loading="eager" decoding="async" fetchpriority="high" /><p><a
  href="https://www.faccts.de/orca/"
    target="_blank" rel="noopener noreferrer">ORCA</a
>
 is a quantum chemistry program for
molecular electronic structure calculations, developed and maintained
by Frank Neese&rsquo;s research group at the Max-Planck-Institut für
Kohlenforschung in Mülheim an der Ruhr, Germany. It supports density
functional theory (DFT), coupled-cluster theory, semi-empirical
methods, and more.</p>
<p>Version <code>6.0.0</code>, released in August 2024, is a major redesign (see
the <a
  href="https://www.faccts.de/docs/orca/6.0/manual/contents/foreword.html"
    target="_blank" rel="noopener noreferrer">foreword to its
release</a
>
).
This guide covers installing it on macOS with Apple Silicon (M1, M2,
etc.), including Open MPI setup for parallel calculations.</p>
<h2 id="installation">
  <a class="heading-anchor" href="#installation" aria-hidden="true" tabindex="-1">#</a>
  Installation
</h2><h3 id="getting-the-files">
  <a class="heading-anchor" href="#getting-the-files" aria-hidden="true" tabindex="-1">#</a>
  Getting the files
</h3><p>To get started, download the ORCA package from the <a
  href="https://orcaforum.kofo.mpg.de/app.php/dlext/"
    target="_blank" rel="noopener noreferrer">official ORCA download
page</a
>
. Note that you&rsquo;ll need a
registered account to access the download&mdash;registration is free if you don&rsquo;t
have an account yet.</p>
<p>For macOS on Arm64, the download page lists two options (both
containing pre-compiled binaries linked to Open MPI <code>4.1.1</code>):</p>
<ol>
<li><strong>ORCA 6.0.0, MacOS X, Arm64, Installer Version:</strong> Extracts,
installs, and adds ORCA to your <code>PATH</code> automatically.</li>
<li><strong>ORCA 6.0.0, MacOS X, Arm64, .tar.bz2 Archive:</strong> Manual
extraction and <code>PATH</code> setup, but more control over the installation
location.</li>
</ol>
<p>This guide uses the <strong>Installer Version</strong>, which downloads as
<code>orca_6_0_0_macosx_arm64_openmpi411.run</code>.</p>
<h3 id="setting-file-permissions">
  <a class="heading-anchor" href="#setting-file-permissions" aria-hidden="true" tabindex="-1">#</a>
  Setting file permissions
</h3><p>Before running the installer, make it executable:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> ~/Downloads
</span></span><span class="line"><span class="cl">chmod +x orca_6_0_0_macosx_arm64_openmpi411.run</span></span></code></pre></div><h3 id="running-the-installer">
  <a class="heading-anchor" href="#running-the-installer" aria-hidden="true" tabindex="-1">#</a>
  Running the installer
</h3><p>Run the installer from the same directory:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ ./orca_6_0_0_macosx_arm64_openmpi411.run
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Creating directory orca_6_0_0
</span></span><span class="line"><span class="cl">Verifying archive integrity...  100%   MD5 checksums are OK. All good.
</span></span><span class="line"><span class="cl">Uncompressing ORCA 6.0.0 Installer ...  100%</span></span></code></pre></div><p>By default, this operation installs the ORCA binaries in the directory
<code>/Users/&lt;username&gt;/Library/Orca/</code>, where <code>&lt;username&gt;</code> is your system&rsquo;s user.</p>
<h3 id="setting-the-path">
  <a class="heading-anchor" href="#setting-the-path" aria-hidden="true" tabindex="-1">#</a>
  Setting the <code>PATH</code>
</h3><p>The installer should automatically add ORCA to your system&rsquo;s <code>PATH</code>.
Verify by running:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ orca
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This program requires the name of a parameterfile as argument
</span></span><span class="line"><span class="cl">For example ORCA TEST.INP</span></span></code></pre></div><p>If you see this output, ORCA is installed. You can also confirm by
checking your <code>.zshrc</code> (macOS ships with zsh by default) for a line
like:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-zsh" data-lang="zsh"><span class="line"><span class="cl"><span class="c1"># ORCA 6.0.0 section</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span>/Users/&lt;username&gt;/Library/orca_6_0_0:<span class="nv">$PATH</span></span></span></code></pre></div><p>If this line is missing, add it manually, pointing to the correct
installation directory. Save the file and restart your terminal.</p>
<h3 id="parallelization-with-open-mpi">
  <a class="heading-anchor" href="#parallelization-with-open-mpi" aria-hidden="true" tabindex="-1">#</a>
  Parallelization with Open MPI
</h3><p>To run calculations in parallel, ORCA needs <strong>Open MPI</strong>.</p>
<div class="callout callout-warning">
      <p class="callout-title">Warning</p>
      <p>The ORCA <code>6.0.0</code> binaries are linked against Open MPI <code>4.1.1</code>. This
guide installs <code>4.1.6</code> instead, because <code>4.1.1</code> failed to compile on
Apple Silicon in my testing. Version <code>4.1.6</code> works without issues.</p>
    </div><p>Download Open MPI <code>4.1.6</code> from the <a
  href="https://www.open-mpi.org/software/ompi/v4.1/"
    target="_blank" rel="noopener noreferrer">official Open MPI
page</a
>
. The file is
<code>openmpi-4.1.6.tar.gz</code>.</p>
<p>Before compiling, install the Fortran compiler via
<a
  href="https://brew.sh/"
    target="_blank" rel="noopener noreferrer">Homebrew</a
>
:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">brew install gcc</span></span></code></pre></div><p>Unpack and prepare Open MPI for compilation. This example installs it
in a dedicated folder in the home directory:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Create a directory for Open MPI</span>
</span></span><span class="line"><span class="cl">$ mkdir <span class="nv">$HOME</span>/openmpi
</span></span><span class="line"><span class="cl">$ <span class="nb">cd</span> <span class="nv">$HOME</span>/openmpi
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Move the downloaded file and extract it</span>
</span></span><span class="line"><span class="cl">$ cp ~/Downloads/openmpi-4.1.6.tar.gz .
</span></span><span class="line"><span class="cl">$ tar -xzvf openmpi-4.1.6.tar.gz
</span></span><span class="line"><span class="cl">$ <span class="nb">cd</span> openmpi-4.1.6</span></span></code></pre></div><p>Compile Open MPI with Fortran support and the flags needed for ORCA:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">./configure --prefix<span class="o">=</span><span class="nv">$HOME</span>/openmpi --without-verbs --enable-mpi-fortran --disable-builtin-atomics
</span></span><span class="line"><span class="cl">make all
</span></span><span class="line"><span class="cl">make install</span></span></code></pre></div><div class="callout callout-note">
      <p class="callout-title">Update 2025-07-30</p>
      <p>A reader has reported that compiling <code>openmpi</code> on newer
versions of Xcode-devtools (Ventura 13.5 to Sonoma 14.x) requires the
additional flag <code>LDFLAGS=&quot;-ld_classic&quot;</code>. In this case, the full configuration
command should be:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">./configure --prefix<span class="o">=</span><span class="nv">$HOME</span>/openmpi --without-verbs --enable-mpi-fortran --disable-builtin-atomicsC <span class="nv">LDFLAGS</span><span class="o">=</span><span class="s2">&#34;-ld_classic&#34;</span></span></span></code></pre></div><p>See this <a
  href="https://github.com/open-mpi/ompi/issues/11935"
    target="_blank" rel="noopener noreferrer">GitHub issue</a
>
 for
details.</p>
    </div><p>Compilation takes time. To speed it up, use multiple cores with the
<code>-jN</code> flag:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">make -j4 all
</span></span><span class="line"><span class="cl">make -j4 install</span></span></code></pre></div><p>After compilation, create a symbolic link to make Open MPI accessible
system-wide:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo ln -s <span class="nv">$HOME</span>/openmpi/lib/libmpi.40.dylib /usr/local/lib/libmpi.40.dylib</span></span></code></pre></div><p>Update the <code>PATH</code> and <code>LD_LIBRARY_PATH</code> in your <code>.zshrc</code> (or
<code>.bash_profile</code> if using bash):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-zsh" data-lang="zsh"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="nv">$HOME</span>/openmpi/bin:<span class="nv">$PATH</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span><span class="nv">$HOME</span>/openmpi/lib:<span class="nv">$LD_LIBRARY_PATH</span></span></span></code></pre></div><p>Run <code>source ~/.zshrc</code> (or restart your terminal), then verify:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ mpirun --version
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">mpirun <span class="o">(</span>Open MPI<span class="o">)</span> 4.1.6
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Report bugs to http://www.open-mpi.org/community/help/</span></span></code></pre></div><p>If you see this output, Open MPI is ready.</p>
<h2 id="testing">
  <a class="heading-anchor" href="#testing" aria-hidden="true" tabindex="-1">#</a>
  Testing
</h2><p>Verify the setup by running a simple calculation. Create a folder for
the test files:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Navigate to the desktop</span>
</span></span><span class="line"><span class="cl">$ <span class="nb">cd</span> ~/Desktop
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create a new folder for the test</span>
</span></span><span class="line"><span class="cl">$ mkdir orca_test
</span></span><span class="line"><span class="cl">$ <span class="nb">cd</span> orca_test
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create an input file for the calculation</span>
</span></span><span class="line"><span class="cl">$ touch water.inp</span></span></code></pre></div><p>Add a basic Hartree-Fock (HF) calculation on a water molecule using the
Def2-SVP basis set (from the <a
  href="https://www.faccts.de/docs/orca/6.0/tutorials/first_steps/first_calc.html"
    target="_blank" rel="noopener noreferrer">official ORCA
tutorial</a
>
):</p>





<pre tabindex="0"><code class="language-orca" data-lang="orca">!HF DEF2-SVP

* xyz 0 1
O   0.0000   0.0000   0.0626
H  -0.7920   0.0000  -0.4973
H   0.7920   0.0000  -0.4973
*</code></pre><p>Save the file and run ORCA in serial mode:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ orca water.inp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                                 *****************
</span></span><span class="line"><span class="cl">                                 * O   R   C   A *
</span></span><span class="line"><span class="cl">                                 *****************
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">--- truncated output ---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Timings <span class="k">for</span> individual modules:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Sum of individual <span class="nb">times</span>          ...        0.245 sec <span class="o">(=</span>   0.004 min<span class="o">)</span>
</span></span><span class="line"><span class="cl">Startup calculation              ...        0.081 sec <span class="o">(=</span>   0.001 min<span class="o">)</span>  33.0 %
</span></span><span class="line"><span class="cl">SCF iterations                   ...        0.114 sec <span class="o">(=</span>   0.002 min<span class="o">)</span>  46.5 %
</span></span><span class="line"><span class="cl">Property calculations            ...        0.050 sec <span class="o">(=</span>   0.001 min<span class="o">)</span>  20.6 %
</span></span><span class="line"><span class="cl">                             ****ORCA TERMINATED NORMALLY****
</span></span><span class="line"><span class="cl">TOTAL RUN TIME: <span class="m">0</span> days <span class="m">0</span> hours <span class="m">0</span> minutes <span class="m">0</span> seconds <span class="m">302</span> msec</span></span></code></pre></div><p>If the output ends with <code>ORCA TERMINATED NORMALLY</code>, the serial setup
works. Next, test parallel execution by adding a <code>%PAL</code> block that
specifies the number of processes. Update <code>water.inp</code>:</p>





<pre tabindex="0"><code class="language-orca" data-lang="orca">!HF DEF2-SVP

%PAL NPROCS 4 END

* xyz 0 1
O   0.0000   0.0000   0.0626
H  -0.7920   0.0000  -0.4973
H   0.7920   0.0000  -0.4973
*</code></pre><p>For parallel runs, use the full path to the ORCA executable (replace
<code>&lt;username&gt;</code> with your macOS username):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ /Users/&lt;username&gt;/Library/orca_6_0_0/orca water.inp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">           ************************************************************
</span></span><span class="line"><span class="cl">           *        Program running with <span class="m">4</span> parallel MPI-processes     *
</span></span><span class="line"><span class="cl">           *              working on a common directory               *
</span></span><span class="line"><span class="cl">           ************************************************************
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">--- truncated output ---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Timings <span class="k">for</span> individual modules:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Sum of individual <span class="nb">times</span>          ...       17.403 sec <span class="o">(=</span>   0.290 min<span class="o">)</span>
</span></span><span class="line"><span class="cl">Startup calculation              ...       16.408 sec <span class="o">(=</span>   0.273 min<span class="o">)</span>  94.3 %
</span></span><span class="line"><span class="cl">SCF iterations                   ...        0.721 sec <span class="o">(=</span>   0.012 min<span class="o">)</span>   4.1 %
</span></span><span class="line"><span class="cl">Property calculations            ...        0.275 sec <span class="o">(=</span>   0.005 min<span class="o">)</span>   1.6 %
</span></span><span class="line"><span class="cl">                             ****ORCA TERMINATED NORMALLY****
</span></span><span class="line"><span class="cl">TOTAL RUN TIME: <span class="m">0</span> days <span class="m">0</span> hours <span class="m">0</span> minutes <span class="m">17</span> seconds <span class="m">708</span> msec</span></span></code></pre></div><p>If the output confirms 4 parallel MPI processes and terminates
normally, both ORCA and Open MPI are working.</p>
<div class="callout callout-note">
      <p class="callout-title">Note</p>
      <p>The parallel run took 17.7 seconds versus 0.3 seconds in
serial. MPI startup and inter-process communication add overhead that
outweighs the benefit for small calculations. The speedup becomes
visible on larger systems.</p>
    </div>]]></content:encoded>
    </item>
    <item>
      <title>Calculating the CIE color of Chlorophyll A and B using Python</title>
      <link>https://tobiacavalli.com/guides/cie-colors-python/</link>
      <pubDate>Sat, 14 Sep 2024 00:00:00 +0200</pubDate><author>tobiablogs@proton.me (Tobia Cavalli)</author>
      <guid>https://tobiacavalli.com/guides/cie-colors-python/</guid>
      <description>A UV-Vis spectrum tells you what light a molecule absorbs, but not what color it looks. This guide uses the CIE 1931 colorimetry system and Python to calculate the perceived color of Chlorophyll A and B from their absorption spectra.</description>
      <content:encoded><![CDATA[<p>A UV-Vis spectrum records how much light a molecule absorbs at each wavelength,
but it says nothing about what the molecule actually looks like. Chlorophyll A
has absorption peaks near 430 nm and 670 nm — but what color does a solution of
it appear to the eye?</p>
<p>Answering that question requires crossing from physics into perception. Color is
a sensation produced by the brain&rsquo;s processing of signals from the retina, not a
property of light itself. The same spectral power distribution can look
different under different illuminants; different distributions can look
identical. This is metamerism: two lights with different spectral compositions
produce the same cone responses and appear identical to a normal observer under
standard conditions.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p><strong>Psychophysics</strong> quantifies this relationship between physical stimuli and
perceived sensations. Guy Brindley formalized the distinction in 1970 by
categorizing perceptual observations into two types:</p>
<ol>
<li><strong>Class A observations:</strong> Two physically different stimuli are perceived as
identical &mdash; the observer cannot distinguish them.</li>
<li><strong>Class B observations:</strong> All other cases where stimuli are distinguishable.</li>
</ol>
<p>Color matching is the canonical Class A case. It is also the experimental
foundation of the CIE colorimetry system.</p>
<h2 id="the-cie-colorimetry-system">
  <a class="heading-anchor" href="#the-cie-colorimetry-system" aria-hidden="true" tabindex="-1">#</a>
  The CIE colorimetry system
</h2><p>The <strong>CIE colorimetry system</strong>, developed by the Commission Internationale
d&rsquo;Éclairage, translates spectral power distributions into standardized color
coordinates using <strong>color matching</strong> experiments.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>In these experiments, observers view a split field: one half shows a test color,
the other a mixture of three primary lights. The observer adjusts the primaries
until both halves match. Repeating this across the visible spectrum and
averaging over many observers produces a statistical model of human color
vision.</p>
<figure><img src="/guides/cie-colors-python/cie_color_matching_hu_227b6ea043027ab9.webp"
         srcset="/guides/cie-colors-python/cie_color_matching_hu_9c3de5e5934b688f.webp 400w, /guides/cie-colors-python/cie_color_matching_hu_227b6ea043027ab9.webp 800w, /guides/cie-colors-python/cie_color_matching_hu_4efd9fdc9abafa2c.webp 1200w, /guides/cie-colors-python/cie_color_matching_hu_bd5914bd36b23848.webp 1372w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="365"
         alt="CIE color matching experiment"
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>CIE color matching
experiment. Adapted from literature.</figcaption>
</figure><p>The CIE 1931 model uses additive color mixing based on <strong>Color Matching
Functions (CMFs)</strong>, denoted <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>x</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5678em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5678em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal">x</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2222em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>y</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{y}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7622em;vertical-align:-0.1944em;"></span><span class="mord accent"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.5678em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.1944em;"><span class="mord">ˉ</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.1944em;"><span></span></span></span></span></span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>z</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{z}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5678em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5678em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.1944em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span>.
CMFs are not the spectral sensitivities of the cone cells directly, but linear
transformations of them, derived from standardized color matching experiments
involving foveal vision, specific field sizes, dark surroundings, and averaged
observations from multiple individuals.</p>
<p>By convolution of the sample spectrum <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">M(\lambda)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span></span></span></span> with the CMFs, we
calculate <strong>tristimulus values</strong> <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Y</mi></mrow><annotation encoding="application/x-tex">Y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span></span></span></span>, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Z</mi></mrow><annotation encoding="application/x-tex">Z</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span></span></span></span>. These values
represent the amounts of the three primary colors (red, green, and blue)
required to match the given color.</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><mi>X</mi><mo>=</mo><msubsup><mo>∫</mo><mn>380</mn><mn>780</mn></msubsup><mi>M</mi><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo><mover accent="true"><mi>x</mi><mo>ˉ</mo></mover><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo><mtext> </mtext><mi>d</mi><mi>λ</mi></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(1)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
X = \int_{380}^{780} M(\lambda) \bar{x}(\lambda)  \, d\lambda \tag{1}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.476em;vertical-align:-0.9119em;"></span><span class="mop"><span class="mop op-symbol large-op" style="margin-right:0.44445em;position:relative;top:-0.0011em;">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.564em;"><span style="top:-1.7881em;margin-left:-0.4445em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">380</span></span></span></span><span style="top:-3.8129em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">780</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9119em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5678em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal">x</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2222em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">λ</span></span><span class="tag"><span class="strut" style="height:2.476em;vertical-align:-0.9119em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">1</span></span><span class="mord">)</span></span></span></span></span></span><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><mi>Y</mi><mo>=</mo><msubsup><mo>∫</mo><mn>380</mn><mn>780</mn></msubsup><mi>M</mi><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo><mover accent="true"><mi>y</mi><mo>ˉ</mo></mover><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo><mtext> </mtext><mi>d</mi><mi>λ</mi></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(2)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
Y = \int_{380}^{780} M(\lambda) \bar{y}(\lambda)  \, d\lambda \tag{2}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.476em;vertical-align:-0.9119em;"></span><span class="mop"><span class="mop op-symbol large-op" style="margin-right:0.44445em;position:relative;top:-0.0011em;">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.564em;"><span style="top:-1.7881em;margin-left:-0.4445em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">380</span></span></span></span><span style="top:-3.8129em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">780</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9119em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span><span class="mord accent"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.5678em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.1944em;"><span class="mord">ˉ</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.1944em;"><span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">λ</span></span><span class="tag"><span class="strut" style="height:2.476em;vertical-align:-0.9119em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">2</span></span><span class="mord">)</span></span></span></span></span></span><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><mi>Z</mi><mo>=</mo><msubsup><mo>∫</mo><mn>380</mn><mn>780</mn></msubsup><mi>M</mi><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo><mover accent="true"><mi>z</mi><mo>ˉ</mo></mover><mo stretchy="false">(</mo><mi>λ</mi><mo stretchy="false">)</mo><mtext> </mtext><mi>d</mi><mi>λ</mi></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(3)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
Z = \int_{380}^{780} M(\lambda) \bar{z}(\lambda)  \, d\lambda \tag{3}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.476em;vertical-align:-0.9119em;"></span><span class="mop"><span class="mop op-symbol large-op" style="margin-right:0.44445em;position:relative;top:-0.0011em;">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.564em;"><span style="top:-1.7881em;margin-left:-0.4445em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">380</span></span></span></span><span style="top:-3.8129em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">780</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9119em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5678em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.1944em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">λ</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">λ</span></span><span class="tag"><span class="strut" style="height:2.476em;vertical-align:-0.9119em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">3</span></span><span class="mord">)</span></span></span></span></span></span><p>The tristimulus values define a point in a three-dimensional color space. For
visualization, this space is reduced to two dimensions using the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> and
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span> chromaticity coordinates:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><mi>x</mi><mo>=</mo><mfrac><mi>X</mi><mrow><mi>X</mi><mo>+</mo><mi>Y</mi><mo>+</mo><mi>Z</mi></mrow></mfrac></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(4)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
x = \frac{X}{X + Y + Z} \tag{4}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.1297em;vertical-align:-0.7693em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3603em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span><span class="tag"><span class="strut" style="height:2.1297em;vertical-align:-0.7693em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">4</span></span><span class="mord">)</span></span></span></span></span></span><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><mi>y</mi><mo>=</mo><mfrac><mi>Y</mi><mrow><mi>X</mi><mo>+</mo><mi>Y</mi><mo>+</mo><mi>Z</mi></mrow></mfrac></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(5)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
y = \frac{Y}{X + Y + Z} \tag{5}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.1297em;vertical-align:-0.7693em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3603em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span><span class="tag"><span class="strut" style="height:2.1297em;vertical-align:-0.7693em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">5</span></span><span class="mord">)</span></span></span></span></span></span><p>The <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span> coordinates specify a chromaticity (hue and saturation)
independently of luminance. This is what makes the diagram useful for comparing
colors across different brightness levels.</p>
<h2 id="python-code">
  <a class="heading-anchor" href="#python-code" aria-hidden="true" tabindex="-1">#</a>
  Python code
</h2><h3 id="dependencies">
  <a class="heading-anchor" href="#dependencies" aria-hidden="true" tabindex="-1">#</a>
  Dependencies
</h3><p>The heavy lifting is done by <a
  href="https://colour.readthedocs.io"
    target="_blank" rel="noopener noreferrer"><code>colour-science</code></a
>
,
a Python library that implements most major colorimetric systems, color space
conversions, and color difference metrics. The remaining dependencies are
standard: <code>numpy</code>, <code>pandas</code>, and <code>matplotlib</code>. Install them with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="ln">1</span><span class="cl">pip install numpy pandas matplotlib colour-science</span></span></code></pre></div><p>Then import them:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">colour</span> <span class="k">as</span> <span class="nn">cl</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.ticker</span> <span class="k">as</span> <span class="nn">tck</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># Disable some annoying warnings from colour library</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">cl</span><span class="o">.</span><span class="n">utilities</span><span class="o">.</span><span class="n">filter_warnings</span><span class="p">(</span><span class="n">colour_usage_warnings</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span></span></span></code></pre></div><h3 id="plot-settings">
  <a class="heading-anchor" href="#plot-settings" aria-hidden="true" tabindex="-1">#</a>
  Plot settings
</h3><p>The following settings match the blog&rsquo;s plot style. If you are following along
in a Jupyter notebook, you can skip this block. I use <code>seaborn</code> for its default
presets (context, ticks, colorblind palette) and the golden ratio from <code>scipy</code>
to set the figure aspect ratio.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 9</span><span class="cl"><span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="kn">from</span> <span class="nn">scipy.constants</span> <span class="kn">import</span> <span class="n">golden_ratio</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># Set seaborn defaults</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">sns</span><span class="o">.</span><span class="n">set_context</span><span class="p">(</span><span class="s2">&#34;notebook&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">sns</span><span class="o">.</span><span class="n">set_style</span><span class="p">(</span><span class="s2">&#34;ticks&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">sns</span><span class="o">.</span><span class="n">set_palette</span><span class="p">(</span><span class="s2">&#34;colorblind&#34;</span><span class="p">,</span> <span class="n">color_codes</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1"># Use white color for elements that are typically black</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">&#34;dark_background&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"># Remove background from figures and axes</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s2">&#34;figure.facecolor&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;none&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s2">&#34;axes.facecolor&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;none&#34;</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"># Default figure size to use throughout</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="n">figure_size</span> <span class="o">=</span> <span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="mi">7</span> <span class="o">/</span> <span class="n">golden_ratio</span><span class="p">)</span></span></span></code></pre></div><h3 id="plotting-the-cie-2-color-space">
  <a class="heading-anchor" href="#plotting-the-cie-2-color-space" aria-hidden="true" tabindex="-1">#</a>
  Plotting the CIE (2°) color space
</h3><p>The <code>colour-science</code> library provides a ready-made function for plotting the CIE
1931 chromaticity diagram. The diagram shows all chromaticities visible to a 2°
standard observer; the spectral locus traces the monochromatic wavelengths, and
any real color falls inside it. We will plot our chlorophyll colors on this
diagram later.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"># Instantiate figure and axes</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c1"># Plot CIE color space for a 2°</span>
</span></span><span class="line hl"><span class="ln">30</span><span class="cl"><span class="n">cl</span><span class="o">.</span><span class="n">plotting</span><span class="o">.</span><span class="n">plot_chromaticity_diagram_CIE1931</span><span class="p">(</span>
</span></span><span class="line hl"><span class="ln">31</span><span class="cl">    <span class="n">cmfs</span><span class="o">=</span><span class="s2">&#34;CIE 1931 2 Degree Standard Observer&#34;</span><span class="p">,</span>
</span></span><span class="line hl"><span class="ln">32</span><span class="cl">    <span class="n">axes</span><span class="o">=</span><span class="n">ax</span><span class="p">,</span>
</span></span><span class="line hl"><span class="ln">33</span><span class="cl">    <span class="n">show</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span></span><span class="line hl"><span class="ln">34</span><span class="cl">    <span class="n">title</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
</span></span><span class="line hl"><span class="ln">35</span><span class="cl">    <span class="n">spectral_locus_colours</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line hl"><span class="ln">36</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;x (2°)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;y (2°)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="c1"># Axes limits</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.85</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.95</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">
</span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.01</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.01</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">
</span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="c1"># Grid settings</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="n">which</span><span class="o">=</span><span class="s2">&#34;major&#34;</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="s2">&#34;both&#34;</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;--&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;gray&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="c1"># Padding adjustment</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">
</span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/CIE_2deg_color_space_hu_85ed38821233d973.webp"
         srcset="/guides/cie-colors-python/CIE_2deg_color_space_hu_3a77b74816ae5188.webp 400w, /guides/cie-colors-python/CIE_2deg_color_space_hu_85ed38821233d973.webp 800w, /guides/cie-colors-python/CIE_2deg_color_space_hu_bedbb92e24d3a917.webp 1200w, /guides/cie-colors-python/CIE_2deg_color_space_hu_450a8211f68f2a8d.webp 1600w, /guides/cie-colors-python/CIE_2deg_color_space_hu_4d916258442aeaa1.webp 1923w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="854"
         alt="CIE color space for a 2° observer."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>CIE color
space for a 2° observer.</figcaption>
</figure><h3 id="importing-and-scaling-data">
  <a class="heading-anchor" href="#importing-and-scaling-data" aria-hidden="true" tabindex="-1">#</a>
  Importing and scaling data
</h3><p>The data are pre-recorded UV-Vis absorption spectra of Chlorophyll A and
Chlorophyll B in 70% and 90% acetone solutions, taken from Chazaux et al.<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>
You can download the <code>.csv</code> file as <a
  href="include/chlorophyll_uv_vis.csv">chlorophyll_uv_vis.csv</a
>
.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">59</span><span class="cl"><span class="n">column_names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;lambda&#34;</span><span class="p">,</span> <span class="s2">&#34;chl_a_70&#34;</span><span class="p">,</span> <span class="s2">&#34;chl_a_90&#34;</span><span class="p">,</span> <span class="s2">&#34;chl_b_70&#34;</span><span class="p">,</span> <span class="s2">&#34;chl_b_90&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="n">measured_samples</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl">    <span class="s2">&#34;chlorophyll_uv_vis.csv&#34;</span><span class="p">,</span> <span class="n">names</span><span class="o">=</span><span class="n">column_names</span><span class="p">,</span> <span class="n">header</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">index_col</span><span class="o">=</span><span class="s2">&#34;lambda&#34;</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="n">measured_samples</span></span></span></code></pre></div><table>
  <thead>
      <tr>
          <th></th>
          <th><strong>chl_a_70</strong></th>
          <th><strong>chl_a_90</strong></th>
          <th><strong>chl_b_70</strong></th>
          <th><strong>chl_b_90</strong></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>lambda</strong></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>350.0</td>
          <td>26132.0</td>
          <td>25552.0</td>
          <td>29529.0</td>
          <td>28301.0</td>
      </tr>
      <tr>
          <td>350.4</td>
          <td>26251.0</td>
          <td>25804.0</td>
          <td>29574.0</td>
          <td>28114.0</td>
      </tr>
      <tr>
          <td>350.8</td>
          <td>26666.0</td>
          <td>26083.0</td>
          <td>29350.0</td>
          <td>27946.0</td>
      </tr>
      <tr>
          <td>351.2</td>
          <td>26703.0</td>
          <td>26227.0</td>
          <td>29084.0</td>
          <td>27660.0</td>
      </tr>
      <tr>
          <td>351.6</td>
          <td>26834.0</td>
          <td>26473.0</td>
          <td>28991.0</td>
          <td>27632.0</td>
      </tr>
      <tr>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
      </tr>
      <tr>
          <td>748.4</td>
          <td>-63.0</td>
          <td>-269.0</td>
          <td>-15.0</td>
          <td>-159.0</td>
      </tr>
      <tr>
          <td>748.8</td>
          <td>-80.0</td>
          <td>-289.0</td>
          <td>-2.0</td>
          <td>-141.0</td>
      </tr>
      <tr>
          <td>749.2</td>
          <td>-95.0</td>
          <td>-283.0</td>
          <td>-13.0</td>
          <td>-157.0</td>
      </tr>
      <tr>
          <td>749.6</td>
          <td>-92.0</td>
          <td>-292.0</td>
          <td>-2.0</td>
          <td>-150.0</td>
      </tr>
      <tr>
          <td>750.0</td>
          <td>82.0</td>
          <td>-198.0</td>
          <td>69.0</td>
          <td>-172.0</td>
      </tr>
  </tbody>
</table>
<p><em>1001 rows × 4 columns</em></p>
<p>Each column records absorbance (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal">A</span></span></span></span>) as a function of wavelength
(<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>λ</mi></mrow><annotation encoding="application/x-tex">\lambda</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">λ</span></span></span></span>) for one chlorophyll–solvent combination:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">60</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="n">figure_size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl">
</span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="c1"># Define the labels for the plot&#39;s legend</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="n">chl_labels</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl">    <span class="s2">&#34;Chlorophyll A (70 % Acetone)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">    <span class="s2">&#34;Chlorophyll A (90 % Acetone)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">66</span><span class="cl">    <span class="s2">&#34;Chlorophyll B (70 % Acetone)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">    <span class="s2">&#34;Chlorophyll B (90 % Acetone)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl">
</span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="c1"># Iterate over dataframe and plot each spectrum</span>
</span></span><span class="line hl"><span class="ln">71</span><span class="cl"><span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="n">sample_label</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">measured_samples</span><span class="o">.</span><span class="n">columns</span><span class="p">,</span> <span class="n">chl_labels</span><span class="p">):</span>
</span></span><span class="line hl"><span class="ln">72</span><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">measured_samples</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="n">measured_samples</span><span class="p">[</span><span class="n">col</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="n">sample_label</span><span class="p">)</span>
</span></span><span class="line hl"><span class="ln">73</span><span class="cl">
</span></span><span class="line hl"><span class="ln">74</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">50</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">77</span><span class="cl">
</span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">79</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;Wavelength [nm]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;Absorbance [a.u.]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">81</span><span class="cl">
</span></span><span class="line"><span class="ln">82</span><span class="cl"><span class="c1"># Display legend</span>
</span></span><span class="line"><span class="ln">83</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">84</span><span class="cl">
</span></span><span class="line"><span class="ln">85</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/chl_a_b_UV_Vis_abs_hu_59a9fac3eedb7766.webp"
         srcset="/guides/cie-colors-python/chl_a_b_UV_Vis_abs_hu_2df7c12b8f5bdf0.webp 400w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_hu_59a9fac3eedb7766.webp 800w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_hu_cf8e6c2eeaddfef8.webp 1200w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_hu_420a7b778e65a1cb.webp 1600w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_hu_6d88b60f4e323db9.webp 1942w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="496"
         alt="UV-Vis absorption spectra of Chlorophyll A and B in 70% and 90 % acetone
solutions."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>UV-Vis absorption spectra of Chlorophyll A
and B in 70% and 90 % acetone solutions.</figcaption>
</figure><p>Chlorophyll A absorbs primarily in the blue (~430 nm) and red (~670 nm) regions.
Chlorophyll B shows a similar pattern with peaks near 460 nm and 650 nm, its
blue peak shifted slightly toward the green. The acetone concentration affects
peak intensities but not spectral shape.</p>
<p>Because the four spectra have different absolute absorbance values, we need to
normalize them before comparing colors. Normalization discards quantitative
information (concentrations), but since our goal is qualitative (what color does
each spectrum produce?), this is acceptable.</p>
<p>We use MinMax scaling to map each spectrum to the 0–1 range while preserving its
shape:<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><msub><mi>x</mi><mrow><mi>s</mi><mi>c</mi><mi>a</mi><mi>l</mi><mi>e</mi><mi>d</mi></mrow></msub><mo>=</mo><mfrac><mrow><mi>x</mi><mo>−</mo><msub><mi>x</mi><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub></mrow><mrow><msub><mi>x</mi><mrow><mi>m</mi><mi>a</mi><mi>x</mi></mrow></msub><mo>−</mo><msub><mi>x</mi><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub></mrow></mfrac></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(6)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
    x_{scaled} = \frac{x - x_{min}}{x_{max} - x_{min}} \tag{6}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">sc</span><span class="mord mathnormal mtight">a</span><span class="mord mathnormal mtight" style="margin-right:0.01968em;">l</span><span class="mord mathnormal mtight">e</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.0963em;vertical-align:-0.836em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">ma</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">min</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">min</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.836em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span><span class="tag"><span class="strut" style="height:2.0963em;vertical-align:-0.836em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">6</span></span><span class="mord">)</span></span></span></span></span></span><p>A simple custom function avoids pulling in <code>scikit-learn</code> for a one-line
operation:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">86</span><span class="cl"><span class="k">def</span> <span class="nf">normalize</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">pd</span><span class="o">.</span><span class="n">Series</span> <span class="o">|</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">pd</span><span class="o">.</span><span class="n">Series</span> <span class="o">|</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">87</span><span class="cl">    <span class="s2">&#34;&#34;&#34;MinMax scaling from 0 to 1
</span></span></span><span class="line"><span class="ln">88</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">89</span><span class="cl"><span class="s2">    Args:
</span></span></span><span class="line"><span class="ln">90</span><span class="cl"><span class="s2">        x (pd.Series | np.ndarray): series or array to normalize
</span></span></span><span class="line"><span class="ln">91</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">92</span><span class="cl"><span class="s2">    Returns:
</span></span></span><span class="line"><span class="ln">93</span><span class="cl"><span class="s2">        pd.Series | np.ndarray: series or array of normalized values
</span></span></span><span class="line"><span class="ln">94</span><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">95</span><span class="cl">    <span class="n">x_scaled</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">x</span><span class="o">.</span><span class="n">min</span><span class="p">())</span> <span class="o">/</span> <span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> <span class="o">-</span> <span class="n">x</span><span class="o">.</span><span class="n">min</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">96</span><span class="cl">    <span class="k">return</span> <span class="n">x_scaled</span></span></span></code></pre></div><p>We apply it to the full DataFrame at once, since pandas vectorizes the operation
across all columns:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">97</span><span class="cl"><span class="n">abs_norm</span> <span class="o">=</span> <span class="n">normalize</span><span class="p">(</span><span class="n">measured_samples</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">98</span><span class="cl"><span class="n">abs_norm</span></span></span></code></pre></div><table>
  <thead>
      <tr>
          <th></th>
          <th><strong>chl_a_70</strong></th>
          <th><strong>chl_a_90</strong></th>
          <th><strong>chl_b_70</strong></th>
          <th><strong>chl_b_90</strong></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>lambda</strong></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>350.0</td>
          <td>0.324398</td>
          <td>0.285405</td>
          <td>0.227556</td>
          <td>0.207087</td>
      </tr>
      <tr>
          <td>350.4</td>
          <td>0.325869</td>
          <td>0.288188</td>
          <td>0.227903</td>
          <td>0.205727</td>
      </tr>
      <tr>
          <td>350.8</td>
          <td>0.331001</td>
          <td>0.291269</td>
          <td>0.226179</td>
          <td>0.204505</td>
      </tr>
      <tr>
          <td>351.2</td>
          <td>0.331458</td>
          <td>0.292859</td>
          <td>0.224133</td>
          <td>0.202425</td>
      </tr>
      <tr>
          <td>351.6</td>
          <td>0.333078</td>
          <td>0.295576</td>
          <td>0.223417</td>
          <td>0.202221</td>
      </tr>
      <tr>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
      </tr>
      <tr>
          <td>748.4</td>
          <td>0.000507</td>
          <td>0.000254</td>
          <td>0.000262</td>
          <td>0.000095</td>
      </tr>
      <tr>
          <td>748.8</td>
          <td>0.000297</td>
          <td>0.000033</td>
          <td>0.000362</td>
          <td>0.000225</td>
      </tr>
      <tr>
          <td>749.2</td>
          <td>0.000111</td>
          <td>0.000099</td>
          <td>0.000277</td>
          <td>0.000109</td>
      </tr>
      <tr>
          <td>749.6</td>
          <td>0.000148</td>
          <td>0.000000</td>
          <td>0.000362</td>
          <td>0.000160</td>
      </tr>
      <tr>
          <td>750.0</td>
          <td>0.002300</td>
          <td>0.001038</td>
          <td>0.000908</td>
          <td>0.000000</td>
      </tr>
  </tbody>
</table>
<p><em>1001 rows × 4 columns</em></p>
<p>A quick plot confirms the spectra now share the same 0–1 scale while retaining
their characteristic shapes:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 99</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="n">figure_size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">100</span><span class="cl">
</span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="n">sample_label</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">abs_norm</span><span class="o">.</span><span class="n">columns</span><span class="p">,</span> <span class="n">chl_labels</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">102</span><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">abs_norm</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="n">normalize</span><span class="p">(</span><span class="n">abs_norm</span><span class="p">[</span><span class="n">col</span><span class="p">]),</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">sample_label</span><span class="si">}</span><span class="s2"> norm&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl">
</span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">105</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">50</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">107</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">108</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.025</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">109</span><span class="cl">
</span></span><span class="line"><span class="ln">110</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">111</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;Wavelength [nm]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">112</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;Absorbance [a.u.]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">113</span><span class="cl">
</span></span><span class="line"><span class="ln">114</span><span class="cl"><span class="c1"># Display legend</span>
</span></span><span class="line"><span class="ln">115</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">116</span><span class="cl">
</span></span><span class="line"><span class="ln">117</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/chl_a_b_UV_Vis_abs_norm_hu_549a485d2d3e409.webp"
         srcset="/guides/cie-colors-python/chl_a_b_UV_Vis_abs_norm_hu_4caa52a5809dbd6.webp 400w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_norm_hu_549a485d2d3e409.webp 800w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_norm_hu_882fcfc9955b4c8a.webp 1200w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_norm_hu_616273e02816e01c.webp 1600w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_norm_hu_18c8f4a4f162d6aa.webp 1853w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="520"
         alt="Normalized UV-Vis absorption spectra of Chlorophyll A and B in 70% and 90 %
acetone solutions."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>Normalized UV-Vis absorption
spectra of Chlorophyll A and B in 70% and 90 % acetone solutions.</figcaption>
</figure><h3 id="converting-absorbance-to-transmittance">
  <a class="heading-anchor" href="#converting-absorbance-to-transmittance" aria-hidden="true" tabindex="-1">#</a>
  Converting absorbance to transmittance
</h3><p>The spectra above record <strong>absorbed</strong> light. The color we perceive depends on
the light that passes <strong>through</strong> the sample: the transmittance. The conversion
from absorbance (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal">A</span></span></span></span>) to percent transmittance (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">%</mi><mi>T</mi></mrow><annotation encoding="application/x-tex">\%T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8056em;vertical-align:-0.0556em;"></span><span class="mord">%</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span></span></span></span>) follows the
Beer-Lambert law:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mtable width="100%"><mtr><mtd width="50%"></mtd><mtd><mrow><mi mathvariant="normal">%</mi><mi>T</mi><mo>=</mo><mn>100</mn><mo>×</mo><msup><mn>10</mn><mrow><mo>−</mo><mi>A</mi></mrow></msup><mo>=</mo><msup><mn>10</mn><mrow><mo stretchy="false">(</mo><mn>2</mn><mo>−</mo><mi>A</mi><mo stretchy="false">)</mo></mrow></msup></mrow></mtd><mtd width="50%"></mtd><mtd><mtext>(7)</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
    \%T = 100 \times 10^{-A} = 10^{(2 - A)} \tag{7}
</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8056em;vertical-align:-0.0556em;"></span><span class="mord">%</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">100</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8913em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mathnormal mtight">A</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.938em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight">A</span><span class="mclose mtight">)</span></span></span></span></span></span></span></span></span></span><span class="tag"><span class="strut" style="height:1.188em;vertical-align:-0.25em;"></span><span class="mord text"><span class="mord">(</span><span class="mord"><span class="mord">7</span></span><span class="mord">)</span></span></span></span></span></span><p>Note that because we are using normalized absorbance values (0&ndash;1) rather than
actual absorbance, the resulting transmittance values do not represent true
physical transmittance. They preserve the spectral shape, which is sufficient
for a qualitative color comparison, but should not be interpreted
quantitatively.</p>
<p>In code:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">120</span><span class="cl"><span class="k">def</span> <span class="nf">abs_to_trans</span><span class="p">(</span><span class="n">A</span><span class="p">:</span> <span class="n">pd</span><span class="o">.</span><span class="n">Series</span> <span class="o">|</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">pd</span><span class="o">.</span><span class="n">Series</span> <span class="o">|</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">121</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Convert absorbance to transmittance
</span></span></span><span class="line"><span class="ln">122</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">123</span><span class="cl"><span class="s2">    Args:
</span></span></span><span class="line"><span class="ln">124</span><span class="cl"><span class="s2">        A (pd.Series | np.ndarray): series or array of absorbance values
</span></span></span><span class="line"><span class="ln">125</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln">126</span><span class="cl"><span class="s2">    Returns:
</span></span></span><span class="line"><span class="ln">127</span><span class="cl"><span class="s2">        pd.Series | np.ndarray: series or array of transmittance values
</span></span></span><span class="line"><span class="ln">128</span><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">129</span><span class="cl">    <span class="n">T</span> <span class="o">=</span> <span class="mi">10</span> <span class="o">**</span> <span class="p">(</span><span class="mi">2</span> <span class="o">-</span> <span class="n">A</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">130</span><span class="cl">    <span class="k">return</span> <span class="n">T</span></span></span></code></pre></div><p>Running it on the normalized absorbance values:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">131</span><span class="cl"><span class="n">transm_norm</span> <span class="o">=</span> <span class="n">abs_to_trans</span><span class="p">(</span><span class="n">abs_norm</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">132</span><span class="cl"><span class="n">transm_norm</span></span></span></code></pre></div><table>
  <thead>
      <tr>
          <th></th>
          <th><strong>chl_a_70</strong></th>
          <th><strong>chl_a_90</strong></th>
          <th><strong>chl_b_70</strong></th>
          <th><strong>chl_b_90</strong></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>lambda</strong></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>350.0</td>
          <td>47.380775</td>
          <td>51.831637</td>
          <td>59.216627</td>
          <td>62.074481</td>
      </tr>
      <tr>
          <td>350.4</td>
          <td>47.220520</td>
          <td>51.500565</td>
          <td>59.169440</td>
          <td>62.269182</td>
      </tr>
      <tr>
          <td>350.8</td>
          <td>46.665880</td>
          <td>51.136488</td>
          <td>59.404698</td>
          <td>62.444622</td>
      </tr>
      <tr>
          <td>351.2</td>
          <td>46.616747</td>
          <td>50.949585</td>
          <td>59.685281</td>
          <td>62.744426</td>
      </tr>
      <tr>
          <td>351.6</td>
          <td>46.443207</td>
          <td>50.631871</td>
          <td>59.783692</td>
          <td>62.773854</td>
      </tr>
      <tr>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
      </tr>
      <tr>
          <td>748.4</td>
          <td>99.883339</td>
          <td>99.941532</td>
          <td>99.939788</td>
          <td>99.978231</td>
      </tr>
      <tr>
          <td>748.8</td>
          <td>99.931694</td>
          <td>99.992372</td>
          <td>99.916775</td>
          <td>99.948098</td>
      </tr>
      <tr>
          <td>749.2</td>
          <td>99.974380</td>
          <td>99.977117</td>
          <td>99.936247</td>
          <td>99.974883</td>
      </tr>
      <tr>
          <td>749.6</td>
          <td>99.965841</td>
          <td>100.000000</td>
          <td>99.916775</td>
          <td>99.963164</td>
      </tr>
      <tr>
          <td>750.0</td>
          <td>99.471847</td>
          <td>99.761259</td>
          <td>99.791184</td>
          <td>100.000000</td>
      </tr>
  </tbody>
</table>
<p><em>1001 rows × 4 columns</em></p>
<p>The transmittance spectra, plotted below, should mirror the absorbance spectra
inverted:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">133</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="n">figure_size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">134</span><span class="cl">
</span></span><span class="line hl"><span class="ln">135</span><span class="cl"><span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="n">sample_label</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">transm_norm</span><span class="o">.</span><span class="n">columns</span><span class="p">,</span> <span class="n">chl_labels</span><span class="p">):</span>
</span></span><span class="line hl"><span class="ln">136</span><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">transm_norm</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="n">transm_norm</span><span class="p">[</span><span class="n">col</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">sample_label</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">137</span><span class="cl">
</span></span><span class="line"><span class="ln">138</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">139</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">50</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">140</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">141</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">142</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">143</span><span class="cl">
</span></span><span class="line"><span class="ln">144</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">145</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;Wavelength [nm]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">146</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;Transmittance [%]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">147</span><span class="cl">
</span></span><span class="line"><span class="ln">148</span><span class="cl"><span class="c1"># Display legend</span>
</span></span><span class="line"><span class="ln">149</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">150</span><span class="cl">
</span></span><span class="line"><span class="ln">151</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/chl_a_b_UV_Vis_trans_norm_hu_cbce41bcc006d87b.webp"
         srcset="/guides/cie-colors-python/chl_a_b_UV_Vis_trans_norm_hu_cc9d75944df32266.webp 400w, /guides/cie-colors-python/chl_a_b_UV_Vis_trans_norm_hu_cbce41bcc006d87b.webp 800w, /guides/cie-colors-python/chl_a_b_UV_Vis_trans_norm_hu_e8f9b306883f335a.webp 1200w, /guides/cie-colors-python/chl_a_b_UV_Vis_trans_norm_hu_5a4fad9f74e23d27.webp 1600w, /guides/cie-colors-python/chl_a_b_UV_Vis_trans_norm_hu_44cbc0f277a47bc4.webp 1866w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="517"
         alt="Normalized UV-Vis transmission spectra of Chlorophyll A and B in 70% and 90 %
acetone solutions."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>Normalized UV-Vis
transmission spectra of Chlorophyll A and B in 70% and 90 % acetone solutions.</figcaption>
</figure><p>The inverse relationship between absorbance and transmittance is visible: peaks
in absorbance correspond to troughs in transmittance. A side-by-side comparison:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">152</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">sharex</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="n">figure_size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">153</span><span class="cl">
</span></span><span class="line"><span class="ln">154</span><span class="cl"><span class="c1"># Iterate over absorbance dataframe</span>
</span></span><span class="line hl"><span class="ln">155</span><span class="cl"><span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="n">sample_label</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">abs_norm</span><span class="o">.</span><span class="n">columns</span><span class="p">,</span> <span class="n">chl_labels</span><span class="p">):</span>
</span></span><span class="line hl"><span class="ln">156</span><span class="cl">    <span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">abs_norm</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="n">normalize</span><span class="p">(</span><span class="n">abs_norm</span><span class="p">[</span><span class="n">col</span><span class="p">]),</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">sample_label</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">157</span><span class="cl">
</span></span><span class="line"><span class="ln">158</span><span class="cl"><span class="c1"># Iterate over transmittance dataframe</span>
</span></span><span class="line hl"><span class="ln">159</span><span class="cl"><span class="k">for</span> <span class="n">col</span><span class="p">,</span> <span class="n">sample_label</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">transm_norm</span><span class="o">.</span><span class="n">columns</span><span class="p">,</span> <span class="n">chl_labels</span><span class="p">):</span>
</span></span><span class="line hl"><span class="ln">160</span><span class="cl">    <span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">transm_norm</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="n">transm_norm</span><span class="p">[</span><span class="n">col</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">sample_label</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">161</span><span class="cl">
</span></span><span class="line"><span class="ln">162</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">163</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;Absorbance [a.u.]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">164</span><span class="cl">
</span></span><span class="line"><span class="ln">165</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;Wavelength [nm]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">166</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;Transmittance [%]&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">167</span><span class="cl">
</span></span><span class="line"><span class="ln">168</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">169</span><span class="cl"><span class="k">for</span> <span class="n">axis</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">170</span><span class="cl">    <span class="n">axis</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">50</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">171</span><span class="cl">    <span class="n">axis</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">172</span><span class="cl">    <span class="c1"># Display legend</span>
</span></span><span class="line"><span class="ln">173</span><span class="cl">    <span class="n">axis</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">174</span><span class="cl">
</span></span><span class="line"><span class="ln">175</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">176</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.025</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">177</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">178</span><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">179</span><span class="cl">
</span></span><span class="line"><span class="ln">180</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/chl_a_b_UV_Vis_abs_trans_norm_hu_38215f4ecd25ead1.webp"
         srcset="/guides/cie-colors-python/chl_a_b_UV_Vis_abs_trans_norm_hu_db10d27a2789079c.webp 400w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_trans_norm_hu_38215f4ecd25ead1.webp 800w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_trans_norm_hu_1c252b6a96fe07e0.webp 1200w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_trans_norm_hu_799efcd0a01f1fad.webp 1600w, /guides/cie-colors-python/chl_a_b_UV_Vis_abs_trans_norm_hu_88637135667f2992.webp 1866w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="517"
         alt="Normalized UV-Vis absorption and transmission spectra of Chlorophyll A and B
in 70% and 90 % acetone solutions."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>Normalized UV-Vis absorption and transmission spectra of Chlorophyll A and B in
70% and 90 % acetone solutions.</figcaption>
</figure><h3 id="calculating-the-cie-colors">
  <a class="heading-anchor" href="#calculating-the-cie-colors" aria-hidden="true" tabindex="-1">#</a>
  Calculating the CIE colors
</h3><p>The pipeline for each spectrum:</p>
<ol>
<li>Build a <code>SpectralDistribution</code> and interpolate to 1 nm intervals (CIE
specification).</li>
<li>Compute <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mi>Y</mi><mi>Z</mi></mrow><annotation encoding="application/x-tex">XYZ</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span></span></span></span> tristimulus values with <code>sd_to_XYZ</code>, using the CIE 1931 2°
observer CMFs and the D65 daylight illuminant.</li>
<li>Convert <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mi>Y</mi><mi>Z</mi></mrow><annotation encoding="application/x-tex">XYZ</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span></span></span></span> to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mi>y</mi></mrow><annotation encoding="application/x-tex">xy</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span> chromaticity coordinates.</li>
</ol>
<p>The results for absorbance-based and transmittance-based colors are stored in
separate lists, then merged into a single DataFrame.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">181</span><span class="cl"><span class="c1"># Define color matching functions</span>
</span></span><span class="line"><span class="ln">182</span><span class="cl"><span class="n">cmfs</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">MSDS_CMFS</span><span class="p">[</span><span class="s2">&#34;cie_2_1931&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">183</span><span class="cl">
</span></span><span class="line"><span class="ln">184</span><span class="cl"><span class="c1"># Define illuminant</span>
</span></span><span class="line"><span class="ln">185</span><span class="cl"><span class="n">illuminant</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">SDS_ILLUMINANTS</span><span class="p">[</span><span class="s2">&#34;D65&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">186</span><span class="cl">
</span></span><span class="line"><span class="ln">187</span><span class="cl"><span class="n">chl_abs_clr</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">188</span><span class="cl">
</span></span><span class="line"><span class="ln">189</span><span class="cl"><span class="c1"># Iterate over each normalized absorbance spectrum</span>
</span></span><span class="line"><span class="ln">190</span><span class="cl"><span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">abs_norm</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">191</span><span class="cl">    <span class="c1"># Initialize spectral distribution</span>
</span></span><span class="line"><span class="ln">192</span><span class="cl">    <span class="n">sd</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">SpectralDistribution</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">abs_norm</span><span class="p">[</span><span class="n">col</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">193</span><span class="cl">
</span></span><span class="line"><span class="ln">194</span><span class="cl">    <span class="c1"># Interpolate sd to conform to the CIE specifications</span>
</span></span><span class="line"><span class="ln">195</span><span class="cl">    <span class="n">sd</span> <span class="o">=</span> <span class="n">sd</span><span class="o">.</span><span class="n">interpolate</span><span class="p">(</span><span class="n">cl</span><span class="o">.</span><span class="n">SpectralShape</span><span class="p">(</span><span class="mi">350</span><span class="p">,</span> <span class="mi">750</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">196</span><span class="cl">
</span></span><span class="line"><span class="ln">197</span><span class="cl">    <span class="c1"># Calculate CIE XYZ coordinates from spectral distribution</span>
</span></span><span class="line"><span class="ln">198</span><span class="cl">    <span class="n">cie_XYZ</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">sd_to_XYZ</span><span class="p">(</span><span class="n">sd</span><span class="p">,</span> <span class="n">cmfs</span><span class="p">,</span> <span class="n">illuminant</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">199</span><span class="cl">
</span></span><span class="line"><span class="ln">200</span><span class="cl">    <span class="c1"># Convert to CIE xy coordinates</span>
</span></span><span class="line"><span class="ln">201</span><span class="cl">    <span class="n">cie_xy</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">XYZ_to_xy</span><span class="p">(</span><span class="n">cie_XYZ</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">202</span><span class="cl">
</span></span><span class="line"><span class="ln">203</span><span class="cl">    <span class="c1"># Append the results to the list of sample colors</span>
</span></span><span class="line"><span class="ln">204</span><span class="cl">    <span class="n">chl_abs_clr</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">205</span><span class="cl">        <span class="p">{</span><span class="s2">&#34;sample&#34;</span><span class="p">:</span> <span class="n">col</span><span class="p">,</span> <span class="s2">&#34;x_A&#34;</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="n">cie_xy</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">4</span><span class="p">),</span> <span class="s2">&#34;y_A&#34;</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="n">cie_xy</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">4</span><span class="p">)}</span>
</span></span><span class="line"><span class="ln">206</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">207</span><span class="cl">
</span></span><span class="line"><span class="ln">208</span><span class="cl"><span class="n">chl_transm_clr</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">209</span><span class="cl">
</span></span><span class="line"><span class="ln">210</span><span class="cl"><span class="c1"># Iterate over each normalized transmittance spectrum</span>
</span></span><span class="line"><span class="ln">211</span><span class="cl"><span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">transm_norm</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">212</span><span class="cl">    <span class="c1"># Initialize spectral distribution</span>
</span></span><span class="line"><span class="ln">213</span><span class="cl">    <span class="n">sd</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">SpectralDistribution</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">transm_norm</span><span class="p">[</span><span class="n">col</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">214</span><span class="cl">    <span class="n">sd</span> <span class="o">=</span> <span class="n">sd</span><span class="o">.</span><span class="n">interpolate</span><span class="p">(</span><span class="n">cl</span><span class="o">.</span><span class="n">SpectralShape</span><span class="p">(</span><span class="mi">350</span><span class="p">,</span> <span class="mi">750</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">215</span><span class="cl">
</span></span><span class="line"><span class="ln">216</span><span class="cl">    <span class="c1"># Calculate CIE XYZ coordinates from spectral distribution</span>
</span></span><span class="line"><span class="ln">217</span><span class="cl">    <span class="n">cie_XYZ</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">sd_to_XYZ</span><span class="p">(</span><span class="n">sd</span><span class="p">,</span> <span class="n">cmfs</span><span class="p">,</span> <span class="n">illuminant</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">218</span><span class="cl">
</span></span><span class="line"><span class="ln">219</span><span class="cl">    <span class="c1"># Convert to CIE xy coordinates</span>
</span></span><span class="line"><span class="ln">220</span><span class="cl">    <span class="n">cie_xy</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">XYZ_to_xy</span><span class="p">(</span><span class="n">cie_XYZ</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">221</span><span class="cl">
</span></span><span class="line"><span class="ln">222</span><span class="cl">    <span class="c1"># Append the results to the list of sample colors</span>
</span></span><span class="line"><span class="ln">223</span><span class="cl">    <span class="n">chl_transm_clr</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">224</span><span class="cl">        <span class="p">{</span><span class="s2">&#34;sample&#34;</span><span class="p">:</span> <span class="n">col</span><span class="p">,</span> <span class="s2">&#34;x_T&#34;</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="n">cie_xy</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">4</span><span class="p">),</span> <span class="s2">&#34;y_T&#34;</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="n">cie_xy</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">4</span><span class="p">)}</span>
</span></span><span class="line"><span class="ln">225</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">226</span><span class="cl">
</span></span><span class="line"><span class="ln">227</span><span class="cl"><span class="c1"># Convert dictionaries to dataframes and join them together</span>
</span></span><span class="line"><span class="ln">228</span><span class="cl"><span class="n">colors</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">chl_transm_clr</span><span class="p">),</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">chl_abs_clr</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">229</span><span class="cl"><span class="n">colors</span></span></span></code></pre></div><table>
  <thead>
      <tr>
          <th></th>
          <th><strong>sample</strong></th>
          <th><strong>x_T</strong></th>
          <th><strong>y_T</strong></th>
          <th><strong>x_A</strong></th>
          <th><strong>y_A</strong></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>0</td>
          <td>chl_a_70</td>
          <td>0.3046</td>
          <td>0.3777</td>
          <td>0.2966</td>
          <td>0.1330</td>
      </tr>
      <tr>
          <td>1</td>
          <td>chl_a_90</td>
          <td>0.3063</td>
          <td>0.3721</td>
          <td>0.2948</td>
          <td>0.1345</td>
      </tr>
      <tr>
          <td>2</td>
          <td>chl_b_70</td>
          <td>0.3558</td>
          <td>0.4365</td>
          <td>0.2036</td>
          <td>0.0930</td>
      </tr>
      <tr>
          <td>3</td>
          <td>chl_b_90</td>
          <td>0.3538</td>
          <td>0.4334</td>
          <td>0.2048</td>
          <td>0.0904</td>
      </tr>
  </tbody>
</table>
<h3 id="visualizing-colors-on-the-cie-color-space">
  <a class="heading-anchor" href="#visualizing-colors-on-the-cie-color-space" aria-hidden="true" tabindex="-1">#</a>
  Visualizing colors on the CIE color space
</h3><p>Plotting the absorbed colors on the CIE 1931 chromaticity diagram:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">230</span><span class="cl"><span class="c1"># Instantiate figure and axes</span>
</span></span><span class="line"><span class="ln">231</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="n">figure_size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">232</span><span class="cl">
</span></span><span class="line"><span class="ln">233</span><span class="cl"><span class="c1"># Plot CIE color space for a 2°</span>
</span></span><span class="line"><span class="ln">234</span><span class="cl"><span class="n">cl</span><span class="o">.</span><span class="n">plotting</span><span class="o">.</span><span class="n">plot_chromaticity_diagram_CIE1931</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">235</span><span class="cl">    <span class="n">cmfs</span><span class="o">=</span><span class="s2">&#34;CIE 1931 2 Degree Standard Observer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">236</span><span class="cl">    <span class="n">axes</span><span class="o">=</span><span class="n">ax</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">237</span><span class="cl">    <span class="n">show</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">238</span><span class="cl">    <span class="n">title</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">239</span><span class="cl">    <span class="n">spectral_locus_colours</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">240</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">241</span><span class="cl">
</span></span><span class="line"><span class="ln">242</span><span class="cl"><span class="n">color_list</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="s2">&#34;g&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;m&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">243</span><span class="cl">
</span></span><span class="line"><span class="ln">244</span><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">color_list</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">245</span><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">scatter</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">246</span><span class="cl">        <span class="n">colors</span><span class="p">[</span><span class="s2">&#34;x_A&#34;</span><span class="p">][</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">247</span><span class="cl">        <span class="n">colors</span><span class="p">[</span><span class="s2">&#34;y_A&#34;</span><span class="p">][</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">248</span><span class="cl">        <span class="n">label</span><span class="o">=</span><span class="n">chl_labels</span><span class="p">[</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">249</span><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">c</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">250</span><span class="cl">        <span class="n">edgecolors</span><span class="o">=</span><span class="s2">&#34;k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">251</span><span class="cl">        <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">252</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">253</span><span class="cl">
</span></span><span class="line"><span class="ln">254</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">255</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;x (2°)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">256</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;y (2°)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">257</span><span class="cl">
</span></span><span class="line"><span class="ln">258</span><span class="cl"><span class="c1"># Axes limits</span>
</span></span><span class="line"><span class="ln">259</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="mf">0.18</span><span class="p">,</span> <span class="mf">0.32</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">260</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mf">0.06</span><span class="p">,</span> <span class="mf">0.16</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">261</span><span class="cl">
</span></span><span class="line"><span class="ln">262</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">263</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.01</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">264</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.005</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">265</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.01</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">266</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.005</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">267</span><span class="cl">
</span></span><span class="line"><span class="ln">268</span><span class="cl"><span class="c1"># Grid settings</span>
</span></span><span class="line"><span class="ln">269</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="n">which</span><span class="o">=</span><span class="s2">&#34;major&#34;</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="s2">&#34;both&#34;</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;--&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;gray&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">270</span><span class="cl">
</span></span><span class="line"><span class="ln">271</span><span class="cl"><span class="c1"># Display legend</span>
</span></span><span class="line"><span class="ln">272</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">273</span><span class="cl">
</span></span><span class="line"><span class="ln">274</span><span class="cl"><span class="c1"># Adjust plot padding</span>
</span></span><span class="line"><span class="ln">275</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">276</span><span class="cl">
</span></span><span class="line"><span class="ln">277</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/CIE_chl_abs_hu_7330f9634d3dac73.webp"
         srcset="/guides/cie-colors-python/CIE_chl_abs_hu_33d4ce3292f2a592.webp 400w, /guides/cie-colors-python/CIE_chl_abs_hu_7330f9634d3dac73.webp 800w, /guides/cie-colors-python/CIE_chl_abs_hu_23e506aa00e49e7c.webp 1200w, /guides/cie-colors-python/CIE_chl_abs_hu_c891051720fed6ce.webp 1600w, /guides/cie-colors-python/CIE_chl_abs_hu_840dc9d2cfc6223a.webp 1733w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="577"
         alt="CIE color space for a 2° observer and calculated absorbed colors for
Chlorophyll A and B in 70 % and 90 % acetone with D65
illuminant."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>CIE color space for a 2° observer and calculated
absorbed colors for Chlorophyll A and B in 70 % and 90 % acetone with D65
illuminant.</figcaption>
</figure><p>The same plot for the transmitted colors:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">278</span><span class="cl"><span class="c1"># Instantiate figure and axes</span>
</span></span><span class="line"><span class="ln">279</span><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="n">figure_size</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">280</span><span class="cl">
</span></span><span class="line"><span class="ln">281</span><span class="cl"><span class="c1"># Plot CIE color space for a 2°</span>
</span></span><span class="line"><span class="ln">282</span><span class="cl"><span class="n">cl</span><span class="o">.</span><span class="n">plotting</span><span class="o">.</span><span class="n">plot_chromaticity_diagram_CIE1931</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">283</span><span class="cl">    <span class="n">cmfs</span><span class="o">=</span><span class="s2">&#34;CIE 1931 2 Degree Standard Observer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">284</span><span class="cl">    <span class="n">axes</span><span class="o">=</span><span class="n">ax</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">285</span><span class="cl">    <span class="n">show</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">286</span><span class="cl">    <span class="n">title</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">287</span><span class="cl">    <span class="n">spectral_locus_colours</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">288</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">289</span><span class="cl">
</span></span><span class="line"><span class="ln">290</span><span class="cl"><span class="n">color_list</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="s2">&#34;g&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;m&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">291</span><span class="cl">
</span></span><span class="line"><span class="ln">292</span><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">color_list</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">293</span><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">scatter</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">294</span><span class="cl">        <span class="n">colors</span><span class="p">[</span><span class="s2">&#34;x_T&#34;</span><span class="p">][</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">295</span><span class="cl">        <span class="n">colors</span><span class="p">[</span><span class="s2">&#34;y_T&#34;</span><span class="p">][</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">296</span><span class="cl">        <span class="n">label</span><span class="o">=</span><span class="n">chl_labels</span><span class="p">[</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="ln">297</span><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">c</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">298</span><span class="cl">        <span class="n">edgecolors</span><span class="o">=</span><span class="s2">&#34;k&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">299</span><span class="cl">        <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">300</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">301</span><span class="cl">
</span></span><span class="line"><span class="ln">302</span><span class="cl"><span class="c1"># Axes labels</span>
</span></span><span class="line"><span class="ln">303</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s2">&#34;x (2°)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">304</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s2">&#34;y (2°)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">305</span><span class="cl">
</span></span><span class="line"><span class="ln">306</span><span class="cl"><span class="c1"># Axes limits</span>
</span></span><span class="line"><span class="ln">307</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">308</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mf">0.35</span><span class="p">,</span> <span class="mf">0.45</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">309</span><span class="cl">
</span></span><span class="line"><span class="ln">310</span><span class="cl"><span class="c1"># Ticks separation</span>
</span></span><span class="line"><span class="ln">311</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.01</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">312</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.005</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">313</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_major_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.01</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">314</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">tck</span><span class="o">.</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mf">0.005</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">315</span><span class="cl">
</span></span><span class="line"><span class="ln">316</span><span class="cl"><span class="c1"># Grid settings</span>
</span></span><span class="line"><span class="ln">317</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="n">which</span><span class="o">=</span><span class="s2">&#34;major&#34;</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="s2">&#34;both&#34;</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;--&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;gray&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">318</span><span class="cl">
</span></span><span class="line"><span class="ln">319</span><span class="cl"><span class="c1"># Display legend</span>
</span></span><span class="line"><span class="ln">320</span><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">(</span><span class="n">labelcolor</span><span class="o">=</span><span class="s2">&#34;k&#34;</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s2">&#34;k&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">321</span><span class="cl">
</span></span><span class="line"><span class="ln">322</span><span class="cl"><span class="c1"># Adjust plot padding</span>
</span></span><span class="line"><span class="ln">323</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">324</span><span class="cl">
</span></span><span class="line"><span class="ln">325</span><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre></div><figure><img src="/guides/cie-colors-python/CIE_chl_transm_hu_bd6e3e621b63d090.webp"
         srcset="/guides/cie-colors-python/CIE_chl_transm_hu_e9c294696ab96f19.webp 400w, /guides/cie-colors-python/CIE_chl_transm_hu_bd6e3e621b63d090.webp 800w, /guides/cie-colors-python/CIE_chl_transm_hu_95de94aa1fb3a0b2.webp 1200w, /guides/cie-colors-python/CIE_chl_transm_hu_608aa88d00bec5e.webp 1600w, /guides/cie-colors-python/CIE_chl_transm_hu_dd9f4f73a3bdb3e2.webp 1836w"
         sizes="(max-width: 800px) 100vw, 800px"
         width="800"
         height="544"
         alt="CIE color space for a 2° observer and calculated transmitted colors for
Chlorophyll A and B in 70 % and 90 % acetone with D65
illuminant."
         loading="lazy"
         decoding="async" /><figcaption><span class="figure-number"></span>CIE color space for a 2° observer and
calculated transmitted colors for Chlorophyll A and B in 70 % and 90 % acetone
with D65 illuminant.</figcaption>
</figure><p>The transmitted-color coordinates confirm what the spectra suggest. Both
chlorophylls absorb in the blue and red regions and transmit primarily in the
green, but the shift in Chlorophyll B&rsquo;s blue absorption peak toward longer
wavelengths pushes its transmitted color toward yellow-green. Chlorophyll A,
with its blue peak at shorter wavelengths, sits closer to a neutral green.</p>
<h2 id="where-to-go-from-here">
  <a class="heading-anchor" href="#where-to-go-from-here" aria-hidden="true" tabindex="-1">#</a>
  Where to go from here
</h2><p>The same pipeline applies to any molecule with a UV-Vis spectrum: dyes,
pigments, optical filter glasses, fluorescent proteins. Swapping in the CIE 1976
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>L</mi><mo lspace="0em" rspace="0em">∗</mo></msup><msup><mi>a</mi><mo lspace="0em" rspace="0em">∗</mo></msup><msup><mi>b</mi><mo lspace="0em" rspace="0em">∗</mo></msup></mrow><annotation encoding="application/x-tex">L^{*}a^{*}b^{*}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">L</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6887em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∗</span></span></span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6887em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∗</span></span></span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6887em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∗</span></span></span></span></span></span></span></span></span></span></span></span> color space (via <code>colour-science</code>&rsquo;s <code>XYZ_to_Lab</code> function) would
give perceptually uniform coordinates, making it possible to compute meaningful
color differences (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>E</mi></mrow><annotation encoding="application/x-tex">\Delta E</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span>) between samples. For quantitative work, the
normalization step should be revisited — using actual absorbance values with a
defined path length and concentration preserves the physical relationship
between Beer-Lambert transmittance and perceived color.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Kingdom, F. A. A.; Prins, N. <em>Psychophysics: A Practical Introduction</em>,
2nd ed.; Academic Press: Amsterdam, NL, 2016; pp. 19&ndash;20.
<a
  href="https://doi.org/10.1016/C2012-0-01278-1"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1016/C2012-0-01278-1</a
>
.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Schanda, J. <em>Colorimetry: Understanding the CIE System</em>; John Wiley &amp;
Sons: Hoboken, NJ, USA, 2007; pp. 56&ndash;59.
<a
  href="https://doi.org/10.1002/9780470175637"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1002/9780470175637</a
>
.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Guild, J. The Colorimetric Properties of the Spectrum. <em>Phil. Trans. R.
Soc. Lond. A</em> <strong>1931</strong>, <em>230</em> (681-693), 149&ndash;187.
<a
  href="https://doi.org/10.1098/rsta.1932.0005"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1098/rsta.1932.0005</a
>
.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Smith, T.; Guild, J. The C.I.E. Colorimetric Standards and Their Use.
<em>Trans. Opt. Soc.</em> <strong>1931</strong>, <em>33</em> (3), 73&ndash;134.
<a
  href="https://doi.org/10.1088/1475-4878/33/3/301"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1088/1475-4878/33/3/301</a
>
.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Chazaux, M.; Schiphorst, C.; Lazzari, G.; Caffarri, S. Precise Estimation
of Chlorophyll a , b and Carotenoid Content by Deconvolution of the
Absorption Spectrum and New Simultaneous Equations for Chl Determination.
<em>Plant J.</em> <strong>2022</strong>, <em>109</em> (6), 1630&ndash;1648.
<a
  href="https://doi.org/10.1111/tpj.15643"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1111/tpj.15643</a
>
.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Otto, M. <em>Chemometrics: Statistics and Computer Application in Analytical
Chemistry</em>, 4th ed.; Wiley-VCH Verlag: Weinheim, DE, 2024; pp. 137&ndash;140.
<a
  href="https://doi.org/10.1002/9783527843800"
    target="_blank" rel="noopener noreferrer">https://doi.org/10.1002/9783527843800</a
>
.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    </channel>
</rss>
