Examples

In the following are listed examples to show nomographs possibilities. Also is explained the background for the cases and underlying math for the nomograph construction. Source code shows the implementation.

Example: Amortized loan calculator

Theory and background

This approach of constructing an amortized loan calculator is similar to one in Ref. [1]_

Equation for amortized loan [2]_ is:

\(\frac{a}{A} = \frac{\frac{p}{100\times 12}}{1-\frac{1}{(1+\frac{p}{100\times 12})^{12n}}},\)

where \(A\) is the amount of loan, \(a\) is monthly payment amount, \(p\) interest rate per year (monthly interest rate is taken as \(p/12\)) 3 and \(n\) is number of years for payment.

This equation of four variables is probably impossible to present with line and grid nomographs. For this reason a “Type 5” contour nomogram is constructed of the right hand side of the equation and left hand equation is just N-nomogram (Type 2). The two equations for nomogram construction are:

\(x = \frac{a}{A}\)

and

\(x = \frac{\frac{p}{100\times 12}}{1-\frac{1}{(1+\frac{p}{100\times 12})^{12n}}}.\)

In practice \(x\) is the x-coordinate of the canvas where nomogram is constructed.

Right hand side of equation

By defining coordinates \(x\,\) and \(y\,\):

\(x = \frac{\frac{p}{100\times 12}}{1-\frac{1}{(1+\frac{p}{100\times 12})^{12n}}},\)

\(y = 12n, \,\) we may solve \(y\,\) in terms of \(x\,\) and \(n\,\):

\(y = \frac{\log (\frac{x}{x-\frac{p}{100\times 12}})}{\log (1+\frac{p}{100 \times 12})} \,\)

The previous two equations are of correct form

\(y = f_1(v) \,\)

and

\(y = f_2(x,u) \,\)

for type 5 nomogram. For compressing time axis (\(y\)-axis), we transform \(y \rightarrow \log y\) and find

\(y = \log \left( \frac{\log (\frac{x}{x-\frac{p}{100\times 12}})}{\log (1+\frac{p}{100 \times 12})} \right)\,\)

\(y = \log( 12n ). \,\)

Left hand side of equation

Left hand side of equation

\(x = \frac{a}{A}\)

is just N-nomogram

\(F_1(u_1) = F_2(u_2)F_3(u_3) \,\)

References

Generated nomograph

../_images/amortized_loan.png

Source code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
    ex_amortized_loan.py

    Amortized loan calculator
"""
import sys
sys.path.insert(0, "..")
from pynomo.nomographer import *

# Type 5 contour
def f1(x,u):
    return log(log(x/(x-u/(100.0*12.0)))/log(1+u/(100.0*12.0)))

block_1_params={
            'width':10.0,
           'height':5.0,
           'block_type':'type_5',
           'u_func':lambda u:log(u*12.0),
           'v_func':f1,
           'u_values':[10.0,11.0,12.0,13.0,14.0,15.0,20.0,25.0,30.0,40.0,50.0,60.0],
           'v_values':[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0],
           'wd_tag':'A',
           'u_title':'years',
           'v_title':r'interest rate = ',
           'u_text_format':r"$%3.0f$ ",
           'v_text_format':r"$%3.0f$ \%% ",
           'isopleth_values':[[21,5,'x']]
             }

# this is non-obvious trick to find bottom edge coordinates of the grid in order
# to align it with N nomogram
block1_dummy=Nomo_Block_Type_5(mirror_x=False)
block1_dummy.define_block(block_1_params)
block1_dummy.set_block()

# Let's define the N-nomogram
N_params_3={
        'u_min':block1_dummy.grid_box.params_wd['u_min'],
        'u_max':block1_dummy.grid_box.params_wd['u_max'],
        'function':lambda u:u,
        'title':'',
        'tag':'A',
        'tick_side':'right',
        'tick_levels':2,
        'tick_text_levels':2,
        'reference':False,
        'tick_levels':0,
        'tick_text_levels':0,
        'title_draw_center':True
                }
N_params_2={
        'u_min':30.0,
        'u_max':1000.0,
        'function':lambda u:u,
        'title':'Loan',
        'tag':'none',
        'tick_side':'left',
        'tick_levels':4,
        'tick_text_levels':3,
        'title_draw_center':True,
        #'text_format':r"$%3.0f$ ",
        'scale_type':'linear smart',
                }
N_params_1={
        'u_min':0.2,
        'u_max':3.0,
        'function':lambda u:u,
        'title':'monthly payment',
        'tag':'none',
        'tick_side':'right',
        'tick_levels':3,
        'tick_text_levels':2,
        'title_draw_center':True
                }

block_2_params={
             'block_type':'type_2',
             'width':10.0,
             'height':20.0,
             'f1_params':N_params_1,
             'f2_params':N_params_2,
             'f3_params':N_params_3,
             'isopleth_values':[['x',200,'x']]
             }

main_params={
              'filename':'amortized_loan.pdf',
              'paper_height':20.0,
              'paper_width':20.0,
              'block_params':[block_1_params,block_2_params],
              'transformations':[('rotate',0.01),('scale paper',)],
                'title_str':r'Amortized loan calculator    \copyright    Leif Roschier  2009',
                'title_x': 17,
                'title_y': 21,
                'title_box_width': 5
              }
Nomographer(main_params)
1

d’Ocagne: Traite nomographie, 1899

2

http://en.wikipedia.org/w/index.php?title=Amortization_calculator&oldid=220083943

3

https://en.wikipedia.org/wiki/Annual_percentage_rate

Example Photography exposure

Theory and background

This example illustrates how exposure in photography depends on factors: latitude, time of day, day of year, weather, composition. It relates these to camera settings: film speed (e.g. ISO 100), aperture and shutter speed. The mathematical approach and model is taken from book written by V. Setälä. [1]_ This book illustrates the approach as nomographs but they are different compared with the one generatated here. Book uses shadow length, but we break shadow length into time, date and latitude via solar zenith angle.

The basic equation in Setälä (pp.492-494) can be extracted and written as

(1)\[FS-L-A-W+C+T=0 \,\]

where parameters of (1) are listed below:

\(FS\,\)

Film speed

DIN value that equals \(10 \log (S) +1 \,\),where S is ISO FILM speed

\(T\,\)

shutter time

\(10 \log \left( \frac{t}{1/10}\right)\)

\(A\,\)

aperture

\(10 \log \left(\frac{N^2}{3.2^2}\right)\)

\(L\,\)

shadow length (in steps)

two times (shadow length)/(person length) \(= 2 \arctan ( \phi) \,\), where \(\phi \,\) is solar zenith angle.

\(W\,\)

weather

Clear sky, Cumulus clouds: 0, Clear sky: 1, Sun through clouds: 3, Sky light gray: 6, Sky dark gray: 9, Thunder-clouds cover sky: 12

\(C\,\)

Composition

Person under trees: -6, Inside forest : -4, Person in shadow of wall : -1, Person at open place; alley under trees : 2, Buildings; street : 5, Landscape and front matter : 7, Open landscape : 9, Snow landscape and front matter; beach : 11,Snow field; open sea : 13, Clouds : 15

It is to be noted that Setälä has stops ten times base-10 logarithmic. Today we think stops in base-2 logarithmic.

Shadow lenght

Calculation of shadow length as a function of day of year, time of day and latitude is according to [2]_. Following equations are used. For fractional year (without time information) we take

\(\gamma = (day-1+0.5)2\pi /365.\)

For time offset (eqtime) we use equation (in minutes)

\(TO = 229.18(0.000075+0.001868\cos(\gamma)-0.032077\sin(\gamma)-0.014615\cos(2\gamma)-0.040849\sin(2\gamma))\)

to calculate that error is below 17 minutes for time axis. We assume that sun is at heightest point at noon and this is the error and approximation. We calculate stops in logarithmic scale and in this case we do not need very accurate equations for time. For declination we use equation

and for hour angle

\(ha=(60h+\overline{TO})/4-180. \,\)

Solar zenith angle (\(\phi \,\)), latitude (LAT), declination (D) and hour angle (ha) are connected with equation:

\(\cos (\phi ) = \sin(LAT)sin(D)+\cos(LAT)\cos(D)\cos(ha). \,\)

This is in our desired form as a function of hour (h), day (day), latitude (LAT), solar zenith angle (\(\phi \,\)):

\(\cos (\phi ) = \sin(LAT)sin(D(\gamma(day)))+\cos(LAT)\cos(D(\gamma(day)))\cos(ha(h)) \,\).

In practice illuminance of flat surface on earth depends on solar zenith angle as \(\cos(\phi)\,\). Setälä uses shadow length that is easily measurable, but scales incorrectly, as value is proportional to \(\tan(\phi)\,\). Also Setälä sums linear value with logarithmic ones as a practical approximation. To correct these assumptions, here we assume that values for shadow length 1 and 10 for Setälä are reasonable, and an equation that scales logarithmically is found:

\(L = 0.33766 - 13.656 \log10 (\cos(\phi)) \,\)

that gives \(L=1\,\) for \(\phi = 26.565 =\arctan(1/2)\,\) and \(L=10\,\) for \(\phi = 78.69 =\arctan(10/2).\,\)

1

Vilho Setälä: “Valokuvaus”, Otava 1940.

2

https://www.esrl.noaa.gov/gmd/grad/solcalc/solareqns.PDF

Construction of the nomograph

The presented equation is the following:

\begin{eqnarray*} FS - \{0.33766 - 13.656 \log_{10}[ \sin (LAT)\sin (D(\gamma(day)))+\cos (LAT)\cos (D(\gamma(day)))\cos (ha(h))]\}\\ - A - W + C + T = 0. \end{eqnarray*}

In order to construct the nomograph, we split the equation into four blocks and an additional block to present values as EV100.

Main equation split into blocks for the nomograph.

Explanation

Type

\[x_1 \equiv \cos(\phi)=\sin(LAT)sin(D(\gamma(day)))+\cos(LAT)\cos(D(\gamma(day)))\cos(ha(h))\,\]

formed into determinant:

\[\begin{split}{{ \begin{vmatrix} 0 & \cos(\phi) & 1 \\ \frac{\cos(LAT)\cos(D(\gamma(day)))}{1+(\cos(LAT)\cos(D(\gamma(day))))} & \frac{\sin(LAT)\sin(D(\gamma(day)))}{1+(\cos(LAT)\cos(D(\gamma(day))))} & 1 \\ 1 & -\cos(ha(h)) & 1 \\ \end{vmatrix} = 0 }}\end{split}\]

Type 9

\[C_1 \equiv L+W = 0.006918-13.656 \log_{10}(x_1)+W\]

split into two equations for contour construction:

\[y_1 = C_1 \,\]
\[y_1 = 0.006918-13.656 \log_{10}(x_1)+W\]

Type 5

\[C_2 \equiv L+W+C = C_1+C\]

split into two equations for contour construction:

\[y_2 = C_2\]
\[y_2 = C_1+C\]

Type 5

\[C_2 = FS-A+T\]

equals

\[C_2 -(10 \log_{10}(S)+1.0)+10 \log_{10}\left(\frac{N^2}{3.2^2} \right)-10 \log_{10}\left( \frac{1/t_i}{1/10}\right)=0,\]

where

\[t_i\equiv 1/t\]

is inverse shutter time.

Type 3

Additional EV100 scale by using relation

\[C_2 =(-EV_{100}+13.654)/0.3322\]

Type 8

Maximum focal length calculator according to equation

\[t_i / f = FL\]

written as

\[-10 \log_{10}\left( \frac{1/t_i}{1/10}\right) - 10 \log_{10}\left( \frac{f}{10} \right) -10 \log_{10}\left( FL \right) = 0\]

in order to align correctly with previous equation. The values for the factor f are: DSLR (3/2), 35mm (1), DSLR image stabilization (3/8) and 35mm image stabilization (1/8).

Type 1

Generated nomograph

../_images/ex_photo_exposure.png

Source code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
"""
    ex_photo_exposure.py

    Photgraph exposure.
