Esempio n. 1
0
 def __init__(self):
     self.df = None
     self.df_col_headers = None
     self.filepath = TextInput()
     self.filepath.on_change('value', self.update_data)
     self.cols = None
     self.num_columns = Spinner(title="Number of columns", low=0, high=100, step=1, value=1, width=150)
     self.num_columns.on_change('value', self.update_num_columns)
     self.col_type_selectors = [Select(options=None)]
     self.col_selectors = [Select(options=self.df_col_headers)]
Esempio n. 2
0
    def __init__(self, name='', pg_type='Product'):

        self.name = TextInput(value=name, width=250)
        self.pg_type = pg_type

        self.num_attributes = Spinner(title="Number of attributes", low=1, high=100, step=1, value=1, width=150)
        self.num_attributes.on_change('value', self.update_attributes, self.update_attribute_selector)

        self.attributes = [Attribute()]
        self.attribute_selector = RadioButtonGroup(labels=['Attribute #1'], active=0)
Esempio n. 3
0
    def __init__(self):
        self.name = TextInput(value='Attribute name')

        self.sourcefile_options = ['', 'Tx data', 'Customer Master', 'Product master', 'Input manually']
        self.sourcefile = Select(value='', options=self.sourcefile_options)
        self.sourcefile.on_change('value', partial(self.update_sourcecolumns_options, cpq=None))
        self.sourcecolumns = Select(value='', options=[''])
        self.include_in_filters = CheckboxGroup(labels=[None], active=[0])

        self.configurations = [Configuration()]
        self.num_configs = Spinner(title="Number of configurations", low=1, high=200, step=1, value=1, width=150)
        self.num_configs.on_change('value', self.update_configs)
Esempio n. 4
0
class Attribute:
    def __init__(self):
        self.name = TextInput(value='Attribute name')

        self.sourcefile_options = ['', 'Tx data', 'Customer Master', 'Product master', 'Input manually']
        self.sourcefile = Select(value='', options=self.sourcefile_options)
        self.sourcefile.on_change('value', partial(self.update_sourcecolumns_options, cpq=None))
        self.sourcecolumns = Select(value='', options=[''])
        self.include_in_filters = CheckboxGroup(labels=[None], active=[0])

        self.configurations = [Configuration()]
        self.num_configs = Spinner(title="Number of configurations", low=1, high=200, step=1, value=1, width=150)
        self.num_configs.on_change('value', self.update_configs)

    def update_sourcefile(self, value='', cpq=None):
        self.sourcefile.value = value
        self.sourcefile.on_change('value', partial(self.update_sourcecolumns_options, cpq=cpq))
        self.set_sourcecolumns_options(cpq=cpq)

    def update_sourcecolumns_options(self, attr, old, new, cpq=None):
        """
        on_change event for changes in the sourcefile Select widget

        :param attr:
        :param old:
        :param new:
        :param cpq: Expects an instance of the PriceView class
        :return:
        """

        self.set_sourcecolumns_options(cpq=cpq)

    def set_sourcecolumns_options(self, cpq=None):
        col_options = None
        try:
            if self.sourcefile.value == 'Tx data':
                col_options = cpq.tx.df.columns.tolist()
            elif self.sourcefile.value == 'Customer Master':
                col_options = cpq.cust_master.df.columns.tolist()
            elif self.sourcefile.value == 'Product master':
                col_options = cpq.prod_master.df.columns.tolist()
        except AttributeError:
            pass

        self.sourcecolumns.options = col_options

    def update_configs(self, attr, old, new):
        """
        on_change event for changes in the num_configs Spinner
        """
        for i in range(new):
            if i + 1 > len(self.configurations):
                self.configurations.append(Configuration())
