Axes

Axes by example

Axes are fundamental building blocks of nomographs. The following code uses minimal axis definion N_params that is rendered as a linear scale illustrated below. The range of values axis represents is defined with keywords u_min and u_max. title sets title string for the axis. Key part of the nomograph is the functional form of the axis. In the example below it is defined with keyword function and is given as a function. Different types of blocks assume different keywords of axis functions. For example types 1, 2 and 3 take keyword function but type 9 takes either f, g, h or f_grid, g_grid, h_grid keywords. So one have to define axis parameters compatible with the used block type. In the examples below Type 8 is used as block to taking axis definition because it is the simplest one.

Linear scale ('scale_type':'linear')

Here we start with the simplest axis. It has by default scale 'scale_type':'linear' that is simple linear scale.

 1# ex_axes_1.py
 2
 3import sys
 4
 5sys.path.insert(0, "..")
 6from pynomo.nomographer import Nomographer
 7
 8# axis definitions
 9N_params = {'u_min': 1.0,  # axis start value
10            'u_max': 10.0,  # axis stop value
11            'function': lambda u: u,  # axis function
12            'title': 'u',  # axis titles
13            }
14
15# block definitons defining one block of type 8
16block_params = {'block_type': 'type_8',
17                'f_params': N_params,
18                'width': 5.0,
19                'height': 15.0,
20                }
21
22# nomograph generation definitions
23main_params = {'filename': 'ex_axes_1.pdf',
24               'paper_height': 15.0,
25               'paper_width': 5.0,
26               'block_params': [block_params],
27               'transformations': [('scale paper',)]
28               }
29
30# actual code that builds the nomograph
31Nomographer(main_params)
../_images/ex_axes_1.png

Because the example above looked little too busy or packed, we reduce the ticks by using only three different tick levels 'tick_levels':3 and two tick text levels 'tick_text_levels':2. Tick side relative to the final drawing is set to left using 'tick_side':'left'.

 1# ex_axes_2.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'u',
 7            'tick_levels': 3,        # <-
 8            'tick_text_levels': 2,   # <-
 9            'tick_side': 'left',     # <-
10            }
11
12block_params = {'block_type': 'type_8',
13                'f_params': N_params,
14                'width': 5.0,
15                'height': 10.0,
16                }
17
18main_params = {'filename': 'ex_axes_2.pdf',
19                'paper_height': 10.0,
20                'paper_width': 5.0,
21                'block_params': [block_params],
22                'transformations': [('scale paper',)]
23               }
24
25Nomographer(main_params)
../_images/ex_axes_2.png

Title position can be shifted in both x- and y-directions. In the following we shift it using key-values 'title_x_shift':-1.0 and 'title_y_shift':0.5. Units are here centimeters.

 1# ex_axes_3.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'u',
 7            'tick_levels': 3,
 8            'tick_text_levels': 2,
 9            'tick_side': 'left',
10            'title_x_shift': -1.0,   # <-
11            'title_y_shift': 0.5     # <-
12            }
13
14block_params = {'block_type': 'type_8',
15                'f_params': N_params,
16                'width': 5.0,
17                'height': 10.0,
18                }
19
20main_params = {'filename': 'ex_axes_3.pdf',
21               'paper_height': 10.0,
22               'paper_width': 5.0,
23               'block_params': [block_params],
24               'transformations': [('scale paper',)]
25               }
26
27Nomographer(main_params)
../_images/ex_axes_3.png

Sometimes single level of axis definitions is not enough. We might want to add more ticks in some additional range of the axis. Keyword 'extra_params' helps here. Value for this key is an array of dictionaries that modify given params in the given range set by u_min and u_max. In the following example we define additional ranges with more ticks in ranges 5.0..10.0 and 9.0..10.0. We also draw title this time to center using 'title_draw_center:True.

 1# ex_axes_4.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'title',
 7            'tick_levels': 2,
 8            'tick_text_levels': 1,
 9            'tick_side': 'left',
10            'title_draw_center': True,                 # <-
11            'extra_params': [{'u_min': 5.0,            # <- range 1
12                              'u_max': 10.0,           # <-
13                              'tick_levels': 3,        # <-
14                              'tick_text_levels': 2,   # <-
15                              },                       # <-
16                             {'u_min': 9.0,            # <- range 2
17                              'u_max': 10.0,           # <-
18                              'tick_levels': 4,        # <-
19                              'tick_text_levels': 2,   # <-
20                              }                        # <-
21                             ]                         # <-
22            }
23block_params = {'block_type': 'type_8',
24                'f_params': N_params,
25                'width': 5.0,
26                'height': 10.0,
27                }
28main_params = {'filename': 'ex_axes_4.pdf',
29               'paper_height': 10.0,
30               'paper_width': 5.0,
31               'block_params': [block_params],
32               'transformations': [('scale paper',)]
33               }
34Nomographer(main_params)
../_images/ex_axes_4.png

