Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cut off top of triangle? #192

Open
Peacemoose10 opened this issue Jun 9, 2022 · 5 comments
Open

Cut off top of triangle? #192

Peacemoose10 opened this issue Jun 9, 2022 · 5 comments

Comments

@Peacemoose10
Copy link

Peacemoose10 commented Jun 9, 2022

Hello!

First, thank you so much for making this package - it's so helpful! I am a geologist, and we often use ternary diagrams with the top cut off, such as the plot below (purely an example I got from the internet).

image

I am struggling to replicate this with your packages. I am using subplots, so I can control the height of the axes using ax.set_ylim, but this just stretches the ternary (example below), and leaves some of the ternary tick marks stretched out above the plot. Is there a way to plot only part of a ternary axis?

strechingproblemexample

Basically, I guess I want to do something like the last part of the solution to #190 but without the free floating ticks.

Thank you!
M

@bmondal94
Copy link

import ternary
import numpy as np

i = [1, 0.7, 0.5, 0.3, 0, 0.7, 0.5, 0.3, 0.4, 0.3, 0.3, 0]
j = [0, 0.3, 0.5, 0.7, 1, 0, 0 , 0, 0.3, 0.3, 0.4, 0.7]
k = [0, 0, 0, 0, 0, 0.3, 0.5, 0.7, 0.3, 0.4, 0.3, 0.3]
Z = np.linspace(0,1,12)

data_dictionary2 = {(i[a], j[a], k[a]) for a in range(len(Z))}
fontsize = 18
#------------------------ Original plot ---------------------------------------
offset = 0.25

fig, tax = ternary.figure(scale=1)
tax.scatter(data_dictionary2)
tax.ticks(axis='lbr', multiple=.1, linewidth=1, offset=0.025, tick_formats="%.1f", fontsize=fontsize)
tax.get_axes().axis('off')
tax.clear_matplotlib_ticks()

tax.boundary(linewidth=2.0)
tax.left_axis_label("Left label $\\alpha^2$", fontsize=fontsize, offset=offset)
tax.right_axis_label("Right label $\\beta^2$", fontsize=fontsize, offset=offset)
tax.bottom_axis_label("Bottom label $\\Gamma - \\Omega$", fontsize=fontsize, offset=offset)

tax.show()

#==============================================================================
#----------------------- After cut --------------------------------------------
ycut = 0.5 # y-axis cut in ternary scale at 0.5
ycut_cart = np.sqrt(3)/2 * ycut # y-axis cut in cartesian coordinate at sqrt(3)/2 * ycut

fig, tax = ternary.figure(scale=1)
tax.scatter(data_dictionary2)
tax.ticks(axis='lbr', multiple=.1, linewidth=1, offset=0.025, tick_formats="%.1f",fontsize=fontsize)
tax.get_axes().axis('off')
tax.clear_matplotlib_ticks()
tax.boundary(linewidth=2.0)

ax = tax.get_axes()
# Note: ymin is not 0.0 but there is an extra lower limit (-0.1) in y-axis to fit 
# the canvas perfectly. Check resize_drawing_canvas() in plotting.py script.
# Calculation: Ternary y-scale maximum 1 == Cartesian y-scale sqrt(3)/2
#              Ternary y-scale maximum ycut == Cartesian y-scale sqrt(3)/2 * ycut
ax.set_ylim(ymax=ycut_cart) # this ymax should be in cartesian coordinate scale.

# Need to increase the offset for left and right labels. Because _redraw_labels()
# will redraw the labels according to the new limits. As in this example the
# bottom ylim was not changed, so one doesn't need to change the bottom_axis_label()
# offset value. 
# Note: tax.show() already calls the tax._redraw_labels().
tax.left_axis_label("Left label $\\alpha^2$", fontsize=fontsize, offset=offset+0.05)
tax.right_axis_label("Right label $\\beta^2$", fontsize=fontsize, offset=offset+0.05)
tax.bottom_axis_label("Bottom label $\\Gamma - \\Omega$", fontsize=fontsize, offset=offset)

# Resize the figure aspect ratio to avoid the streching.
import matplotlib
# height = ycut + 0.1 # 0.1 is the extra ymin used to fit canvas in vertical direction
# width = xlimit(=1) + 2*0.05 # In horizontal axis extra 0.05 was used in both left 
# right to fit the canvas. Check resize_drawing_canvas() in ternary/plotting.py script.
# ratio = height/width
fig_aspect_ratio = (ycut+0.1)/(1+0.1)
w, h = matplotlib.figure.figaspect(fig_aspect_ratio) 
fig.set_size_inches(w, h)

#tax._redraw_labels()
tax.show()
# fig.savefig('/home/test.png',format='png',dpi=300)