Esempio n. 5
0
    def __init__(self):

        title = Div(text="""<h1>Coin tossing simulation</h1>"""
                    """<p>Simulates the effects of tossing a coin """
                    """many times. Heads are scored 1 and tails 0. """
                    """The chart shows the cumlative mean, which """
                    """should go to 0.5 in 'the long run'. To use """
                    """the software, select the number of coin """
                    """tosses or press go to generate a fresh """
                    """data set.</p>""",
                    sizing_mode="""stretch_width""")

        self.tosses = 2000

        self.toss_count = Spinner(step=1,
                                  value=self.tosses,
                                  title="""Number of tosses""",
                                  sizing_mode="""stretch_width""")
        self.go = Button(label="Button",
                         button_type="""success""",
                         sizing_mode="""stretch_width""")

        chart = Figure(title='Cumulative mean of coin tosses',
                       x_axis_label='Number of tosses',
                       y_axis_label='Cumulative mean')
        self.cds = ColumnDataSource()
        self.make_means()
        chart.line(source=self.cds,
                   x='tosses',
                   y='means',
                   line_color='red',
                   line_width=4,
                   line_alpha=0.5)

        chart.title.text_font_size = '20px'
        chart.xaxis.axis_label_text_font_size = '15px'
        chart.xaxis.major_label_text_font_size = '15px'
        chart.yaxis.axis_label_text_font_size = '15px'
        chart.yaxis.major_label_text_font_size = '15px'

        title_bar = column(children=[title], sizing_mode="stretch_both")
        widget_bar = column(children=[self.toss_count, self.go],
                            sizing_mode='fixed',
                            width=250,
                            height=500)
        chart_row = row(children=[widget_bar, chart],
                        sizing_mode='stretch_both')
        self.layout = column(children=[title_bar, chart_row],
                             sizing_mode='stretch_both')
Esempio n. 6
0
    def __init__(self):
        self.num_prod_groups = Spinner(title="Number of product groups", low=0, high=100, step=1, value=0, width=150)
        self.num_prod_groups.on_change('value', self.update_num_prod_groups, self.update_price_group_selector)
        self.prod_groups = [PriceGroup(name='Product group #1', pg_type='Product')]

        self.num_customer_groups = Spinner(title="Number of customer groups", low=0, high=100, step=1, value=0,
                                           width=150)
        self.num_customer_groups.on_change('value', self.update_num_cust_groups, self.update_price_group_selector)
        self.cust_groups = []

        # initialize with the number of product groups plus the number of customer groups
        self.price_groups = self.prod_groups + self.cust_groups

        self.num_price_groups = 1

        self.price_group_selector = RadioButtonGroup(labels=['Prod group #1'], active=0)
Esempio n. 7
0
def build_orbital_parameter(title, css_class, start, end, step, value):
    slider = Slider(
        title=title,
        value=value,
        start=start,
        end=end,
        step=step,
        css_classes=["slider", f"{css_class}_slider"],
    )

    spinner = Spinner(
        low=start,
        high=end,
        value=value,
        step=step,
        width=80,
        css_classes=["spinner", f"{css_class}_spinner"],
    )
    spinner.js_link("value", slider, "value")
    slider.js_link("value", spinner, "value")
    layout = row(slider, spinner, css_classes=[f"{css_class}_layout"])
    return (layout, slider)
Esempio n. 8
0
class _DataSource:
    """
        Abstract base class
    """

    def __init__(self):
        self.df = None
        self.df_col_headers = None
        self.filepath = TextInput()
        self.filepath.on_change('value', self.update_data)
        self.cols = None
        self.num_columns = Spinner(title="Number of columns", low=0, high=100, step=1, value=1, width=150)
        self.num_columns.on_change('value', self.update_num_columns)
        self.col_type_selectors = [Select(options=None)]
        self.col_selectors = [Select(options=self.df_col_headers)]

    def import_data(self):
        infile = Path(self.filepath.value)
        self.df = pd.read_csv(infile, parse_dates=True, infer_datetime_format=True, encoding='unicode_escape')
        self.df_col_headers = self.df.columns.tolist()

        print(self.df)
        print(self.df_col_headers)

    def update_data(self, attr, old, new):
        self.import_data()

    def update_num_columns(self, attr, old, new):
        for i in range(self.num_columns.value):
            if i + 1 > len(self.col_type_selectors):
                self.col_type_selectors.append(Select(options=[*self.cols]))
                self.col_selectors.append(Select(options=self.df_col_headers))
            else:
                self.col_type_selectors[i].options = [*self.cols]
                self.col_selectors[i].options = self.df_col_headers

    def update_col_options(self):
        self.col_type_selectors[0].options = [*self.cols]
Esempio n. 9
0
class PriceGroup:
    """
    Each price group (typically one for customers and one for each of a handful of product groups) is going to have
    several things
        - a column data source for the coefficients
        - a table associated with the cds (and table columns to go along with it)
        - a spinner to set the number of attributes
        - an attribute list, with associated file sources and column names
    """

    def __init__(self, name='', pg_type='Product'):

        self.name = TextInput(value=name, width=250)
        self.pg_type = pg_type

        self.num_attributes = Spinner(title="Number of attributes", low=1, high=100, step=1, value=1, width=150)
        self.num_attributes.on_change('value', self.update_attributes, self.update_attribute_selector)

        self.attributes = [Attribute()]
        self.attribute_selector = RadioButtonGroup(labels=['Attribute #1'], active=0)

    def update_attributes(self, attr, old, new):
        """
        on_change event for changes in the num_attributes Spinner
        """

        for i in range(new):
            if i + 1 > len(self.attributes):
                self.attributes.append(Attribute())
            self.attributes[i].name.on_change('value', self.update_attribute_selector)

    def update_attribute_selector(self, attr, old, new):
        attributes = self.attributes[:self.num_attributes.value]

        self.attribute_selector.labels = [attr.name.value for attr in attributes]
        self.attribute_selector.active = 0
Esempio n. 10
0
class Coins():
    """Coin tossing simulator class."""

    # %%
    def __init__(self):

        title = Div(text="""<h1>Coin tossing simulation</h1>"""
                    """<p>Simulates the effects of tossing a coin """
                    """many times. Heads are scored 1 and tails 0. """
                    """The chart shows the cumlative mean, which """
                    """should go to 0.5 in 'the long run'. To use """
                    """the software, select the number of coin """
                    """tosses or press go to generate a fresh """
                    """data set.</p>""",
                    sizing_mode="""stretch_width""")

        self.tosses = 2000

        self.toss_count = Spinner(step=1,
                                  value=self.tosses,
                                  title="""Number of tosses""",
                                  sizing_mode="""stretch_width""")
        self.go = Button(label="Button",
                         button_type="""success""",
                         sizing_mode="""stretch_width""")

        chart = Figure(title='Cumulative mean of coin tosses',
                       x_axis_label='Number of tosses',
                       y_axis_label='Cumulative mean')
        self.cds = ColumnDataSource()
        self.make_means()
        chart.line(source=self.cds,
                   x='tosses',
                   y='means',
                   line_color='red',
                   line_width=4,
                   line_alpha=0.5)

        chart.title.text_font_size = '20px'
        chart.xaxis.axis_label_text_font_size = '15px'
        chart.xaxis.major_label_text_font_size = '15px'
        chart.yaxis.axis_label_text_font_size = '15px'
        chart.yaxis.major_label_text_font_size = '15px'

        title_bar = column(children=[title], sizing_mode="stretch_both")
        widget_bar = column(children=[self.toss_count, self.go],
                            sizing_mode='fixed',
                            width=250,
                            height=500)
        chart_row = row(children=[widget_bar, chart],
                        sizing_mode='stretch_both')
        self.layout = column(children=[title_bar, chart_row],
                             sizing_mode='stretch_both')

    # %%
    def setup(self):
        """Setup the callbacks"""
        self.toss_count.on_change('value', self.callback_toss_count)
        self.go.on_change('clicks', self.callback_go)

    # %%
    def callback_toss_count(self, attrname, old, new):
        """Callback method for mean count"""

        self.tosses = self.toss_count.value
        self.make_means()

    # %%
    def callback_go(self, attrname, old, new):
        """Callback method for mean count"""
        self.make_means()

    # %%
    def make_means(self):
        """Create thje means be generating a random number serioes."""
        heads = np.random.randint(2, size=self.toss_count.value)
        means = np.cumsum(heads) / np.arange(1, self.toss_count.value + 1)

        self.cds.data = {'tosses': range(1, self.tosses + 1), 'means': means}
Esempio n. 11
0
# =============================================================================

# Getting list of unique Nodes
nodes = list(df['Node'].unique())

# Creating Check Box Button Group Widget for Nodes
node_cbbg = CheckboxButtonGroup(labels=nodes,
                                active=[nodes.index(i) for i in nodes])

# Creating Toggle Button Widget for show/hide unclustered PrSMs
unclustered_toggle = Toggle(label='Hide unclustered')

# Creating Spinner Widget for the DBSCAN eps hyperparameter
ε_spinner = Spinner(title='ε',
                    width=100,
                    value=p['ε'],
                    low=0.0005,
                    high=0.0050,
                    step=0.0001)

