Skip to content

Commit 4f5dab6

Browse files
tgwoodcockmarcharper
authored andcommitted
Custom axis scales and ticks
Added convenience functions for 1) custom axis scaling e.g. the simplex can have scaöe = 10 but the axes can be labelled for example from 10 to 20, 25 to 35 and 40 to 50, and 2) the ability to pass format strings into lines.ticks() so that any or all of the axes can have int, float or scientific format.
1 parent b783b70 commit 4f5dab6

File tree

3 files changed

+178
-7
lines changed

3 files changed

+178
-7
lines changed

ternary/helpers.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,86 @@ def project_sequence(s, permutation=None):
114114

115115
xs, ys = unzip([project_point(p, permutation=permutation) for p in s])
116116
return xs, ys
117+
118+
119+
## Convert coordinates for custom plots with limits ##
120+
121+
def convert_coordinates(q,conversion,axisorder):
122+
"""
123+
Convert a 3-tuple in data coordinates into to simplex data
124+
coordinates for plotting.
125+
126+
Parameters
127+
----------
128+
q, 3-tuple
129+
the point to be plotted in data coordinates
130+
131+
conversion, dict
132+
keys = ['b','l','r']
133+
vals = lambda function giving the conversion
134+
135+
axisorder, str giving the order of the axes for
136+
the coordinate tuple e.g. 'blr' for bottom, left,
137+
right coordinates.
138+
139+
Returns
140+
-------
141+
p, 3-tuple
142+
the point converted to simplex coordinates
143+
"""
144+
p = []
145+
for k in range(3):
146+
p.append(conversion[axisorder[k]](q[k]))
147+
148+
return tuple(p)
149+
150+
151+
def get_conversion(scale,limits):
152+
"""
153+
Get the converion equations for each axis.
154+
155+
limits: dict of min and max values for the axes in the order blr.
156+
"""
157+
fb = float(scale)/float(limits['b'][1]-limits['b'][0])
158+
fl = float(scale)/float(limits['l'][1]-limits['l'][0])
159+
fr = float(scale)/float(limits['r'][1]-limits['r'][0])
160+
161+
conversion = {"b" : lambda x: (x-limits['b'][0])*fb,
162+
"l" : lambda x: (x-limits['l'][0])*fl,
163+
"r" : lambda x: (x-limits['r'][0])*fr
164+
}
165+
166+
return conversion
167+
168+
169+
def convert_coordinates_sequence(qs,scale,limits,axisorder):
170+
"""
171+
Take a sequence of 3-tuples in data coordinates and convert them
172+
to simplex coordinates for plotting. This is needed for custom
173+
plots where the scale of the simplex axes is set within limits rather
174+
than being defined by the scale parameter.
175+
176+
Parameters
177+
----------
178+
qs, sequence of 3-tuples
179+
the points to be plotted in data coordinates
180+
181+
scale, int
182+
the scale parameter for the plot
183+
184+
limits, dict
185+
keys = ['b','l','r']
186+
vals = min,max data values for this axis
187+
188+
axisorder, str giving the order of the axes for
189+
the coordinate tuple e.g. 'blr' for bottom, left,
190+
right coordinates.
191+
192+
Returns
193+
-------
194+
s, list of 3-tuples
195+
the points converted to simplex coordinates
196+
"""
197+
conversion = get_conversion(scale,limits)
198+
199+
return [convert_coordinates(q,conversion,axisorder) for q in qs]

