Search code examples
pythonplotplotlyplotly-pythonternary

Issues with ternary coordinates in plotly Scatterternary object


I am trying to create a ternary plot of soil types with text over specific areas to declare what type of soil the area represents. I accomplished this, but the contrast is not great, so I wanted to put a box behind the text to help it stand out... the problem is that the coordinates I derived using pen and paper are yielding bizarre results. Here is the relevant code chunk:

import plotly.graph_objects as go
import plotly.express as px
import pandas as pd

df = pd.DataFrame({"Clay (%)": [], "Silt (%)": [], "Sand (%)": []})
fig = go.Figure(px.scatter_ternary(df, a="Clay (%)", c="Silt (%)", b="Sand (%)"))

# Clay text_bg
a0, a1 = 0.60, 0.60      # bottom left/right vertices
da = 0.09                # change in vertical height
a2, a3 = a1+da, a0+da    # top right/left vertices
b0 = 0.26                # bottom left (eyeballed)
b1 = 0.13                # bottom right (eyeballed)
b2 = b1-da               # top right
b3 = b0-da               # top left
c0 = 0.10                # bottom left (eyeballed)
c1 = 0.24                # bottom right (eyeballed)
c2 = c1-da               # top right
c3 = c0-da               # top left
fig.add_trace(
    go.Scatterternary(a=[a0, a1, a2, a3, a0],
                      b=[b0, b1, b2, b3, b0],
                      c=[c0, c1, c2, c3, c0],
                      mode='lines',
                      line=dict(width=1.5, color='black'),
                      showlegend=False,
                      fill='toself',
                      fillcolor='rgba(1.0,1.0,1.0,0.5)')
)

fig.show()

Soil pyramid

Clearly this is just the code for the box around the word "Clay", I can provide the rest of my code if needed.

--> a represents the "Clay (%)" axis

--> b represents the "Sand (%)" axis

--> c represents the "Silt (%)" axis

I try to generate the box by starting at its bottom left vertex and moving counterclockwise. The first two glaring issues, is that I have the base height (a0) set to 0.60, but it looks like it starts closer to 0.63.; and its height should be constant as it moves to the bottom right vertex, but it clearly decreases. Next, the new height should be 0.69, but it looks closer to 0.79 and is again not constant.

Since the axes are separated by angles of 60deg, you can derive my expressions for the formulated 'b' and 'c' vertices with the law of sines -- that is to say the change in 'a' should be equal to the change in 'b' and 'c' when you are moving vertically.

What is going on here?

BTW: Running in a jupyter notebook IPython version 7.31.1, jupyterlab version 3.4.4, plotly version 5.9.0, on a Windows 11 machine.


Solution

  • I am bad at geometry... the issue was that when the value of changes by some distance da, and do not change by da, they change by da/sqrt(3). I still do not understand the output of the code when I input the wrong coordinates... but regardless, here is the corrected code chunk:

    # Clay text_bg
    a0, a1 = 0.60, 0.60
    da = 0.09
    d_bc = da/np.sqrt(3)
    a2, a3 = a1+da, a0+da
    b0 = 0.30
    b1 = 0.10
    b2 = b1-d_bc
    b3 = b0-d_bc
    c0 = 0.10
    c1 = 0.30
    c2 = c1-d_bc
    c3 = c0-d_bc
    fig.add_trace(
        go.Scatterternary(a=[a0, a1, a2, a3, a0],
                          b=[b0, b1, b2, b3, b0],
                          c=[c0, c1, c2, c3, c0],
                          mode='lines',
                          line=dict(width=1.5, color='black'),
                          showlegend=False,
                          fill='toself',
                          fillcolor='rgba(1.0,1.0,1.0,0.5)')
    )