Color can be used to tune visual appearance of the axis. In the following example we tune colors with self-explaining keywords 'axis_color', 'text_color' and 'title_color'. Additional titles are set by using keyword 'extra_titles' with value of an array of dictionaries that can take keywords 'dx' and 'dy' as relative position to main title. Value of keyword 'text'``sets the title text and ``'pyx_extra_defs' can be used to give additional parameters for pyx rendering that is only option in current release. In the example numbers are formatted to have one three digits before comma and and one digit after comma using 'text_format':r"$%3.1f$ ".

 1# ex_axes_4_1.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'title',
 7            'tick_levels': 2,
 8            'tick_text_levels': 1,
 9            'tick_side': 'left',
10            'title_draw_center': True,
11            'text_format': r"$%3.1f$ ",                              # <- format numbers as %3.1f
12            'axis_color': color.cmyk.Orange,
13            'text_color': color.cmyk.Plum,
14            'title_color': color.cmyk.Plum,
15            'extra_params': [{'u_min': 5.0,
16                              'u_max': 10.0,
17                              'tick_levels': 3,
18                              'tick_text_levels': 2,
19                              'axis_color': color.cmyk.Red,
20                              },
21                             {'u_min': 9.0,
22                              'u_max': 10.0,
23                              'tick_levels': 4,
24                              'tick_text_levels': 2,
25                              'axis_color': color.cmyk.Blue,
26                              }
27                            ],
28            'extra_titles': [{'dx': 1.0,                                          # <- 1st extra title
29                              'dy': 1.0,                                          # <-
30                              'text': 'extra title 1',                            # <-
31                              'width': 5,                                         # <-
32                              'pyx_extra_defs': [color.rgb.red, text.size.tiny]   # <-
33                              },
34                            {'dx': 0.0,                                           # <- 2nd extra title
35                             'dy': 2.0,                                           # <-
36                             'text': 'extra title 2',                             # <-
37                             'width': 5,                                          # <-
38                             'pyx_extra_defs': [color.rgb.green]                  # <-
39                             },
40                            {'dx': -1.0,                                          # <- 3rd extra title
41                             'dy': 1.0,                                           # <-
42                             'text': r"extra  \par title 3",                      # <- \par = newline
43                             'width': 5,                                          # <-
44                             'pyx_extra_defs': [color.rgb.blue]                   # <-
45                             }]
46            }
47block_params = {'block_type': 'type_8',
48                'f_params': N_params,
49                'width': 5.0,
50                'height': 10.0,
51                }
52main_params = {'filename': 'ex_axes_4_1.pdf',
53               'paper_height': 10.0,
54               'paper_width': 5.0,
55               'block_params': [block_params],
56               'transformations': [('scale paper',)]
57               }
58Nomographer(main_params)
../_images/ex_axes_4_1.png

Manual point scale ('scale_type':'manual point')

Sometimes axes have to be defined manually. One option is to use manual point scale type with 'scale_type':'manual point' and define the points as a dict to keyword 'manual_axis_data'.

 1# ex_axes_5.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'title',
 7            'tick_levels': 2,
 8            'tick_text_levels': 1,
 9            'tick_side': 'left',
10            'title_draw_center': True,
11            'scale_type': 'manual point',        # <- use manual points
12            'manual_axis_data': {1.0: 'one',     # <- give point values as keys
13                                 2.0: 'two',     # <- and texts as values
14                                 3.0: 'three',
15                                 3.1415: r'$\pi$',
16                                 4.0: 'four',
17                                 5.0: 'five',
18                                 6.0: 'six',
19                                 7.0: 'seven',
20                                 8.0: 'eight',
21                                 9.0: 'nine',
22                                 10.0: 'ten'}
23            }
24block_params = {'block_type': 'type_8',
25                'f_params': N_params,
26                'width': 5.0,
27                'height': 10.0
28                }
29main_params = {'filename': 'ex_axes_5.pdf',
30               'paper_height': 10.0,
31               'paper_width': 5.0,
32               'block_params': [block_params],
33               'transformations': [('scale paper',)]
34               }
35Nomographer(main_params)
../_images/ex_axes_5.png

Manual line scale ('scale_type':'manual line')