#==============================================================================
#---------------------- Alternative way to set figure aspect ratio ------------
import matplotlib
# Resize the figure aspect ratio to avoid the streching.
w, h = matplotlib.figure.figaspect(fig_aspect_ratio)
fig, ax = matplotlib.pyplot.subplots(figsize=(w,h))
tax = ternary.TernaryAxesSubplot(ax=ax, scale = 1)
tax.scatter(data_dictionary2)
tax.ticks(axis='lbr', multiple=.1, linewidth=1, offset=0.025, tick_formats="%.1f",fontsize=fontsize)
tax.get_axes().axis('off')
tax.clear_matplotlib_ticks()
tax.boundary(linewidth=2.0)

ax.set_ylim(ymax=ycut_cart) 

tax.left_axis_label("Left label $\\alpha^2$", fontsize=fontsize, offset=offset+0.05)
tax.right_axis_label("Right label $\\beta^2$", fontsize=fontsize, offset=offset+0.05)
tax.bottom_axis_label("Bottom label $\\Gamma - \\Omega$", fontsize=fontsize, offset=offset)

tax.show()

@Peacemoose10
Copy link
Author

Thank you very much! The last example using subplots is exactly what I needed!

@Peacemoose10
Copy link
Author

Actually, so sorry - I am still struggling to get the numbers above the cut off to disappear. I want to make a figure that has two rows, but when I do that, the ternary numbers above the cutoff bleed into the next plot. I can't figure out how to make them disappear or plot under the top row (I've tried using zorder but that doesn't seem to make a difference). Thank you for your help!

Ternary_AllAnalysisSites_SeparatePlots_quads

@bmondal94
Copy link

Quick and dirty: Add clip_on=True in the ax.text calls inside ternary/lines.py script.
ax.text(x, y, s, horizontalalignment="center", color=axes_colors['l'], fontsize=fontsize,clip_on=True)

@bmondal94
Copy link

A better solution:

import ternary
import numpy as np
from matplotlib import pyplot, gridspec

#-------------------- Function definition for manual tick settings ------------
def ManualTicks(tax, limits):
    '''
    This function creates the ticks. Similar to set_custom_ticks() function in
    ternary/ternary_axes_subplot.py .
    
    Parameters
    ----------
    tax : axis
        Ternary axis.
    limits : dictionary
        Dictionary containing limits. b, l, r == bottom, left, right

    Returns
    -------
    None.

    '''
    
    for k in ['b', 'r', 'l']:
        minimum, maximum, step = limits[k]
        myticks = np.arange(minimum, maximum, step)
        mylocations = np.copy(myticks) - min(myticks) if k=='l' else myticks 
        tax.ticks(ticks=list(myticks), locations=list(mylocations), axis=k,
                  linewidth=1, offset=0.025, fontsize=fontsize)

#--------------------------Create random data----------------------------------
pointsx = np.random.randint(1,50,size=100)
pointsy = np.random.randint(1,50,size=100)
data_dictionary = {(pointsx[a], pointsy[a]) for a in range(len(pointsx))}

fontsize = 18
offset = 0.25

# If you need to cut the ylimit at different positions
# for different subplots you can make a array of cut limits here and
# call accordingly later.
ycut_cart = np.sqrt(3)/2* 50  
limits = {'b':(10,110,10), 'r':(0,60,10), 'l':(50,110,10)} # limits = {which_axis:(minimum_limit, maximum_limit, step_size)}

#-------------------------- Plotting -----------------------------------------
pyplot.figure(figsize=(12,8))
nrows = 2; ncols = 2
gs = gridspec.GridSpec(nrows,ncols)
pyplot.subplots_adjust(wspace=0.3,hspace=0.5)

LeftAxisLabels = ['$\\alpha_1^2$', '$\\alpha_2^2$', '$\\alpha_3^2$', '$\\alpha_4^2$']
RightAxisLabels = ['$\\beta_1^2$','$\\beta_2^2$','$\\beta_3^2$','$\\beta_4^2$']
BottomAxisLabels = ['$\\Gamma_1$','$\\Gamma_2$','$\\Gamma_3$','$\\Gamma_4$']

n = 0
for i in range(nrows):
    for j in range(ncols):       
        ax = pyplot.subplot(gs[i, j])
        figure, tax = ternary.figure(ax=ax, scale = 100)
        tax.scatter(data_dictionary)

        tax.boundary(linewidth=1.0)
        tax.set_title(f"Scatter Plot {i,j}", fontsize=fontsize, pad=30)
        tax.left_axis_label(LeftAxisLabels[n], fontsize=fontsize, offset=0.28)
        tax.right_axis_label(RightAxisLabels[n], fontsize=fontsize, offset=0.3)
        tax.bottom_axis_label(BottomAxisLabels[n], fontsize=fontsize, offset=0.25)
        
        tax._redraw_labels()
        tax.get_axes().set_ylim(ymax=ycut_cart) 
        tax.get_axes().axis('off')
        tax.clear_matplotlib_ticks()
        
        # Lets create the ticks manually       
        ManualTicks(tax, limits)

        n+=1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants