BOKEH_TOOLS = 'pan,wheel_zoom,box_zoom,reset,resize'
BIT_DEPTH = 12
MINIMUM_REPRESENTABLE_VALUE = 1 / 2 ** BIT_DEPTH
MAXIMUM_REPRESENTABLE_VALUE = 1
def solve_EV_range(function,
minimum_representable_value=MINIMUM_REPRESENTABLE_VALUE,
maximum_representable_value=MAXIMUM_REPRESENTABLE_VALUE,
**kwargs):
EV_min = fsolve(lambda x: function(2 ** x, **kwargs) - minimum_representable_value, 0)
EV_max = fsolve(lambda x: function(2 ** x, **kwargs) - maximum_representable_value, 0)
EV_neutral_gray = fsolve(lambda x: function(2 ** x, **kwargs) - 0.18, 0)
EV_domain = np.arange(np.floor(EV_min), np.ceil(EV_max) + 1)
EV_range = function(2 ** EV_domain, **kwargs)
return colour.Structure(
**{'EV_domain': EV_domain.astype(np.int_),
'EV_range': EV_range,
'EV_min': EV_min,
'EV_max': EV_max,
'EV_neutral_gray': EV_neutral_gray})
def dynamic_range_plot(function,
minimum_representable_value=MINIMUM_REPRESENTABLE_VALUE,
maximum_representable_value=MAXIMUM_REPRESENTABLE_VALUE,
**kwargs):
solve_r = solve_EV_range(
function,
minimum_representable_value,
maximum_representable_value,
**colour.filter_kwargs(function, **kwargs))
settings = colour.Structure(
**{'title': None,
'width': 720,
'height': 405,
'x_range': None,
'y_range': None,
'y_axis_location' : 'right',
'toolbar_location': 'left',
'toolbar_sticky': False,
'tools': BOKEH_TOOLS})
settings.update({(key, value) for key, value in kwargs.items()
if key in settings})
plot = figure(**settings)
plot.xaxis.axis_label = 'Dynamic Range (EV)'
plot.xaxis.major_tick_line_width = 8
EV_rectangle = plot.rect(
solve_r.EV_domain, solve_r.EV_range, width=0.5, height=0.01)
neutral_gray_line = plot.line(
(-64, 64), np.ones(2) * 0.18, line_width=2, line_dash=[8, 2])
data = {'Metric': ('Minimum EV',
'Maximum EV',
'EV < 18%',
'EV > 18%'),
'Value':(solve_r.EV_min,
solve_r.EV_max,
solve_r.EV_min - solve_r.EV_neutral_gray,
solve_r.EV_max - solve_r.EV_neutral_gray)}
source = ColumnDataSource(data)
columns = [TableColumn(field='Metric', title='Metric'),
TableColumn(field='Value', title='Value')]
table = DataTable(source=source,
columns=columns,
row_headers=False,
width=int(settings.width / 3))
handle = show(row(plot, table), notebook_handle=True)
return colour.Structure(
**{'EV_rectangle': EV_rectangle,
'table': table,
'handle': handle})
def update_dynamic_range_plot(structure, function, **kwargs):
solve_r = solve_EV_range(function, **kwargs)
structure.EV_rectangle.data_source.data['x'] = solve_r.EV_domain
structure.EV_rectangle.data_source.data['y'] = solve_r.EV_range
structure.table.source.data = {
'Metric': ('Minimum EV',
'Maximum EV',
'EV < 18%',
'EV > 18%'),
'Value':(solve_r.EV_min,
solve_r.EV_max,
solve_r.EV_min - solve_r.EV_neutral_gray,
solve_r.EV_max - solve_r.EV_neutral_gray)}
push_notebook(handle=structure.handle)