"""
import sys
sys.path.insert(0, "..")
from pynomo.nomographer import *
"""
functions for solartime taken from solareqns.pdf from
http://www.srrb.noaa.gov/highlights/sunrise/solareqns.PDF
"""


# fractional year
def gamma(day):
    return 2 * pi / 365.0 * (day - 1 + 0.5)
# equation of time


def eq_time(day):
    gamma0 = gamma(day)
    return 229.18 * (0.000075 + 0.001868 * cos(gamma0) - 0.032077 * sin(gamma0)\
                   - 0.014615 * cos(2 * gamma0) - 0.040849 * sin(2 * gamma0))

# mean correction, with constant correction we make less than 17 minutes  error
# in time axis
temp_a = arange(0, 365.0, 0.1)
temp_b = eq_time(temp_a)
correction = mean(temp_b) # this is 0.0171885 minutes


# declination
def eq_declination(day):
    g0 = gamma(day)
    return 0.006918 - 0.399912 * cos(g0) + 0.070257 * sin(g0) - 0.006758 * cos(2 * g0)\
            + 0.000907 * sin(2 * g0) - 0.002697 * cos(3 * g0) + 0.00148 * sin(3 * g0)


def f1(dummy):
    return 0.0


def g1(fii):
    return cos(fii*pi/180.0)


def f2(lat, day):
    dec = eq_declination(day)
    return (cos(lat * pi / 180.0) * cos(dec)) / (1.0 + (cos(lat * pi / 180.0) * cos(dec)))


def g2(lat, day):
    dec = eq_declination(day)  # in radians
    return (sin(lat * pi / 180.0) * sin(dec)) / (1.0 + (cos(lat * pi / 180.0) * cos(dec)))


def f3(dummy):
    return 1


def g3(h):
    hr = (h * 60.0 + correction) / 4.0 - 180.0
    return -1.0 * cos(hr * pi / 180.0)

days_in_month = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
times1=[]
for idx in range(0, 12):
    times1.append(sum(days_in_month[0:idx])+1)

time_titles = ['January', 'February', 'March', 'April', 'May', 'June',
               'July', 'August', 'September', 'October', 'November', 'December']

phi_params = {'u_min': 0.0,
              'u_max': 90.0,
              'u_min_trafo': 0.0,
              'u_max_trafo': 90.0,
              'f': f1,
              'g': g1,
              'h': lambda u: 1.0,
              'title': r'Solar zenith angle $\phi$',
              'title_x_shift': 0.0,
              'title_y_shift': 0.25,
              'scale_type': 'linear smart',
              'tick_levels': 4,
              'tick_text_levels': 2,
              'tick_side': 'right',
              'tag': 'phi',
              'grid': False,
              }
time_params = {'u_min': 0.0,
               'u_max': 23.0,
               'u_min_trafo': 0.0,
               'u_max_trafo': 12.0,
               'f': f3,
               'g': g3,
               'h':lambda u: 1.0,
               'title': r'Hour (h)',
               'title_x_shift': 0.0,
               'title_y_shift': 0.25,
               'scale_type': 'linear',
               'tick_levels': 2,
               'tick_text_levels': 1,
               'tick_side': 'right',
               'tag': 'none',
               'grid': False,
               }
lat_day_params = {'ID': 'none',  # to identify the axis
                  'tag': 'none',  # for aligning block wrt others
                  'title': 'Grid',
                  'title_x_shift': 0.0,
                  'title_y_shift': 0.25,
                  'title_distance_center': 0.5,
                  'title_opposite_tick': True,
                  'u_min': 20.0,  # for alignment
                  'u_max': 80.0,  # for alignment
                  'f_grid': f2,
                  'g_grid': g2,
                  'h_grid': lambda u, v: 1.0,
                  'u_start': 30.0,
                  'u_stop': 80.0,
                  'v_start': times1[0],  # day
                  'v_stop': times1[-1],
                  'u_values': [30.0, 40.0, 50.0, 60.0, 70.0, 80.0],
                  'u_texts': ['30', '40', '50', 'Latitude = 60', '70', '80'],
                  'v_values': times1,
                  'v_texts': time_titles,
                  'grid': True,
                  'text_prefix_u': r'',
                  'text_prefix_v': r'',
                  'text_distance': 0.5,
                  'v_texts_u_start': False,
                  'v_texts_u_stop': True,
                  'u_texts_v_start': False,
                  'u_texts_v_stop': True,
                  }
block_params = {'block_type': 'type_9',
                'f1_params': phi_params,
                'f2_params': lat_day_params,
                'f3_params': time_params,
                'transform_ini': True,
                'isopleth_values': [['x', [60, times1[4]], 14.0]]
                }


# limiting functions are to avoid NaN in contour construction that uses optimization
def limit_xx(x):
    x1 = x
    return x1


def limit_x(x):
    x1 = x
    return x1

const_A = 0.33766
const_B = -13.656

block_params_weather = {'block_type': 'type_5',
                        'u_func': lambda u: u,
                        'v_func':lambda x, v: const_A + const_B * log10(limit_x(x)) + v,
                        'u_values': [1.0, 25.0],
                        'u_manual_axis_data': {1.0: '',
                                               25.0: ''},
                        'v_values': [0.0, 1.0, 3.0, 6.0, 9.0, 12.0],
                        'v_manual_axis_data': {0.0: ['Clear sky, Cumulus clouds',
                                                     {'x_corr': 0.5,
                                                      'y_corr': 0.0,
                                                      'draw_line': False}],
                                               1.0: 'Clear sky',
                                               3.0: 'Sun through clouds',
                                               6.0: 'Sky light gray',
                                               9.0: 'Sky dark gray',
                                               12.0: 'Thunder-clouds cover sky'},
                        'v_text_distance': 0.5,
                        'wd_tick_levels': 0,
                        'wd_tick_text_levels': 0,
                        'wd_tick_side': 'right',
                        'wd_title': '',
                        'manual_x_scale': True,
                        'x_min': 0.06,
                        'x_max': 0.99,
                        'u_title': '',
                        'v_title': '',
                        'wd_title_opposite_tick': True,
                        'wd_title_distance_center': 2.5,
                        'wd_align_func': lambda L: acos(limit_xx(10.0**((L - const_A) / const_B))) * 180.0 / pi,  # phi as L
                        'wd_func': lambda L: 10.0**((L - const_A) / const_B),  # x as L
                        'wd_func_inv': lambda x: const_A+const_B * log10(x),  # L as x
                        'wd_tag': 'phi',
                        'mirror_y': True,
                        'mirror_x': False,
                        'width': 10.0,
                        'height': 10.0,
                        'u_scale_opposite': True,
                        'u_tag': 'AA',
                        'horizontal_guides': True,
                        'isopleth_values': [['x', 9.0, 'x']],
                        }
block_params_scene = {'block_type': 'type_5',
                      'u_func': lambda u: u,
                      'v_func': lambda x, v: x + v,
                      'u_values': [1.0, 25.0],
                      'u_manual_axis_data': {1.0: '',
                                             25.0: ''},
                      'u_tag': 'AA',
                      'wd_tag': 'EV',
                      'v_values': [-4.0, -1.0, 2.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0],
                      'v_manual_axis_data': {-6.0: 'Person under trees',
                                             -4.0: 'Inside forest',
                                             -1.0: 'Person in shadow of wall',
                                             2.0: 'Person at open place; alley under trees',
                                             5.0: 'Buildings; street',
                                             7.0: 'Landscape and front matter',
                                             9.0: 'Open landscape',
                                             11.0: 'Snow landscape and front matter; beach',
                                             13.0: 'Snow field; open sea',
                                             15.0: 'Clouds',
                                             },
                      'wd_tick_levels': 0,
                      'wd_tick_text_levels': 0,
                      'wd_tick_side': 'right',
                      'wd_title': '',
                      'u_title': '',
                      'v_title': '',
                      'wd_title_opposite_tick': True,
                      'wd_title_distance_center': 2.5,
                      'mirror_x': True,
                      'horizontal_guides': True,
                      'u_align_y_offset': -0.9,
                      'isopleth_values': [['x', 2.0, 'x']],
                      }
camera_params_1 = {'u_min': -10.0,
                   'u_max': 15.0,
                   'function': lambda u: u,
                   'title': r'',
                   'tick_levels': 0,
                   'tick_text_levels': 0,
                   'tag': 'EV',
                   }
camera_params_2 = {'u_min': 10.0,
                   'u_max': 25600.0,
                   'function': lambda S: -(10 * log10(S) + 1.0),
                   'title': r'Film speed',
                   'manual_axis_data': {10.0: 'ISO 10',
                                        20.0: 'ISO 20',
                                        50.0: 'ISO 50',
                                        100.0: 'ISO 100',
                                        200.0: 'ISO 200',
                                        400.0: 'ISO 400',
                                        800.0: 'ISO 800',
                                        1600.0: 'ISO 1600',
                                        3200.0: 'ISO 3200',
                                        6400.0: 'ISO 6400',
                                        12800.0: 'ISO 12800',
                                        25600.0: 'ISO 25600',
                                        },
                   'scale_type': 'manual line'
                   }
camera_params_3 = {'u_min': 0.1,
                   'u_max': 10000.0,
                   'function': lambda t: -10 * log10((1.0 / t) / (1.0 / 10.0)) - 30,
                   'manual_axis_data': {1/10.0: '10',
                                        1/7.0: '7',
                                        1/5.0: '5',
                                        1/3.0: '3',
                                        1/2.0: '2',
                                        1.0: '1',
                                        2.0: '1/2',
                                        3.0: '1/3',
                                        5.0: '1/5',
                                        7.0: '1/7',
                                        10.0: '1/10',
                                        20.0: '1/20',
                                        30.0: '1/30',
                                        50.0: '1/50',
                                        70.0: '1/70',
                                        100.0: '1/100',
                                        200.0: '1/200',
                                        300.0: '1/300',
                                        500.0: '1/500',
                                        700.0: '1/700',
                                        1000.0: '1/1000',
                                        2000.0: '1/2000',
                                        3000.0: '1/3000',
                                        5000.0: '1/5000',
                                        7000.0: '1/7000',
                                        10000.0: '1/10000',
                             },
                   'scale_type': 'manual line',
                   'title': r't (s)',
                   'text_format': r"1/%3.0f s",
                   'tag': 'shutter',
                   'tick_side': 'left',
                   }
camera_params_4 = {'u_min': 1.0,
                   'u_max': 22.0,
                   'function': lambda N: 10 * log10((N / 3.2)**2) + 30,
                   'manual_axis_data': {1.0: '$f$/1',
                                        1.2: '$f$/1.2',
                                        1.4: '$f$/1.4',
                                        1.7: '$f$/1.7',
                                        2.0: '$f$/2',
                                        2.4: '$f$/2.4',
                                        2.8: '$f$/2.8',
                                        3.3: '$f$/3.3',
                                        4.0: '$f$/4',
                                        4.8: '$f$/4.8',
                                        5.6: '$f$/5.6',
                                        6.7: '$f$/6.7',
                                        8.0: '$f$/8',
                                        9.5: '$f$/9.5',
                                        11.0 :'$f$/11',
                                        13.0 :'$f$/13',
                                        16.0 :'$f$/16',
                                        19.0 :'$f$/19',
                                        22.0 :'$f$/22',
                                        },
                   'scale_type': 'manual line',
                   'title': r'Aperture',
                   }
block_params_camera = {'block_type': 'type_3',
                       'width': 10.0,
                       'height': 10.0,
                       'f_params': [camera_params_1, camera_params_2, camera_params_3,
                                    camera_params_4],
                       'mirror_x': True,
                       'isopleth_values': [['x', 100.0, 'x', 4.0]],
                       }


def old_EV(EV):  # C2(EV100) in wiki
    return (-EV + 13.654) / 0.3322

EV_para = {'tag': 'EV',
           'u_min': 4.0,
           'u_max': 19.0,
           'function': lambda u: old_EV(u),
           'title': r'EV$_{100}$',
           'tick_levels': 1,
           'tick_text_levels': 1,
           'align_func': old_EV,
           'title_x_shift': 0.5,
           'tick_side': 'right',
           }
EV_block = {'block_type': 'type_8',
            'f_params': EV_para,
            'isopleth_values': [['x']],
            }
# maximum focal length
FL_t_para={'u_min': 0.1,
           'u_max': 10000.0,
           'function': lambda t:-10 * log10((1.0 / t) / (1.0 / 10.0)) - 30,
           'scale_type': 'linear',
           'tick_levels': 0,
           'tick_text_levels': 0,
           'title': r't (s)',
           'text_format': r"1/%3.0f s",
           'tag': 'shutter',
           }
FL_factor_params_2 = {'u_min': 1.0/4.0,
                      'u_max': 3.0/2.0,
                      'function': lambda factor: -10 * log10(factor / 10.0) + 0,
                      'title': r'Sensor, IS',
                      'scale_type': 'manual point',
                      'manual_axis_data': {1.0/(2.0/3.0): 'DSLR',
                                           1.0/(1.0): '35mm',
                                           1.0/(8.0/3.0): 'DSLR IS',
                                           1.0/(4.0): '35mm IS',
                      },
                      'tick_side':'left',
                      'text_size_manual': text.size.footnotesize,  # pyx directive
                      }
FL_fl_params = {'u_min': 20.0,
                'u_max': 1000.0,
                'function': lambda FL:-10 * log10(FL) + 30,
                'title': r'Max focal length',
                'tick_levels': 3,
                'tick_text_levels': 2,
                'tick_side': 'left',
                'scale_type': 'manual line',
                'manual_axis_data': {20.0: '20mm',
                                     35.0: '35mm',
                                     50.0: '50mm',
                                     80.0: '80mm',
                                     100.0: '100mm',
                                     150.0: '150mm',
                                     200.0: '200mm',
                                     300.0: '300mm',
                                     400.0: '400mm',
                                     500.0: '500mm',
                                     1000.0: '1000mm'}
                }

FL_block_params = {'block_type': 'type_1',
                   'width': 12.0,
                   'height': 10.0,
                   'f1_params': FL_t_para,
                   'f2_params': FL_factor_params_2,
                   'f3_params': FL_fl_params,
                   'mirror_x': True,
                   'proportion': 0.5,
                   'isopleth_values': [['x', 1.0/(8.0/3.0), 'x']],
                   }

main_params = {'filename': ['ex_photo_exposure.pdf', 'ex_photo_exposure.eps'],
               'paper_height': 35.0,
               'paper_width': 35.0,
               'block_params': [block_params, block_params_weather, block_params_scene,
                                block_params_camera, EV_block, FL_block_params],
               'transformations': [('rotate', 0.01), ('scale paper',)],
               'title_x': 7,
               'title_y': 34,
               'title_box_width': 10,
               'title_str': r'\LARGE Photography exposure (Setala 1940) \par \copyright Leif Roschier  2009 '
              }
Nomographer(main_params)