# Creating Spinner Widget for the DBSCAN min_samples hyperparameter
n_spinner = Spinner(title='n_min',
                    width=100,
                    value=p['n_min'],
                    low=1,
                    high=50,
                    step=1)

# Getting RT floor & ceil for low= and high= Spinner parameters
t_floor = math.floor(min(df['RT (min)']))
t_ceil = math.ceil(max(df['RT (min)']))
Esempio n. 12
0
completions = ["aaa", "aab", "aac", "baa", "caa"]
autocomplete_input = AutocompleteInput(placeholder="Enter value (auto-complete) ...", completions=completions)

select = Select(options=["Option 1", "Option 2", "Option 3"])

multi_select = MultiSelect(options=["Option %d" % (i+1) for i in range(16)], size=6)

slider = Slider(value=10, start=0, end=100, step=0.5)

range_slider = RangeSlider(value=[10, 90], start=0, end=100, step=0.5)

date_slider = DateSlider(value=date(2016, 1, 1), start=date(2015, 1, 1), end=date(2017, 12, 31))

date_range_slider = DateRangeSlider(value=(date(2016, 1, 1), date(2016, 12, 31)), start=date(2015, 1, 1), end=date(2017, 12, 31))

spinner = Spinner(value=100)

color_picker = ColorPicker(color="red", title="Choose color:")

date_picker = DatePicker(value=date(2017, 8, 1))

paragraph = Paragraph(text="some text")

div = Div(text="some <b>text</b>")

pre_text = PreText(text="some text")

def mk_tab(color):
    plot = figure(plot_width=300, plot_height=300)
    plot.scatter(flowers["petal_length"], flowers["petal_width"], color=color, fill_alpha=0.2, size=12)
    return Panel(title="Tab 1: %s" % color.capitalize(), child=plot)