Similarly other option is to use manual line scale type with 'scale_type':'manual line' that draws main scale line and ticks. Drawn ticks are defined as a dict to keyword 'manual_axis_data' as above example.

 1# ex_axes_6.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'title',
 7            'tick_levels': 2,
 8            'tick_text_levels': 1,
 9            'tick_side': 'left',
10            'title_draw_center': True,
11            'scale_type': 'manual line',     # <-
12            'manual_axis_data': {1.0: 'one',
13                                 2.0: 'two',
14                                 3.0: 'three',
15                                 3.1415: r'$\pi$',
16                                 4.0: 'four',
17                                 5.0: 'five',
18                                 6.0: 'six',
19                                 7.0: 'seven',
20                                 8.0: 'eight',
21                                 9.0: 'nine',
22                                 10.0: 'ten'}
23            }
24block_params = {'block_type': 'type_8',
25                'f_params': N_params,
26                'width': 5.0,
27                'height': 10.0,
28                }
29main_params = {'filename': 'ex_axes_6.pdf',
30               'paper_height': 10.0,
31               'paper_width': 5.0,
32               'block_params': [block_params],
33               'transformations': [('scale paper',)]
34               }
35Nomographer(main_params)
../_images/ex_axes_6.png

Combining manual lines and a linear scale.

 1# ex_axes_7.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': 'title',
 7            'tick_levels': 2,
 8            'tick_text_levels': 1,
 9            'tick_side': 'left',
10            'scale_type': 'manual line',
11            'manual_axis_data': {1.0: 'one',
12                                 2.0: 'two',
13                                 3.0: 'three',
14                                 3.1415: r'$\pi$',
15                                 4.0: 'four',
16                                 5.0: 'five',
17                                 6.0: 'six',
18                                 7.0: 'seven',
19                                 8.0: 'eight',
20                                 9.0: 'nine',
21                                 10.0: 'ten'},
22            'extra_params': [{'u_min': 1.0,
23                              'u_max': 10.0,
24                              'scale_type': 'linear',
25                              'tick_levels': 3,
26                              'tick_text_levels': 2,
27                              'tick_side': 'right',
28                              }]
29            }
30block_params = {'block_type': 'type_8',
31                'f_params': N_params,
32                'width': 5.0,
33                'height': 10.0,
34                }
35main_params = {'filename': 'ex_axes_7.pdf',
36               'paper_height': 10.0,
37               'paper_width': 5.0,
38               'block_params': [block_params],
39               'transformations': [('scale paper',)]
40               }
41Nomographer(main_params)
../_images/ex_axes_7.png

Manual arrows ('scale_type':'manual arrow')

Manual arrows can be used to point values in the scale using arrows.

 1# ex_axes_7_1.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10.0,
 5            'function': lambda u: u,
 6            'title': r'\bf title',
 7            'tick_levels': 2,
 8            'tick_text_levels': 1,
 9            'tick_side': 'left',
10            'scale_type': 'manual line',
11            'manual_axis_data': {1.0: 'one',
12                                 2.0: 'two',
13                                 3.0: 'three',
14                                 3.1415: r'$\pi$',
15                                 4.0: 'four',
16                                 5.0: 'five',
17                                 6.0: 'six',
18                                 7.0: 'seven',
19                                 8.0: 'eight',
20                                 9.0: 'nine',
21                                 10.0: 'ten'},
22            'extra_params': [{'u_min': 1.0,
23                              'u_max': 10.0,
24                              'scale_type': 'linear',
25                              'tick_levels': 3,
26                              'tick_text_levels': 2,
27                              'tick_side': 'right',
28                              'extra_angle': 90.0,
29                              'text_horizontal_align_center': True,
30                              'text_format': r"$%2.1f$"},
31                             {'scale_type': 'manual arrow',           # <-
32                              'manual_axis_data': {6.2830: r'$2\pi$',
33                                                   9.4245: r'$3\pi$'},
34                              'arrow_color': color.cmyk.Sepia,
35                              'arrow_length': 2.0,
36                              'text_color': color.cmyk.Sepia,
37                              }]
38            }
39block_params = {'block_type': 'type_8',
40                'f_params': N_params,
41                'width': 5.0,
42                'height': 10.0,
43                }
44main_params = {'filename': 'ex_axes_7_1.pdf',
45               'paper_height': 10.0,
46               'paper_width': 5.0,
47               'block_params': [block_params],
48               'transformations': [('scale paper',)]
49               }
50Nomographer(main_params)
../_images/ex_axes_7_1.png

Manual function ('function_x' and 'function_y')

