Latexify ternary Countour Plot Colobar

I have created the above ternary plot using the code below:

import plotly.figure_factory as ff
fig = ff.create_ternary_contour(np.stack((prob0,prob1,prob2)),some_calc_val,
                                pole_labels=[r'$\text{AxesA}$', r'$\text{AxesB}$', r'$\text{AxesC}$'],
                                interp_mode='cartesian',
                                ncontours=50,
                                colorscale='Jet',
                                showscale=True,
                                title=r'$\text{Plot}$')


fig.update_ternaries(
    aaxis = dict(
        tickmode = 'array',
        ticklen = 10,
        tickvals = [0.2, 0.4, 0.6, 0.8],
        ticktext = [r'$0.2$', r'$0.4$', r'$0.6$', r'$0.8$']
    ),
    baxis = dict(
        tickmode = 'array',
        ticklen = 10,
        tickvals = [0.2, 0.4, 0.6, 0.8],
        ticktext = [r'$0.2$', r'$0.4$', r'$0.6$', r'$0.8$']
    ),
    caxis = dict(
        tickmode = 'array',
        ticklen = 10,
        tickvals = [0.2, 0.4, 0.6, 0.8],
        ticktext = [r'$0.2$', r'$0.4$', r'$0.6$', r'$0.8$']
    )
)

fig.update_layout(width=600, height=600)

fig.show()

Data for refrence

prob0=[9.99960940e-01 6.03061907e-04 9.10372544e-12 9.99952169e-01
 2.81419593e-04 2.17084140e-18 9.99882767e-01 5.63535132e-11
 1.86320179e-25]

 prob1=[3.90598546e-05 9.99396859e-01 6.40065936e-01 4.78313969e-05
 5.71105924e-01 1.86904565e-07 5.85691843e-05 1.40045638e-07
 1.96443635e-14]

 prob2=[4.32181700e-19 7.88323607e-08 3.59934064e-01 5.03536073e-12
 4.28612656e-01 9.99999813e-01 5.86636024e-05 9.99999860e-01
 1.00000000e+00]

 some_calc_val=[3.90598546e-05 6.03140740e-04 3.59934064e-01 4.78314019e-05
 4.28894076e-01 1.86904565e-07 1.17232787e-04 1.40101991e-07
 1.95399252e-14]

Questions:

  • I would like to Latexify the ticks for the color bar on the right, I have looked around in the layout but did not find any such color bar which I could update the ticks for
  • Is it possible to add a little space between the ternary plot and the color bar, the name of the AxesC falls right under the color bar which is not ideal for my use case.
  • Also is there a way to add labels similar to what is used in go.Countour() which has a showlabels key

References before posting:

@Sharma

  • It’s not clear from your post whether you want a LaTeX-like font for numerical ticks or you intend to add some greek letters/formula, for example, like colorbar ticks.
    The “Open Sherif” font it’s a good LaTeX font.
  • a ternary contour plot is performed using some tricks. If you’ll print(len(fig.data)) you can notice that your figure consists in 53 traces. The last one is responsible for plotting the marker_colorbar. Hence this last, fig.data[-1], must be updated to move the colorbar to the right, such that no overlapping with AxesC occurs.
    These are the updates to set a LaTeX font for numerical ticks, and to change the colorbar position.
fig.update_layout(width=600, height=600, font_family="Open Sherif")
fig.data[-1].update(marker_colorbar_x=1.15); #you can change 1.15 with a  convenient value >1.

Let me know what you intend to display as colorbar ticks, to point out the corresponding updates as LaTeX ticktext.

My opinion is that you have set too many contour lines. With ncontours = 25 you get a much more relevant ternary contour plot, with a better aesthetic.
There is no key to set labels for contours, in a ternary contour, but with a hack I could find a solution. With 50 contours however it is difficut to place a label.

With more updates for marker_colorbar, and layout:

fig.update_layout(title_x=0.5, width=500, height=500, font_family="Open Sherif")
fig.data[-1].update(marker_colorbar_x=1.12, marker_colorbar_len=0.87, marker_colorbar_y=0.48);

the plot looks like this:
ternary-contour

2 Likes

@empet thanks for your inputs on this, the plot above looks great. Some clarity

It’s not clear from your post whether you want a LaTeX-like font for numerical ticks or you intend to add some greek letters/formula, for example, like colorbar ticks.
The “Open Sherif” font it’s a good LaTeX font.