Esempio n. 13
0
    def __init__(self, model):
        """
        Construct separation dashboard
        """
        # Save reference to model
        self.model = model

        ################################
        # Process button
        ################################

        self.process = Button(label="Generate",
                              button_type="primary",
                              name='process',
                              sizing_mode='scale_width',
                              css_classes=['generate'])
        self.process.js_on_click(CustomJS(code="toggleLoading()"))

        ################################
        # Widgets
        ################################

        # Data type selection
        self.data_type = RadioButtonGroup(
            labels=["All Data", "Experimental", "Simulated"],
            active=0,
            css_classes=['dtypes'])

        # Adsorbate drop-down selections
        self.g1_sel = Select(title="Adsorbate 1",
                             options=self.model.ads_list,
                             value=self.model.g1,
                             css_classes=['g-selectors'])
        self.g2_sel = Select(title="Adsorbate 2",
                             options=self.model.ads_list,
                             value=self.model.g2)

        # Temperature selection
        self.t_absolute = Spinner(value=self.model.t_abs,
                                  title='Temperature:',
                                  css_classes=['t-abs'])
        self.t_tolerance = Spinner(value=self.model.t_tol,
                                   title='Tolerance:',
                                   css_classes=['t-tol'])

        # Combined in a layout
        self.dsel_widgets = layout([
            [self.data_type],
            [self.g1_sel, self.g2_sel, self.t_absolute, self.t_tolerance],
        ],
                                   sizing_mode='scale_width',
                                   name="widgets")

        ################################
        # KPI Plots
        ################################

        # Top graph generation
        tooltip = load_tooltip()
        self.p_henry, rend1 = self.top_graph("K", "Henry coefficient (log)",
                                             self.model.data,
                                             self.model.errors, tooltip)
        self.p_loading, rend2 = self.top_graph(
            "L", "Uptake at selected pressure (bar)", self.model.data,
            self.model.errors, tooltip)
        self.p_wc, rend3 = self.top_graph(
            "W", "Working capacity in selected range (bar)", self.model.data,
            self.model.errors, tooltip)

        # Give graphs the same hover and select effect
        sel = Circle(fill_alpha=1, fill_color="red", line_color=None)
        nonsel = Circle(fill_alpha=0.2, fill_color="blue", line_color=None)
        for rend in [rend1, rend2, rend3]:
            rend.selection_glyph = sel
            rend.nonselection_glyph = nonsel
            rend.hover_glyph = sel

        # Pressure slider
        self.p_slider = Slider(
            title="Pressure (bar)",
            value=0.5,
            start=0,
            end=20,
            step=0.5,
            callback_policy='throttle',
            callback_throttle=200,
        )

        # Working capacity slider
        self.wc_slider = RangeSlider(
            title="Working capacity (bar)",
            value=(0.5, 5),
            start=0,
            end=20,
            step=0.5,
            callback_policy='throttle',
            callback_throttle=200,
        )

        # Material datatable
        self.mat_list = DataTable(
            columns=[
                TableColumn(field="labels", title="Material", width=300),
                TableColumn(field="sel",
                            title="KH2/KH1",
                            width=35,
                            formatter=NumberFormatter(format='‘0.0a’')),
                TableColumn(field="psa_W",
                            title="PSA-API",
                            width=35,
                            formatter=NumberFormatter(format='‘0.0a’')),
            ],
            source=self.model.data,
            index_position=None,
            selectable='checkbox',
            scroll_to_selection=True,
            width=400,
            fit_columns=True,
        )

        # Custom css classes for interactors
        self.p_henry.css_classes = ['g-henry']
        self.p_loading.css_classes = ['g-load']
        self.p_wc.css_classes = ['g-wcap']
        self.mat_list.css_classes = ['t-details']

        # Generate the axis labels
        self.top_graph_labels()

        self.kpi_plots = layout([
            [
                gridplot([[self.mat_list, self.p_henry],
                          [self.p_loading, self.p_wc]],
                         sizing_mode='scale_width')
            ],
            [self.p_slider, self.wc_slider],
        ],
                                sizing_mode='scale_width',
                                name="kpiplots")
        self.kpi_plots.children[0].css_classes = ['kpi']
        self.kpi_plots.children[1].css_classes = ['p-selectors']

        ################################
        # Isotherm details explorer
        ################################

        # Isotherm display graphs
        self.p_g1iso = self.bottom_graph(self.model.g1_iso_sel, self.model.g1)
        self.p_g2iso = self.bottom_graph(self.model.g2_iso_sel, self.model.g2)

        # Isotherm display palette
        self.c_cyc = cycle(gen_palette(20))

        self.detail_plots = layout([
            [self.p_g1iso, self.p_g2iso],
        ],
                                   sizing_mode='scale_width',
                                   name="detailplots")
        self.detail_plots.children[0].css_classes = ['isotherms']
Esempio n. 14
0
# Init model first time.
model.frames = get_frames(directory_selection.value)

# Slider to select frame.
idx_selection_slider = Slider(start=model.idxs[0],
                              end=model.idxs[-1],
                              step=1.0,
                              value=model.idxs[0],
                              title="Select frame id")
idx_selection_slider.on_change('value', idx_slider_update)

# Spinner to select frame.
idx_selection_spinner = Spinner(low=model.idxs[0],
                                high=model.idxs[-1],
                                step=1.0,
                                value=model.idxs[0],
                                title="Select frame id")
idx_selection_spinner.on_change('value', idx_spinner_update)

# Selection for column to yield symbol color.
color_column_selection = Select(options=model.frames[int(
    idx_selection_spinner.value)].columns.to_list(),
                                title="Select symbol color from column",
                                value="Volume (µm^3)")
color_column_selection.on_change('value', color_update)