If one wants to explicitely draw scale in xy-scace, parameters 'function_x' and 'function_y' can be used in conjuction with block type 8. In the following example circular scale is drawn.

 1# ex_axes_8.py
 2
 3N_params = {'u_min': 0.0,
 4            'u_max': 300.0,
 5            'function_x': lambda u: 3 * sin(u / 180.0 * pi),
 6            'function_y': lambda u: 3 * cos(u / 180.0 * pi),
 7            'title': 'u',
 8            'tick_levels': 3,
 9            'tick_text_levels': 1,
10            'title_x_shift': -0.5,
11            }
12block_params = {'block_type': 'type_8',
13                'f_params': N_params,
14                'width': 5.0,
15                'height': 15.0,
16                }
17main_params = {'filename': 'ex_axes_8.pdf',
18               'paper_height': 10.0,
19               'paper_width': 10.0,
20               'block_params': [block_params],
21               'transformations': [('scale paper',)]
22               }
23Nomographer(main_params)
../_images/ex_axes_8.png

In the following we fine-tune the appearance of the scale. Tick lengths are explicitly given with params 'grid_length_x' (note name with bad logic), text sizes are tuned with params 'text_size_x' and distance of text to the scale is set using 'text_distance_x'. 'full_angle' parameter allows text to be drawn also upside down and text angle is rotated with 'extra_angle'.

 1# ex_axes_8_1.py
 2
 3N_params = {'u_min': 0.0,
 4            'u_max': 300.0,
 5            'function_x': lambda u: 3 * sin(u / 180.0 * pi),
 6            'function_y': lambda u: 3 * cos(u / 180.0 * pi),
 7            'title': 'u',
 8            'tick_levels': 3,
 9            'tick_text_levels': 1,
10            'title_x_shift': -0.5,
11            'grid_length_0': 0.8/4,
12            'grid_length_1': 0.6/4,
13            'grid_length_2': 0.5/4,
14            'grid_length_3': 0.4/4,
15            'grid_length_4': 0.3/4,
16            'text_size_0': text.size.tiny,
17            'text_size_1': text.size.tiny,
18            'text_size_2': text.size.tiny,
19            'text_size_3': text.size.tiny,
20            'text_size_4': text.size.tiny,
21            'text_distance_0': 1.2/4,
22            'text_distance_1': 1.1/4,
23            'text_distance_2': 1.0/4,
24            'text_distance_3': 1.0/4,
25            'text_distance_4': 1.0/4,
26            'title_distance_center': 0.7,
27            'title_opposite_tick': True,
28            'title_draw_center': True,
29            'text_format': "$%3.1f$",
30            'full_angle': True,
31            'extra_angle': 90.0,
32            'text_horizontal_align_center': True,
33            'text_format': r"$%2.0f$",
34            'text_color': color.cmyk.Sepia,
35            }
36block_params = {'block_type': 'type_8',
37                'f_params': N_params,
38                'width': 5.0,
39                'height': 15.0,
40                }
41main_params = {'filename': 'ex_axes_8_1.pdf',
42               'paper_height': 10.0,
43               'paper_width': 10.0,
44               'block_params': [block_params],
45               'transformations': [('scale paper',)]
46               }
47Nomographer(main_params)
../_images/ex_axes_8_1.png

Linear scale ('scale_type':'log')

Often one needs to use logarithmic functions in scales and 'scale_type':'log' makes some optimizations for this kind of scale appearance.

 1# ex_axes_9.py
 2
 3N_params = {'u_min': 1.0,
 4            'u_max': 10000.0,
 5            'function': lambda u: log(u),
 6            'title': 'u',
 7            'scale_type': 'log',
 8            }
 9block_params = {'block_type': 'type_8',
10                'f_params': N_params,
11                'width': 5.0,
12                'height': 15.0,
13                }
14main_params = {'filename': 'ex_axes_9.pdf',
15               'paper_height': 15.0,
16               'paper_width': 5.0,
17               'block_params': [block_params],
18               'transformations': [('scale paper',)]
19              }
20Nomographer(main_params)
../_images/ex_axes_9.png

Smart scales ('scale_type':'smart linear', 'scale_type':'smart log')