So I am not looking for greek letters or symbols for the color bar, I want LaTeX-like font for numerical ticks. I can work with the color bar tick text as shown in the figure you have created, but even after updating the code I still end up with regular ticks for the color bar as shown below

I think the spacing thing for the color bar is pretty neat and works as expected. I also agree that 25 contour lines should give a better plot. If it is not too much work could you maybe update the code for contour labels here?

Plotly version details

Name: plotly
Version: 5.5.0
Summary: An open-source, interactive data visualization library for Python
Home-page: https://plotly.com/python/
Author: Chris P
Author-email: chris@plot.ly
License: MIT
Location: /usr/local/lib/python3.7/dist-packages
Requires: tenacity, six
Required-by: cufflinks

@Sharma
The last Plotly version is 5.8.0.
Install it, via:

pip install plotly  __upgrade

A font type is displayed only if it exists on your system.
Try also:

font_family='Sherif'   #or
font_family='Balto'

See also the reference: Layout in Python

@empet I will fix the above issues at my end. Kindly let me know if you can still plot labels for the ternary contour lines.

Thanks in advance

Hi @Sharma ,
Your ternary contour figure, with 25 contour lines, contains 28 traces, i.e. len(fig.data)=28.
fig.data[0] fills the entire triangle with the same color, figdata[-2] adds the pole names, and the last one, fig.data[-1],adds the colorbar. Hence each fig.data[k], for k=1, 2, …25, represents a contour plot. The trace name,
fig.data[k].name is a number that represents the contourline “height”,
hence this one should be displayed.

To suggest how to add the contour line height at a few traces, just define a new figure and plot it,
to realize how difficult is to choose a particular position for that number.
Example, let us plot fig.data[15]:

Scatterternary({
    'a': array([0.67587022, 0.67653508, 0.67693866, ..., 0.67494656, 0.67497363,
                0.67587022]),
    'b': array([0.12722625, 0.13189232, 0.13668901, ..., 0.12268959, 0.12282173,
                0.12722625]),
    'c': array([0.19690353, 0.19157261, 0.18637232, ..., 0.20236385, 0.20220464,
                0.19690353]),
    'fill': 'toself',
    'fillcolor': 'rgb(206.923076923077, 255.0, 49.03846153846149)',
    'hoverinfo': 'skip',
    'line': {'color': 'rgb(150, 150, 150)', 'shape': 'spline', 'width': 1},
    'mode': 'lines',
    'name': '0.247',
    'showlegend': False
})

namely define a new figure, fig1, just to see the contour line shape and to decide where we can locate its height:

import plotly.graph_objects as go
k=15
tr= fig.data[15] #tr stands for trace
fig1=go.Figure(tr)
fig.update_traces(showlegend=False)
fig1.update_layout(width=400, height=400, font_family="Open Sherif")

contour-fig-data-15
Now let us update the initial figure, where are plotted all contour lines, the height of the above contour line:

m= len(tr.a)//4  #m is the point position where the text witll be displayed (i.e. the contour height)
text= tr.name
fig.add_scatterternary(a=[tr.a[m]], b=[tr.b[m]], c=[tr.c[m]],
                        mode="text", text=text, showlegend=False)

global-plot-with-contour-height
Notice that we cannot decide now which contour line has the height 0.247 :frowning:

If you intend to add a few heights on the plot, then you must repeat the experiment described above for some k in {1,2, …25}.
Pick up the position , m, of each point on a contour you selected for adding its height , and append each corresponding coordinate a, b, c, to a list of a-coords, b-coords, c-coords. Then the last line of code displayed above should be replaced by something like this:

fig.add_scatterternary(a=[fig.data[12].a[51], ... , fig.data[24],a[123]],  
                       b=[fig.data[12].b[51], ... , fig.data[24],b123]],
                       c=fig.data[12].c[51], ... , fig.data[24],c[123]], 
                       mode="text", text=[fig.data[12].name, ..., ,  fig.data[24].name], 
                      showlegend=False)

All strings in your initial code in ticktext = [r'$0.2$', r'$0.4$', r'$0.6$', r'$0.8$'] should be written simply, as 0.2, 0.4, etc,
and poles_labels as:

 pole_labels= ['AxesA', 'AxesB', 'AxesC']

Good luck!!! :slight_smile:

This is slightly more challenging than I thought it was going to be :sweat_smile:

Anyways thank you for taking out the time and implementing this. :slightly_smiling_face:

1 Like