# Selection for column to yield symbol size.
size_column_selection = Select(options=model.frames[int(
    idx_selection_spinner.value)].columns.to_list(),
                               title="Select symbol size from column",
Esempio n. 15
0
 def __init__(self):
     self.name = TextInput(placeholder='Config name')
     self.coefficient = Spinner(value=0, step=0.0001)
     self.abs_or_pct = Select(options=['Absolute', 'Percent'], value='Absolute')
Esempio n. 16
0
class PriceModel:
    """
    fundamentally, this class contains a list of PriceGroup objects and related widgets and methods
    """

    def __init__(self):
        self.num_prod_groups = Spinner(title="Number of product groups", low=0, high=100, step=1, value=0, width=150)
        self.num_prod_groups.on_change('value', self.update_num_prod_groups, self.update_price_group_selector)
        self.prod_groups = [PriceGroup(name='Product group #1', pg_type='Product')]

        self.num_customer_groups = Spinner(title="Number of customer groups", low=0, high=100, step=1, value=0,
                                           width=150)
        self.num_customer_groups.on_change('value', self.update_num_cust_groups, self.update_price_group_selector)
        self.cust_groups = []

        # initialize with the number of product groups plus the number of customer groups
        self.price_groups = self.prod_groups + self.cust_groups

        self.num_price_groups = 1

        self.price_group_selector = RadioButtonGroup(labels=['Prod group #1'], active=0)

    def update_num_price_groups(self):
        self.num_price_groups = self.num_prod_groups.value + self.num_customer_groups.value

    def update_price_group_selector(self, attr, old, new):

        prod_groups = self.prod_groups[:self.num_prod_groups.value]
        cust_groups = self.cust_groups[:self.num_customer_groups.value]
        price_groups = prod_groups + cust_groups

        self.price_group_selector.labels = [_.name.value for _ in price_groups]
        self.price_group_selector.active = 0

    def update_num_prod_groups(self, attr, old, new):
        """
        on_change event for changes in the num_prod_groups spinner

        :param attr:
        :param old:
        :param new:
        :return:
        """
        self.update_num_price_groups()

        for i in range(new):
            if i + 1 > len(self.prod_groups):
                self.prod_groups.append(PriceGroup(name='Product group #{}'.format(i + 1), pg_type='Product'))
            self.prod_groups[i].name.on_change('value', self.update_price_group_selector)

        self.price_groups = self.prod_groups + self.cust_groups

    def update_num_cust_groups(self, attr, old, new):
        """
        on_change event for changes in the num_prod_groups spinner

        :param attr:
        :param old:
        :param new:
        :return:
        """
        self.update_num_price_groups()

        for i in range(new):
            if i + 1 > len(self.cust_groups):
                self.cust_groups.append(PriceGroup(name='Customer Group #{}'.format(i + 1), pg_type='Customer'))
            self.cust_groups[i].name.on_change('value', self.update_price_group_selector)
        self.price_groups = self.prod_groups + self.cust_groups
maturity = list(menu_maturities.keys())[0]
select_maturity = Select(title="Maturity", options=list(
    menu_maturities.keys()), value=maturity)

opt_type = {"Call": "Call", "Put": "Put"}
select_type = Select(title="Option type", options=list(opt_type.keys()),
                     value=option_type)

my_Strategy.api.get_options_data(ticker, option_type, maturity)
menu_strikes = {str(k): k for k in my_Strategy.api.possible_values(ticker,
                                                                   "Strike")}
K = list(menu_strikes.keys())[0]
select_strike = Select(title="Strike", options=list(menu_strikes.keys()),
                       value=K)

spinner_qty = Spinner(value=0, step=1, title="Number of options to add \
                      (or remove)")

button_add = Button(label='Add options (or remove)', button_type="success")

spinner_qty_stocks = Spinner(value=0, step=1, title="Number of stocks")

# ##############################display widgets###############################
menu_greeks = {"Delta": "Delta", "Gamma": "Gamma", "Vega": "Vega",
               "Theta": "Theta"}
select_greek = Select(title="Greek", options=list(menu_greeks.keys()),
                      value=greek)

min_T = 1/365
slider_time = Slider(start=0, end=int(min_T * 365), value=0, step=1,
                     title="Shift Time (in days)")
Esempio n. 18
0
    "x": np.array(range(a, a + n + 1)),
    "normalized": np.zeros(n + 1, dtype="int")
})
DensityPanel.vbar(x="x", top="normalized", width=0.2, source=DensitySource)
DensityPanel.min_border, WalkPanel.min_border = 5, 5
DensityPanel.xaxis.visible = False
DensityPanel.yaxis.visible = True

start_button = Button(label="Go", button_type="success", width=100)
stop_button = Button(label="Stop", button_type="success", width=100)
stop_button.disabled = True

print("!!!!!!!!!")
a_field = Spinner(high=10.0,
                  low=1.0,
                  step=1.0,
                  value=a,
                  title="White Balls",
                  width=100)
b_field = Spinner(high=10.0,
                  low=1.0,
                  step=1.0,
                  value=b,
                  title="Black Balls",
                  width=100)


def update(U, source):

    n, a, b = U._n, U._a, U._b
    Walk, Density = U.draw()
    normalized = (n + a + b) * Density / Density.sum()