Linear and log scales just plot ticks and texts as given with params 'tick_levels' and 'tick_text_levels'. Often this approach generates busy scales with overlapping texts and too dense ticks. Better approach is to use smart linear scales 'scale_type':'smart linear' or smart log scales 'scale_type':'smart log' These scales check that tick and text distances does not go below given thresholds ('tick_distance_smart' and 'text_distance_smart'. TODO: example to use smart scales.

Common axis params

Common axis params

parameter

default value

explanation

'ID'

'none'

String. To identify the axis.

'tag'

'none'

String. To align blocks w.r.t each other along axes with same tag.

'dtag'

'none'

String. To double-align blocks w.r.t each other along axes with same tag.

'title'

''

String. Axis title.

'title_x_shift'

0.0

Float. Title shift in x-direction.

'title_y_shift'

0.25

Float. Title shift in y-direction.

'scale_type'

'linear'

String. Scale type. Can be 'linear': linear scale. 'log': logarithmic scale. 'smart linear': linear scale with equal spacings. 'smart log': logarithmic scale with equal spacings, can also have negative values. 'manual point': Points and corresponding text positions are given manually in 'manual axis data'. No line is drawn. 'manual line': Ticks and corresponding text positions are given manually in 'manual axis data'.

'tick_levels'

4

Integer. How many levels (minor, minor-minor, etc.) of ticks are drawn. Largest effect to ‘linear’ scale.

'tick_text_levels'

'3'

Integer. How many levels (minor, minor-minor, etc.) of texts are drawn. Largest effect to ‘linear’ scale.

'tick_side'

'right'

String. Tick and text side in final paper. Can be: 'right' or 'left'.

'reference'

False

Boolean. If axis is treated as reference line that is a turning point.

'reference_padding'

'0.2'

Float. Fraction of reference line over other lines.

'manual_axis_data'

{}

Dict. Manually set tick/point positions and text positions. Could be for example:{1:'1', 3.14:r'$\pi$', 5:'5', 7:'seven', 10:'10'}

'title_draw_center'

False

Boolean. Title is drawn to center of line.

'title_distance_center'

'0.5'

Float. When 'title_draw_center' is 'True' sets distance of title from axis.

'title_opposite_tick'

True

Boolean. Title in opposite direction w.r.t ticks.

'align_func'

lambda u:u

func(u). function to align different scales.

'align_x_offset'

0.0

Float. If axis is aligned with other axis, this value x offsets final scale.

'align_y_offset'

0.0

Float. If axis is aligned with other axis, this value y offsets final scale.

'text_format'

r'$%4.4g$ '

String. Format for numbers in scale.

'extra_params'

[{},...]

Array of Dicts. List of dictionary of params to be drawn additionally.

'text_distance_#'

x.x

Float. where #=0,1,2,3 or 4. Distance of text from scale line. Number corresponds to the level, where 0 is the major tick and 4 is the most minor ticks.

'grid_length_#'

x.x

Float. where #=0,1,2,3 or 4. Length of the tick. Number corresponds to the level, where 0 is the major tick and 4 is the most minor ticks.

'text_size_#'

x.x

Where #=0,1,2,3 or 4. Text size for linear scale specified by parameter. For example: text.size.small, text.size.scriptsize or text.size.tiny. Number corresponds to the level, where 0 is the major tick and 4 is the most minor ticks.

'text_size_log_#'

x.x

Where #=0,1 or 2. Text size for log scale specified by parameter. For example: text.size.small, text.size.scriptsize or text.size.tiny . Number corresponds to the level, where 0 is the major tick and 2 is the most minor ticks.

'full_angle'

False

Boolean. If true, text can be upside down, otherwise +- 90 degrees from horizontal. Good foor example for full circle scales.

'extra_angle'

0.0

Float. Angle to rotate tick text from horizontal along tick.

'text_horizontal_align_center'

False

Boolean. Aligns tick text horizontally to center. Good when text rotated 90 degrees.

'turn_relative'

False

Boolean. Side left or right is relative according to traveling of scale from min to max.

'arrow_size'

0.2

Float. Used with arrow scale.

'arrow_length'

1.0

Float. Used with arrow scale..

'arrow_color'

color.rgb.black

Color. Used with arrow scale.

'axis_color'

color.rgb.black

Color. Color of axis.

'text_color'

color.rgb.black

Color. Color of tick texts.

'extra_titles'

[]

Array. List of extra title dicts for scale. Could be i.e.``[{‘dx’:1.0, ‘dy’:1.0, ‘text’:’extra title 1’, ‘width’:5, ‘pyx_extra_defs’: [color.rgb.red,text.size.Huge]}, {‘text’: ‘extra title 2’}]``.

'base_start'

None

None/Float. Defines number with 'base_stop' (instead of 'u_min' or 'u_max') to find major tick decades.

'base_stop'

None

None/Float. Defines number with 'base_start' (instead of 'u_min' or 'u_max') to find major tick decades.

'tick_distance_smart'

.05

Float. Minimum distance between smart ticks.

'text_distance_smart'

.25

Float. Minimum distance between smart texts.