ternary/lines.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ def gridlines(ax, scale, multiple=None, horizontal_kwargs=None, left_kwargs=None
186186
return ax
187187

188188
def ticks(ax, scale, ticks=None, locations=None, multiple=1, axis='b',
189-
offset=0.01, clockwise=False, axes_colors=None, fsize = 10, **kwargs):
189+
offset=0.01, clockwise=False, axes_colors=None, fsize = 10,
190+
tick_formats=None, **kwargs):
190191
"""
191192
Sets tick marks and labels.
192193
@@ -213,6 +214,12 @@ def ticks(ax, scale, ticks=None, locations=None, multiple=1, axis='b',
213214
axes_colors: Dict, None
214215
Option to color ticks differently for each axis, 'l', 'r', 'b'
215216
e.g. {'l': 'g', 'r':'b', 'b': 'y'}
217+
tick_formats: None, Dict, Str
218+
If None, all axes will be labelled with ints. If Dict, the keys are
219+
'b', 'l' and 'r' and the values are format strings e.g. "%.3f" for
220+
a float with 3 decimal places or "%.3e" for scientific format with
221+
3 decimal places or "%d" for ints. If tick_formats is a string, it
222+
is assumed that this is a format string to be applied to all axes.
216223
kwargs:
217224
Any kwargs to pass through to matplotlib.
218225
@@ -258,7 +265,16 @@ def ticks(ax, scale, ticks=None, locations=None, multiple=1, axis='b',
258265
tick = ticks[index]
259266
line(ax, loc1, loc2, color=axes_colors['r'], **kwargs)
260267
x, y = project_point(text_location)
261-
ax.text(x, y, str(tick), horizontalalignment="center",
268+
if tick_formats == None:
269+
if type(tick) == int:
270+
s = str(tick)
271+
else:
272+
s = str(int(tick))
273+
elif type(tick_formats) == str:
274+
s = tick_formats %(tick)
275+
elif type(tick_formats == dict):
276+
s = tick_formats['r'] %(tick)
277+
ax.text(x, y, s, horizontalalignment="center",
262278
color=axes_colors['r'], fontsize=fsize)
263279

264280
if 'l' in axis:
@@ -276,7 +292,16 @@ def ticks(ax, scale, ticks=None, locations=None, multiple=1, axis='b',
276292
tick = ticks[-(index+1)]
277293
line(ax, loc1, loc2, color=axes_colors['l'], **kwargs)
278294
x, y = project_point(text_location)
279-
ax.text(x, y, str(tick), horizontalalignment="center",
295+
if tick_formats == None:
296+
if type(tick) == int:
297+
s = str(tick)
298+
else:
299+
s = str(int(tick))
300+
elif type(tick_formats) == str:
301+
s = tick_formats %(tick)
302+
elif type(tick_formats == dict):
303+
s = tick_formats['l'] %(tick)
304+
ax.text(x, y, s, horizontalalignment="center",
280305
color=axes_colors['l'], fontsize=fsize)
281306

282307
if 'b' in axis:
@@ -294,5 +319,14 @@ def ticks(ax, scale, ticks=None, locations=None, multiple=1, axis='b',
294319
tick = ticks[index]
295320
line(ax, loc1, loc2, color=axes_colors['b'], **kwargs)
296321
x, y = project_point(text_location)
297-
ax.text(x, y, str(tick), horizontalalignment="center",
322+
if tick_formats == None:
323+
if type(tick) == int:
324+
s = str(tick)
325+
else:
326+
s = str(int(tick))
327+
elif type(tick_formats) == str:
328+
s = tick_formats %(tick)
329+
elif type(tick_formats == dict):
330+
s = tick_formats['b'] %(tick)
331+
ax.text(x, y, s, horizontalalignment="center",
298332
color=axes_colors['b'], fontsize=fsize)

ternary/ternary_axes_subplot.py

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from . import heatmapping
1111
from . import lines
1212
from . import plotting
13-
from .helpers import project_point
13+
from .helpers import project_point, convert_coordinates_sequence
1414

1515

1616
def figure(ax=None, scale=None, permutation=None):
@@ -102,6 +102,20 @@ def set_scale(self, scale=None):
102102
def get_scale(self):
103103
return self._scale
104104

105+
def set_axis_limits(self, axis_limits=None):
106+
"""
107+
Set min and max data limits for each of the three axes.
108+
109+
axis_limits = dict
110+
keys are 'b','l' and 'r' for the three axes
111+
vals are lists of the min and max values for the axis in
112+
data units.
113+
"""
114+
self._axis_limits = axis_limits
115+
116+
def get_axis_limits(self):
117+
return self._axis_limits
118+
105119
# Title and Axis Labels
106120

107121
def set_title(self, title, **kwargs):
@@ -255,13 +269,42 @@ def clear_matplotlib_ticks(self, axis="both"):
255269
ax = self.get_axes()
256270
plotting.clear_matplotlib_ticks(ax=ax, axis=axis)
257271

272+
273+
def get_ticks_from_axis_limits(self,multiple=1):
274+
"""
275+
Taking self._axis_limits and self._boundary_scale get the scaled
276+
ticks for all three axes and store them in self._ticks under the
277+
keys 'b' for bottom, 'l' for left and 'r' for right axes.
278+
"""
279+
for k in ['b','l','r']:
280+
self._ticks[k] = numpy.linspace(self._axis_limits[k][0],
281+
self._axis_limits[k][1],
282+
(self._boundary_scale/float(multiple)+1)).tolist()
283+
284+
285+
286+
def set_custom_ticks(self, locations=None,clockwise=False,multiple=1,
287+
axes_colors=None, tick_formats=None, **kwargs):
288+
"""
289+
Having called get_ticks_from_axis_limits, set the custom ticks on the
290+
plot.
291+
"""
292+
for k in ['b','l','r']:
293+
self.ticks(ticks=self._ticks[k],locations=locations,
294+
axis=k,clockwise=clockwise, multiple=multiple,
295+
axes_colors=axes_colors, tick_formats=tick_formats,
296+
**kwargs)
297+
298+
258299
def ticks(self, ticks=None, locations=None, multiple=1, axis='blr',
259-
clockwise=False, axes_colors=None, **kwargs):
300+
clockwise=False, axes_colors=None, tick_formats=None,
301+
**kwargs):
260302
ax = self.get_axes()
261303
scale = self.get_scale()
262304
lines.ticks(ax, scale, ticks=ticks, locations=locations,
263305
multiple=multiple, clockwise=clockwise, axis=axis,
264-
axes_colors=axes_colors, **kwargs)
306+
axes_colors=axes_colors, tick_formats=tick_formats,
307+
**kwargs)
265308

266309
# Redrawing and resizing
267310

@@ -293,6 +336,17 @@ def _redraw_labels(self):
293336
text.set_rotation_mode("anchor")
294337
self._to_remove.append(text)
295338

339+
340+
341+
def convert_coordinates(self,points,axisorder='blr'):
342+
"""
343+
Convert data coords to simplex coords for plotting
344+
in the case that axis limits have been applied
345+
"""
346+
return convert_coordinates_sequence(points,self._boundary_scale,
347+
self._axis_limits,axisorder)
348+
349+
296350
## Various Plots
297351

298352
def scatter(self, points, **kwargs):

0 commit comments

Comments
 (0)