示例#1
0
def create_figure(y_column, x_column):

    df_cars = load_data()
    source = ColumnDataSource(data=df_cars)

    hover = HoverTool(tooltips=[
        ("Modell", "@Modell"),
        ("price", "@price"),
    ])

    p = figure(title='Cars', tools=[hover])

    #x_column = 'Tillverkningsår'
    #y_column = 'price'

    markers = ['circle']

    p.scatter(x=x_column,
              y=y_column,
              source=source,
              legend="car type",
              marker=factor_mark('car type',
                                 markers=markers,
                                 factors=df_cars['car type'].unique()),
              color=factor_cmap('car type',
                                palette='Category10_3',
                                factors=df_cars['car type'].unique()),
              size=8,
              alpha=0.25)

    p.xaxis.axis_label = x_column
    p.yaxis.axis_label = y_column
    return p
示例#2
0
 def test_defaults(self) -> None:
     t = bt.factor_mark("foo", ["hex", "square"], ["foo", "bar"])
     assert isinstance(t, Field)
     assert t.field == "foo"
     assert isinstance(t.transform, CategoricalMarkerMapper)
     assert t.transform.markers == ["hex", "square"]
     assert t.transform.factors == ["foo", "bar"]
     assert t.transform.start == 0
     assert t.transform.end is None
示例#3
0
 def test_defaults(self):
     t = bt.factor_mark("foo", ["hex", "square"], ["foo", "bar"])
     assert isinstance(t, dict)
     assert set(t) == {"field", "transform"}
     assert t['field'] == "foo"
     assert isinstance(t['transform'], CategoricalMarkerMapper)
     assert t['transform'].markers == ["hex", "square"]
     assert t['transform'].factors == ["foo", "bar"]
     assert t['transform'].start == 0
     assert t['transform'].end is None
示例#4
0
 def test_basic(self) -> None:
     t = bt.factor_mark("foo", ["hex", "square"], ["foo", "bar"], start=1, end=2)
     assert isinstance(t, dict)
     assert set(t) == {"field", "transform"}
     assert t['field'] == "foo"
     assert isinstance(t['transform'], CategoricalMarkerMapper)
     assert t['transform'].markers == ["hex", "square"]
     assert t['transform'].factors == ["foo", "bar"]
     assert t['transform'].start == 1
     assert t['transform'].end == 2
 def test_defaults(self):
     t = bt.factor_mark("foo", ["hex", "square"], ["foo", "bar"])
     assert isinstance(t, dict)
     assert set(t) == {"field", "transform"}
     assert t['field'] == "foo"
     assert isinstance(t['transform'], CategoricalMarkerMapper)
     assert t['transform'].markers == ["hex", "square"]
     assert t['transform'].factors == ["foo", "bar"]
     assert t['transform'].start == 0
     assert t['transform'].end is None
示例#6
0
 def test_basic(self) -> None:
     t = bt.factor_mark("foo", ["hex", "square"], ["foo", "bar"],
                        start=1,
                        end=2)
     assert isinstance(t, Field)
     assert t.field == "foo"
     assert isinstance(t.transform, CategoricalMarkerMapper)
     assert t.transform.markers == ["hex", "square"]
     assert t.transform.factors == ["foo", "bar"]
     assert t.transform.start == 1
     assert t.transform.end == 2
示例#7
0
文件: fit1d.py 项目: DBerke/DRAGONS
    def mask_rendering_kwargs(self):
        """
        Get the marks and colors to use for the various point masks

        Returns
        -------
        dict : Returns a dict for bokeh that describes the markers and pallete
        """
        return {
            'marker': bt.factor_mark('mask', self.MARKERS, self.MASK_TYPE),
            'color': bt.factor_cmap('mask', self.PALETTE, self.MASK_TYPE)
        }
示例#8
0
文件: Scatter.py 项目: tae2089/vizual
def mapping_marker():
    SPECIES = ['setosa', 'versicolor', 'virginica']
    MARKERS = ['hex', 'circle_x', 'triangle']

    p = figure(title="Iris Morphology")
    p.xaxis.axis_label = 'Petal Length'
    p.yaxis.axis_label = 'Sepal Width'

    p.scatter("petal_length",
              "sepal_width",
              source=flowers,
              legend_field="species",
              fill_alpha=0.4,
              size=12,
              marker=factor_mark('species', MARKERS, SPECIES),
              color=factor_cmap('species', 'Category10_3', SPECIES))

    show(p)
示例#9
0
def create_sample_scatter(x_data,
                          y_data,
                          source,
                          label,
                          title='',
                          x_axis_title='',
                          y_axis_title=''):
    result_plot = figure(title=title,
                         tools=tools_list,
                         tooltips=custom_tooltip)
    result_plot.xaxis.axis_label = x_axis_title
    result_plot.yaxis.axis_label = y_axis_title
    for cat_filter in label['standard_label_list']:
        index_list = []
        for i in range(len(source.data[label['real_label_list']])):
            if source.data[label['real_label_list']][i] == cat_filter:
                index_list.append(i)
        view = CDSView(source=source, filters=[IndexFilter(index_list)])
        result_plot.scatter(
            x_data,
            y_data,
            source=source,
            fill_alpha=0.4,
            size=8,
            marker=factor_mark(label['real_label_list'], markers,
                               label['standard_label_list']),
            color=factor_cmap(label['real_label_list'], 'Category10_8',
                              label['standard_label_list']),
            # muted_color=factor_cmap(label['real_label_list'], 'Category10_8',
            #                         label['standard_label_list']),
            muted_alpha=0.1,
            view=view,
            legend=cat_filter)
    result_plot.legend.click_policy = "mute"
    # highlight x y axes
    result_plot.renderers.extend([vline, hline])

    return result_plot
示例#10
0
def Electron_Energy_Graph(conn):

    output_file(
        "Electron_Energy_Graph2.html"
    )  #????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

    ############################################################################
    ############################# USER INPUTS ##################################

    # Decide what the default viewing option is going to be. (i.e. the fields to
    # be plotted on the x and y axis when the graph is opened).
    # NB: Have it set that if axis is 'adate' then will automatically update
    # to plot datetime.
    x_data1 = 'adate'
    y_data1 = '6fwhm'
    plot_title1 = 'Electron Energy'
    x_axis_title1 = x_data1
    y_axis_title1 = y_data1
    plot_size_height1 = 450
    plot_size_width1 = 800
    legend_location = 'bottom_left'
    hover_tool_fields = ['comments']
    # Create a list of the plot parameters that will be used as input to a
    # function later.
    list_plot_parameters = [
        x_data1, y_data1, plot_title1, x_axis_title1, y_axis_title1,
        plot_size_height1, plot_size_width1, legend_location
    ]
    # Define the fields that the legend will be based off. If there is only
    # one field then put it in both columns.
    color_column = 'machinename'
    custom_color_boolean = False
    custom_color_palette = []
    marker_column = 'machinename'
    custom_marker_boolean = False
    custom_marker_palette = []
    # From the legend defined above give the values that will be pre-ticked when
    # the plot is opened. NB: Bokeh will throw an error if one of these lists is
    # empty (i.e. =[]) If only using color or marker then set the color_to plot
    # and then enter the command:  marker_to_plot = color_to_plot.
    color_to_plot = ['TrueBeam B', 'TrueBeam C']
    marker_to_plot = ['option1', 'option2', 'option3']
    marker_to_plot = color_to_plot

    ############################################################################
    #################### CREATE THE DATA FOR THE GRAPH #########################

    # Do this in a function so it can be used in an update callback later

    def Create_df():

        # Use the connection passed to the function to read the data into a
        # dataframe via an SQL query.
        df = pd.read_sql('SELECT * FROM [eEnergyICP]', conn)

        # Delete empty rows where the data is very important to have
        df = df.dropna(subset=['protocol id'], how='any')

        # The format is complicated for this field but seems to be that the date is
        # always the first element and the machine is always the last regardless of
        # how many elements there are.
        # Seperate on the first '_'
        df_left = df['protocol id'].str.partition(sep='_')
        # Seperate on the last '_'
        df_right = df['protocol id'].str.rpartition(sep='_')
        # From these sperated dataframes add the appropriate columns back into
        # the main dataframe.
        df.loc[:, 'adate'] = df_left[0]
        df.loc[:, 'machinename'] = df_right[2]
        # Turn 'adate' into datetime. An annoying factor in the database is a
        # few entries with a different datetime format. In combination with the
        # dayfirst=True parameter to override the American date default the
        # to_datetime function seems to solve this. NB: Might be a little slow
        # without feeding it a specific format but unlikely to be an issue given
        # relatively small datasets. Possibly someway to feed multiple formats
        # but currently more effort than it's worth.
        df.loc[:, 'adate'] = pd.to_datetime(df.loc[:, 'adate'], dayfirst=True)

        # Drop any rows that aren't related to the Truebeams (ditches the old
        # uneeded data). Might be possible to put this in the SQL query but
        # difficult as machinename is embedded in the protocol ID.
        df = df[df['machinename'].isin(
            ['TrueBeam B', 'TrueBeam C', 'TrueBeam D', 'TrueBeam F'])]

        # Drop any columns where there is no data (likely because of the
        # dropping of the old linacs (e.g. data that used to be collected from
        # them that is no longer collected for the Truebeams))
        df = df.dropna(axis='columns', how='all')

        return df

    df = Create_df()

    # Create a list of the fields using the dataframe. By doing it now before
    # the extra legend fields are added it's easy to limit what is displayed in
    # the select widgets.
    TableFields = (list(df.columns))

    ############################################################################
    ############################################################################

    ############################################################################
    ################ CREATE THE DATAFRAME FOR THE TOLERANCES ###################

    # If you want to add tolerances change the boolean to True and construct the
    # dataframe in the correct format.
    tolerance_boolean = True
    # The format of the dataframe should be the first line being the x_axis
    # (with some values taken from the main dataframe to get the right
    # formatting). The subsequent columns are the tolerances [low, high].
    # NB: column names should match those from the main dataframe.
    if tolerance_boolean == True:
        df_tol1 = pd.DataFrame({
            'adate': [df['adate'].max(), df['adate'].max()],
            '6fwhm': [6, 10],
            '9fwhm': [9, 12]
        })

        df_tol1 = pd.read_sql('SELECT * FROM [ElectronFWHMLimits]', conn)
        df_tol1 = df_tol1.set_index('class')
        df_tol1 = pd.DataFrame({
            'adate': [df['adate'].max(), df['adate'].max()],
            '6fwhm':
            [df_tol1.loc['TBUCLH', 'lower6'], df_tol1.loc['TBUCLH', 'upper6']],
            '9fwhm':
            [df_tol1.loc['TBUCLH', 'lower9'], df_tol1.loc['TBUCLH', 'upper9']],
            '12fwhm': [
                df_tol1.loc['TBUCLH', 'lower12'], df_tol1.loc['TBUCLH',
                                                              'upper12']
            ],
            '15fwhm': [
                df_tol1.loc['TBUCLH', 'lower15'], df_tol1.loc['TBUCLH',
                                                              'upper15']
            ]
        })

    ############################################################################
    ############################################################################

    ############################################################################
    ############################################################################
    '''

	This is the end of the user input section. If you don't need to make any
	other changes you can end here.

	'''

    ##########################################################################
    ################### CREATE THE COLUMNS FOR THE LEGEND ######################

    (color_list, color_palette, marker_list, marker_palette, df,
     add_legend_to_df) = Create_Legend(df, color_column, custom_color_boolean,
                                       custom_color_palette, marker_column,
                                       custom_marker_boolean,
                                       custom_marker_palette)

    ############################################################################
    ############################################################################

    ############################################################################
    ################## FORMATTING AND CREATING A BASIC PLOT ####################

    ######### Make Dataset:
    # Run the Make_Dataset function to create a sub dataframe that the plot will
    # be made from.
    Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                           marker_to_plot, x_data1, y_data1)

    # Make the ColumnDataSource (when making convert dataframe to a dictionary,
    # which is helpful for the callback).
    src1 = ColumnDataSource(Sub_df1.to_dict(orient='list'))

    ######### Make Plot:
    # Create an empty plot (plot parameters will be applied later in a way that
    # can be manipulated in the callbacks)
    p1 = figure()
    p1.scatter(
        source=src1,
        x='x',
        y='y',
        fill_alpha=0.4,
        size=12,
        # NB: Always use legend_field for this not legend_group as the
        # former acts on the javascript side but the latter the Python
        # side. Therefore the former will update automatically when the
        # plot is changed with no need for a callback.
        legend_field='legend',
        marker=factor_mark('marker1', marker_palette, marker_list),
        color=factor_cmap('color1', color_palette, color_list))

    ######### Add plot parameters:
    Define_Plot_Parameters(p1, list_plot_parameters)

    ############################################################################
    ############################################################################

    ############################################################################
    ############################ ADD TOLERANCES ################################

    # We defined the tolerances further up and now want to add the correct ones
    # to the plot. Only do this through if the boolean is set to True as
    # otherwise the user doesn't want tolerances.

    if tolerance_boolean == True:

        Sub_df1_tol1 = Make_Dataset_Tolerance(x_data1, y_data1, Sub_df1,
                                              df_tol1)

        src1_tol = ColumnDataSource(Sub_df1_tol1.to_dict(orient='list'))

        p1.line(source=src1_tol, x='x', y='y_low', color='firebrick')
        p1.line(source=src1_tol, x='x', y='y_high', color='firebrick')

    ############################################################################
    ############################################################################

    ############################################################################
    ################## ADD MORE COMPLEX TOOLS TO THE PLOT ######################

    ######## 1)
    # Create a hover tool and add it to the plot
    hover1 = HoverTool()

    if len(hover_tool_fields) < 11:
        kwargs = {}
        i = 0
        for x in hover_tool_fields:
            i = i + 1
            kwargs['Field' + str(i)] = x
    else:
        kwargs = {}
        msgbox('Too many fields selected to display on HoverTool ' \
         '(Max = 10). Please reduce number of fields selected')

    Update_HoverTool(hover1, x_data1, y_data1, **kwargs)

    p1.add_tools(hover1)

    ############################################################################
    ############################################################################

    ############################################################################
    ################# CREATE WIDGETS TO BE ADDED TO THE PLOT ###################

    ######## 1)
    # This select funtion will be used to create dropdown lists to change the
    # data plotted on the x/y-axis.
    select_xaxis, select_yaxis = Create_Select_Axis(TableFields, x_axis_title1,
                                                    y_axis_title1)

    ######## 2)
    # This select widget will be used to create dropdown lists to change the
    # legend position.
    select_legend = Create_Select_Legend(legend_location)

    ######## 3)
    # These checkbox widgets will be used to create a tool to select the machine
    # and energy that are being plotted.
    checkbox_color, checkbox_marker = Create_Checkbox_Legend(
        df, color_column, color_to_plot, marker_column, marker_to_plot)

    ######## 4)
    # These checkbox widgets will be used to create a tool to select the machine
    # and energy that are being plotted.
    checkbox_hovertool = Create_Checkbox_HoverTool(TableFields,
                                                   hover_tool_fields)

    ######## 5)
    # Make an 'Update Button' to requery the database and get up to date data.
    update_button = Button(label='Update', button_type='success')

    ######## 6)
    # Make a Range Button
    range_button = Button(label='Range', button_type='primary')

    ######## 7)
    # Make some titles for the checkboxes
    color_title = Div(text='<b>Machine Choice</b>')
    marker_title = Div(text='<b>Marker</b>')
    hover_title = Div(text='<b>Hovertool Fields</b>')

    ############################################################################
    ############################################################################

    ############################################################################
    ########################### CREATE A LAYOUT ################################

    # Create a layout to add widgets and arrange the display.
    if color_column == marker_column:
        layout_checkbox = column(
            [color_title, checkbox_color, hover_title, checkbox_hovertool])
    else:
        layout_checkbox = column([
            color_title, checkbox_color, marker_title, checkbox_marker,
            hover_title, checkbox_hovertool
        ])

    button_row = row([update_button, range_button])

    layout_plots = column(
        [button_row, select_xaxis, select_yaxis, select_legend, p1])

    tab_layout = row([layout_plots, layout_checkbox])

    ############################################################################
    ############################################################################

    ############################################################################
    ####################### CREATE CALLBACK FUNCTIONS ##########################

    # Create a big callback that does most stuff
    def callback(attr, old, new):

        # Want to acquire the current values of all of the checkboxes and select
        # widgets to provide as inputs for the re-plot.
        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        if color_column != marker_column:
            marker_to_plot = [
                checkbox_marker.labels[i] for i in checkbox_marker.active
            ]
        else:
            marker_to_plot = color_to_plot
        hovertool_to_plot = [
            checkbox_hovertool.labels[i] for i in checkbox_hovertool.active
        ]
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value
        legend_location = select_legend.value
        # Set the new axis titles
        x_axis_title1 = plot1_xdata_to_plot
        y_axis_title1 = plot1_ydata_to_plot

        # Use the pre-defined Make_Dataset function with these new inputs to
        # create new versions of the sub dataframes.
        Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                               marker_to_plot, plot1_xdata_to_plot,
                               plot1_ydata_to_plot)

        # Use the pre-defined Define_Plot_Parameters function with these new
        # inputs to update the plot parameters.
        Define_Plot_Parameters(p1, [
            plot1_xdata_to_plot, plot1_ydata_to_plot, plot_title1,
            x_axis_title1, y_axis_title1, plot_size_height1, plot_size_width1,
            legend_location
        ])

        # Update the hovertool
        if len(hovertool_to_plot) < 11:
            kwargs = {}
            i = 0
            for x in hovertool_to_plot:
                i = i + 1
                kwargs['Field' + str(i)] = x
        else:
            kwargs = {}
            msgbox('Too many fields selected to display on HoverTool ' \
             '(Max = 10). Please reduce number of fields selected')

        Update_HoverTool(hover1, plot1_xdata_to_plot, plot1_ydata_to_plot,
                         **kwargs)

        # Use the pre-defined tolerances function with these new inputs to
        # make a new version of the tolerances sub dataframe.
        if tolerance_boolean == True:
            Sub_df1_tol1 = Make_Dataset_Tolerance(plot1_xdata_to_plot,
                                                  plot1_ydata_to_plot, Sub_df1,
                                                  df_tol1)

        # Update the ColumnDataSources.
        src1.data = Sub_df1.to_dict(orient='list')
        if tolerance_boolean == True:
            src1_tol.data = Sub_df1_tol1.to_dict(orient='list')

        return

    select_xaxis.on_change('value', callback)
    select_yaxis.on_change('value', callback)
    select_legend.on_change('value', callback)
    checkbox_color.on_change('active', callback)
    checkbox_marker.on_change('active', callback)
    checkbox_hovertool.on_change('active', callback)

    # Callback for the Update Button
    def callback_update():

        # Make a new version of the dataframe using the original Create_df
        # function that connects to the database.
        df = Create_df()
        df = add_legend_to_df(df)

        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        if color_column != marker_column:
            marker_to_plot = [
                checkbox_marker.labels[i] for i in checkbox_marker.active
            ]
        else:
            marker_to_plot = color_to_plot
        hovertool_to_plot = [
            checkbox_hovertool.labels[i] for i in checkbox_hovertool.active
        ]
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value
        x_axis_title1 = plot1_xdata_to_plot
        y_axis_title1 = plot1_ydata_to_plot
        legend_location = select_legend.value

        Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                               marker_to_plot, plot1_xdata_to_plot,
                               plot1_ydata_to_plot)

        Define_Plot_Parameters(p1, [
            plot1_xdata_to_plot, plot1_ydata_to_plot, plot_title1,
            x_axis_title1, y_axis_title1, plot_size_height1, plot_size_width1,
            legend_location
        ])

        if len(hovertool_to_plot) < 11:
            kwargs = {}
            i = 0
            for x in hovertool_to_plot:
                i = i + 1
                kwargs['Field' + str(i)] = x
        else:
            kwargs = {}
            msgbox('Too many fields selected to display on HoverTool ' \
             '(Max = 10). Please reduce number of fields selected')

        Update_HoverTool(hover1, plot1_xdata_to_plot, plot1_ydata_to_plot,
                         **kwargs)

        if tolerance_boolean == True:
            Sub_df1_tol1 = Make_Dataset_Tolerance(plot1_xdata_to_plot,
                                                  plot1_ydata_to_plot, Sub_df1,
                                                  df_tol1)
            src1_tol.data = Sub_df1_tol1.to_dict(orient='list')

        src1.data = Sub_df1.to_dict(orient='list')

        return

    update_button.on_click(callback_update)

    # Callback for the Range Button
    def callback_range():

        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        if color_column != marker_column:
            marker_to_plot = [
                checkbox_marker.labels[i] for i in checkbox_marker.active
            ]
        else:
            marker_to_plot = color_to_plot
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value

        # Use the pre-defined Make_Dataset function with these new inputs to
        # create new versions of the sub dataframes.
        Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                               marker_to_plot, plot1_xdata_to_plot,
                               plot1_ydata_to_plot)

        x_data1 = select_xaxis.value
        y_data1 = select_yaxis.value

        if (x_data1 == 'adate') and ((y_data1 == '6fwhm') or
                                     (y_data1 == '9fwhm') or
                                     (y_data1 == '12fwhm') or
                                     (y_data1 == '15fwhm') or
                                     (y_data1 == '16fwhm')):

            p1.x_range.start = Sub_df1['x'].max() - timedelta(weeks=53)
            p1.x_range.end = Sub_df1['x'].max() + timedelta(weeks=2)

            if y_data1 == '6fwhm':
                p1.y_range.start = 9.6
                p1.y_range.end = 10.3
            elif y_data1 == '9fwhm':
                p1.y_range.start = 12.6
                p1.y_range.end = 13.32
            elif y_data1 == '12fwhm':
                p1.y_range.start = 16.25
                p1.y_range.end = 17.01
            elif y_data1 == '15fwhm':
                p1.y_range.start = 19.4
                p1.y_range.end = 20.16
            elif y_data1 == '16fwhm':
                p1.y_range.start = 19.5
                p1.y_range.end = 19.9

        return

    range_button.on_click(callback_range)

    ############################################################################
    ############################################################################

    ############################################################################
    ####################### RETURN TO THE MAIN SCRIPT ##########################

    return Panel(child=tab_layout, title='Electron Energy')
示例#11
0
# SquareX, Triangle, X]

TOOLTIPS_SCATTER = [
    ("(Fare,AGE)", "$x, $y"),
]


# Set the Title
p = figure(title = "Titanic Passenger Age & Fare by Survial Type",
    tooltips=TOOLTIPS_SCATTER)



# Construnct the colours
p.scatter("Fare", "Age", source=titanic_df, legend="Survived", fill_alpha=0.3, size=12,
          marker=factor_mark('Survived', MARKERS, FATE),
          color=factor_cmap('Survived', palette=['#3a6587', '#aeb3b7'], factors=FATE))

#Set the axis labels
p.xaxis.axis_label = 'Fare (In Pounds)'
p.yaxis.axis_label = 'Age (In Years)'

# Remove the Grid lines
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None

# change just some things about the x-axis
p.xaxis.axis_line_width = 2
p.xaxis.major_label_text_color = "black"
p.xaxis.axis_line_color = "#aeb3b7"
示例#12
0
def main(assignment_dir: str, log_dirs: List[str], plotfile: str, csv: str):
    """This script generates a HTML file containing a plot of the coverage for each
    sample after they have been through the QC pipeline.\n
    LOG_DIRS: Director(y/ies) containing the subsampling log files. (Coverage is
    extracted from these)
    ),
    """
    logfiles = []
    for d in log_dirs:
        logfiles.extend(Path(d).rglob("*.log"))

    data = defaultdict(dict)
    for file in logfiles:
        tech = "illumina" if "illumina" in file.parts[2] else "nanopore"
        sample = file.with_suffix("").name
        site = file.parts[-2]
        covg = ripgrep_extract_covg(file)
        data[sample].update({f"{tech}_covg": covg, "site": site})

    assignment_files = Path(assignment_dir).rglob("*.csv")
    for file in assignment_files:
        fields = file.read_text().split("\n")[1].split(",")
        sample = file.name.split(".")[0]
        data[sample]["lineage"] = fields[1]

    df = pd.DataFrame(data).T
    df.index.name = "sample"
    df.to_csv(csv)
    cds = ColumnDataSource(df)

    sites = list(set(df["site"]))
    lineages = list(set(df["lineage"]))
    tooltips = [
        ("index", "@sample"),
        ("Illumina", "@illumina_covg"),
        ("Nanopore", "@nanopore_covg"),
        ("site", "@site"),
        ("lineage", "@lineage"),
    ]
    title = "Sample coverage for different technologies after quality control"
    palette = Set2[len(lineages)]
    legend_var = "lineage"

    # inline effectively allows the plot to work offline
    output_file(plotfile, title=title, mode="inline")

    p = figure(
        tools=TOOLS,
        height=HEIGHT,
        width=WIDTH,
        tooltips=tooltips,
        active_drag="box_zoom",
        active_scroll="wheel_zoom",
        title=title,
    )
    p.yaxis.axis_label = "Nanopore Coverage"
    p.xaxis.axis_label = "Illumina Coverage"
    legend = Legend(
        click_policy="hide",
        location="top_left",
        title=legend_var.capitalize(),
        background_fill_alpha=0.1,
    )
    p.add_layout(legend)

    p.scatter(
        source=cds,
        y="nanopore_covg",
        x="illumina_covg",
        size=10,
        fill_alpha=0.4,
        marker=factor_mark("site", MARKERS, sites),
        color=factor_cmap("lineage", palette, lineages),
        legend_field=legend_var,
    )

    save(p)
def Electron_Energy_Graph_Old(conn):

    ############################################################################
    #################### CREATE THE DATA FOR THE GRAPH #########################

    output_file(
        "Electron_Output_Graph.html"
    )  #????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

    # Use the connection passed to the function to read the data into a
    # dataframe via an SQL query.
    df = pd.read_sql('SELECT * FROM [eEnergyICP]', conn)
    print(df)

    # Delete cells where 'protocol id' is empty
    df = df.dropna(subset=['protocol id'])

    # With any luck this can be removed after chatting to AW and MB ?????????????????????????????????????????????????????????????????????????????????
    # Get the date and machinename from the protocol id' field
    # Seperate on the first '_'
    df_left = df['protocol id'].str.partition(sep='_')
    # Seperate on the last '_'
    df_right = df['protocol id'].str.rpartition(sep='_')
    # From these sperated dataframes add the appropriate columns back into the
    # main dataframe.
    df.loc[:, 'adate'] = df_left[0]
    df.loc[:, 'machinename'] = df_right[2]

    # Turn 'adate' into datetime. Problems with this function as it assumes american date formats over british. ?????????????????????????????????????????????????????????????????????????????????
    # Talk to AW and MB about getting date from other tables in the database and pulling them into the query. ???????????????????????????????????????????????????????????????????????????????????
    # This way the date should be in a set format that the datetime function can be told, which should resolve this issue. ??????????????????????????????????????????????????????????????????????
    #
    # Need to turn the date fields into a Dateime object (either 'adate'
    # (protons) or the newly created 'adate' (photons)). The date field should
    # always be named 'adate' for consistency.
    df.loc[:, 'adate'] = pd.to_datetime(df.loc[:, 'adate'])

    # When starting a new graph can be useful to print the dataframe after any
    # manipulations to make sure the code has done what you expected.
    print(df)

    # Create a list of the fields using the dataframe
    TableFields = (list(df.columns))

    ############################################################################
    ############################################################################

    ############################################################################
    ################ CREATE THE DATAFRAME FOR THE TOLERANCES ###################

    # The purpose of this plot is generally to be as general as possible but
    # there are only a few parameters that will have defined tolerances.
    # Therefore the tolerance section can be a bit more specific and a dataframe
    # containing tolereances can be manually created for many cases and
    # extracted from the database in others (in a manner similar to above but
    # calling from a different table/query with the SQL statement)
    #
    # The format of the dataframe should be the first line being the x_axis
    # (with some values taken from the main dataframe to get the right
    # formatting). The subsequent columns are the tolerances [low, high].
    # NB: column names should match those from the main dataframe.
    df_tol1 = pd.read_sql('SELECT * FROM [ElectronFWHMLimits]', conn)
    print(df_tol1)
    df_tol1 = df_tol1.set_index('class')
    print(df_tol1)

    df_tol_TB = pd.DataFrame({
        'adate': [df['adate'].max(), df['adate'].max()],
        '6fwhm':
        [df_tol1.loc['TBUCLH', 'lower6'], df_tol1.loc['TBUCLH', 'upper6']],
        '9fwhm':
        [df_tol1.loc['TBUCLH', 'lower9'], df_tol1.loc['TBUCLH', 'upper9']],
        '12fwhm':
        [df_tol1.loc['TBUCLH', 'lower12'], df_tol1.loc['TBUCLH', 'upper12']],
        '15fwhm':
        [df_tol1.loc['TBUCLH', 'lower15'], df_tol1.loc['TBUCLH', 'upper15']]
    })
    print(df_tol_TB)

    df_tol_Classic = pd.DataFrame({
        'adate': [df['adate'].max(), df['adate'].max()],
        '6fwhm':
        [df_tol1.loc['Classic', 'lower6'], df_tol1.loc['Classic', 'upper6']],
        '9fwhm':
        [df_tol1.loc['Classic', 'lower9'], df_tol1.loc['Classic', 'upper9']],
        '12fwhm':
        [df_tol1.loc['Classic', 'lower12'], df_tol1.loc['Classic', 'upper12']],
        '16fwhm':
        [df_tol1.loc['Classic', 'lower16'], df_tol1.loc['Classic', 'upper16']],
        '20fwhm':
        [df_tol1.loc['Classic', 'lower20'], df_tol1.loc['Classic', 'upper20']]
    })
    print(df_tol_Classic)

    ############################################################################
    ############################################################################

    ##########################################################################
    ################### CREATE THE COLUMNS FOR THE LEGEND ######################

    # NB: The following section has been designed to be as general as possible
    # but in reality it might be preferable to more manually choose the markers
    # and colors based on optimising the most likey things to be plotted.
    #
    # This code is a way of creating a legend with markers based on one
    # parameter (e.g. machine name) and color on another parameter (e.g. energy)

    ######### Colors:
    # Create a sorted list of the unique values in a dataframe column that the
    # colors will be based on.
    list_forcolor = sorted(df['machinename'].unique().tolist())
    # If the length of the list is <9 then we can use the colorblind palette,
    # which contains 8 colors. This should be the default for accessability
    # reasons unless there are compeling reasons otherwise.
    if len(list_forcolor) < 9:
        color_palette = Colorblind[len(list_forcolor)]
    # If not <9 then we can use the much larger Turbo palette which contains
    # 256 colors. Will check if there are more than 256 options though and
    # throw an error if so.
    elif len(list_forcolor) > 256:
        print( 'Error - Name of Function: >256 unique energies in database ' \
          'causing failure of the turbo color palette function (only ' \
             '256 availible colors.' )
        exit()
    # If it passes the check then use the built in turbo function that splits
    # the turbo palette into roughly equal sections based on a supplied integer
    # number.
    else:
        color_palette = turbo(len(list_forcolor))

    ######### Markers:
    # Doesn't seem to be a way to create a simple list of all the Bokeh marker
    # options so just do this manually. May want to re-order to improve
    # visibility of commonly used options.
    markers = [
        'asterisk', 'circle', 'circle_cross', 'circle_x', 'cross', 'dash',
        'diamond', 'diamond_cross', 'hex', 'inverted_triangle', 'square',
        'square_cross', 'square_x', 'triangle', 'x'
    ]
    # Create a sorted list of the unique values in a dataframe column that the
    # markers will be based on.
    list_formarker = sorted(df['machinename'].unique().tolist())
    # Check that there are enough markers to give a unique marker to each option
    # but otherwise throw an error.
    if len(list_formarker) > len(markers):
        print( 'Error - Name of Function: Not enough markers to assign a ' \
            'unique marker to each option.' )
        exit()

    ######### Legend Key:
    # Create a function that will be used to run through the dataframe looking
    # at the energy and machine column and creating a new column that will have
    # values for both seperated by a '_', stored as a string.
    def add_legend(row):
        return str(str(row['machinename']))

    # Run the function and also copy the other columns into new columns so that
    # when ther are renamed to 'x' and 'y' later they are still availible for
    # the legend if needed.
    df.loc[:, 'legend'] = df.apply(lambda row: add_legend(row), axis=1)
    df.loc[:, 'machinename1'] = df.loc[:, 'machinename']
    print(df)

    ############################################################################
    ############################################################################

    ############################################################################
    ################## FORMATTING AND CREATING A BASIC PLOT ####################

    ############################################################################
    ############################# USER INPUTS ##################################

    # Decide what the default viewing option is going to be. (i.e. the fields to
    # be plotted on the x and y axis when the graph is opened, the plot size
    # etc.).

    # From the legend defined above give the values that will be pre-ticked when
    # the plot is opened
    color_to_plot = ['TrueBeam B', 'TrueBeam C']
    marker_to_plot = color_to_plot

    # Decide on what data to plot on the x/y axis when opened.
    x_data1 = 'adate'
    y_data1 = '6fwhm'
    # Decide what the plot formatting will be, inluding the plot title, axis
    # titles and the size of the plot.
    plot_title1 = 'Electron Energy'
    x_axis_title1 = x_data1
    y_axis_title1 = y_data1
    plot_size_height1 = 450
    plot_size_width1 = 800
    legend_location = 'bottom_left'

    # Create a list of the plot parameters that will be used as input to a
    # function later.
    list_plot_parameters = [
        x_data1, y_data1, plot_title1, x_axis_title1, y_axis_title1,
        plot_size_height1, plot_size_width1, legend_location
    ]

    ############################################################################
    ############################################################################

    ############################################################################
    ########################### CREATE THE PLOT ################################

    # Create the actual ploy. Generally it's a good idea to do this by defining
    # functions as they can then be used in the callbacks later without having
    # a lot of redundant very similar code.

    ######### Make Dataset:
    # Define a make dataset function that can be used now but also called later
    # in the callback functions to save re-writing similar code later.
    def make_dataset(color_to_plot, marker_to_plot, x_data1, y_data1):
        # Create a sub dataframe
        Sub_df1 = df.copy()
        # Delete any rows in the sub-dataframes that do not exist in the
        # checkboxes/default user choices. (e.g. if you've selected 6MV in the
        # checkbox this will remove any rows that have something other than 6MV)
        Sub_df1 = Sub_df1[Sub_df1['machinename'].isin(color_to_plot)]
        Sub_df1 = Sub_df1[Sub_df1['machinename'].isin(marker_to_plot)]
        # Search for the columns with the x_data and y_data names and replace
        # them with 'x' and 'y'. Unless plotting the same data on both in which
        # case add an extra column for 'y' that's a copy of 'x'
        if x_data1 == y_data1:
            Sub_df1.rename(columns={x_data1: 'x'}, inplace=True)
            Sub_df1.loc[:, 'y'] = Sub_df1.loc[:, 'x']
        else:
            Sub_df1.rename(columns={x_data1: 'x'}, inplace=True)
            Sub_df1.rename(columns={y_data1: 'y'}, inplace=True)
        # Return the newly created Sub_df1
        return Sub_df1

    # Run the make_dataset function to create a sub dataframe that the plot will
    # be made from.
    Sub_df1 = make_dataset(color_to_plot, marker_to_plot, x_data1, y_data1)

    # Create a Column Data Source. This is important as it is the data format
    # needed for Bokeh. When making this it is useful to convert the dataframe
    # into a dictionary, which seems to help with the callback function (see
    # 'Common Issues' for details).
    src1 = ColumnDataSource(Sub_df1.to_dict(orient='list'))

    ######### Make Plot:
    # Create an empty plot (plot parameters will be applied later in a way that
    # can be manipulated in the callbacks)
    p1 = figure()
    # Create a scatter plot.
    p1.scatter(  # source = The ColumnDataSource made above.
        source=src1,
        # x/y = 'x'/'y' which are fields that were renamed as such in
        # the make_dataset function
        x='x',
        y='y',
        # Some general parameters about marker size. These seem like
        # reasonable values but possible could alter these in a
        # callback?
        fill_alpha=0.4,
        size=12,
        # Create the legend using the created fields added in the legend
        # section. Use the factor_mark and factor_cmap functions to
        # match the colors/markers to the right lists.
        # NB: Always use legend_field for this not legend_group as the
        # former acts on the javascript side but the latter the Python
        # side. Therefore the former will update automatically when the
        # plot is changed with no need for a callback.
        legend_field='legend',
        marker=factor_mark('machinename1', markers, list_formarker),
        color=factor_cmap('machinename1', color_palette, list_forcolor))

    ######### Add plot parameters:
    # Define a define plot parameters factor that can be used now but also
    # called later in the callback functions.
    def define_plot_parameters(list):

        # Input is a List of format:
        # list_plot_parameters = [	x_data1, y_data1,
        # 	 						plot_title1, x_axis_title1, y_axis_title1,
        # 							plot_size_height1, plot_size_width1,
        # 							legend_location	]

        # The parameters have to be controlled like this in a callback to allow
        # for them to be adjusted. Otherwise the plot parameters are not
        # interactive.
        # 	Yes!	- p1.xaxis.axis_label = 'X_axis_title'
        # 	No! 	- p1 = figure(x_axis_label = 'X_axis_title')
        p1.title.text = list[2]
        p1.xaxis.axis_label = list[3]
        p1.yaxis.axis_label = list[4]
        p1.plot_height = list[5]
        p1.plot_width = list[6]
        p1.legend.location = list[7]

        # If the user wants to plot an axis as datetime then the axis needs to
        # be reformatted. Will do this by checking if the x_data1/y_data1 is
        # =='adate'.
        # NB: This only works if 'adate' is used as the name for the date column
        # and also that this is the only date column.
        if list[0] == 'adate':
            p1.xaxis.formatter = DatetimeTickFormatter(days=['%d/%m', '%a%d'])
        else:
            p1.xaxis.formatter = BasicTickFormatter()
        if list[1] == 'adate':
            p1.yaxis.formatter = DatetimeTickFormatter(days=['%d/%m', '%a%d'])
        else:
            p1.yaxis.formatter = BasicTickFormatter()

        return

    # Run the define_plot_parameters function to format the plot.
    define_plot_parameters(list_plot_parameters)

    ############################################################################
    ############################################################################

    ############################################################################
    ############################################################################

    ############################################################################
    ############################ ADD TOLERANCES ################################

    # We defined the tolerances further up and now want to add the correct ones
    # to the plot (having created the plot above). Again this will be done with
    # functions and in a way that the functions can be used in the callbacks
    # later.
    #
    # NB: At the moment this is still a bit of a work in progress and shows the
    # way to add line tolerances. Another option might be to add colorblocks
    # using varea and/or varea_stack.
    #
    # NB: Also this funcion assumes that tolerances will all be against one
    # x_axis value (e.g. date). This is probably the majority of use cases but
    # probably relatively trivial to add further toleraces against other x_axis
    # data.

    # Create a function that will create a dataframe that can be used to supply
    # a plot of two tolerance lines. This will including 'appearing' and
    # 'disappearing' depending on whether tolerances are defined or not.

    def tolerances(x_data1, y_data1, Sub_df1, df_tol1):

        # Get a list of the column headers from the tolerance table defined
        # earlier.
        headers1 = df_tol1.columns.values.tolist()

        # Check if the xdata is what is in the df_tol1 as the x_axis (if not no
        # point plotting tolerances as all tolerances are vs this tolerance).
        if x_data1 != headers1[0]:
            # x_data1 doesn't match so going to output something that should
            # basically just not plot but also won't throw the viewing range.
            data = {
                'x': [Sub_df1['x'].max(), Sub_df1['x'].max()],
                'y_low': [Sub_df1['y'].max(), Sub_df1['y'].max()],
                'y_high': [Sub_df1['y'].max(), Sub_df1['y'].max()]
            }
            Sub_df1_tol1 = pd.DataFrame(data)
            return Sub_df1_tol1
        # Otherwise we have the right x_data1 so now just check if it's datetime
        # or not.
        if x_data1 == 'adate':
            # It has the format 'adate' so should be datetime. So find the max
            # min dates in the Sub_df1 and add a couple of weeks either side so
            # that it plots the full range (plus a little bit for visualisation
            # reasons).
            max_x = Sub_df1['x'].max() + pd.DateOffset(weeks=2)
            min_x = Sub_df1['x'].min() + pd.DateOffset(weeks=-2)
        else:
            # If it's not datetime then just add about 5% of the range to
            # either side to make the plot look nicer.
            # NB: This has not been checked extensively as most tolerances are
            # vs. time.
            max_x = Sub_df1['x'].max()
            min_x = Sub_df1['x'].min()
            range = max_x - min_x
            max_x = max_x + (range / 20)
            min_x = min_x - (range / 20)

        # Used the x part so now remove the element from the list. This will
        # help for the small case where x_data1 == ydata1.
        headers1.remove(x_data1)

        if y_data1 in headers1:
            # If y_data1 is in the list then loop through to find out where and
            # get the data from the tolerance dataframe.
            for x in headers1:
                if y_data1 == x:
                    # When the loop has found where it is then can output a
                    # dataframe of the form:
                    # 	x = [far left of plot, far right of plot]
                    # 	y_low = [low_tolerance, low_tolerance]
                    # 	y_high = [high_tolerance, high_tolerance]
                    data = {
                        'x': [min_x, max_x],
                        'y_low': [df_tol1[x][0], df_tol1[x][0]],
                        'y_high': [df_tol1[x][1], df_tol1[x][1]]
                    }
                    Sub_df1_tol1 = pd.DataFrame(data)
        else:
            # If y_data1 is not in the headers1 list then there are no
            # tolerances to plot so going to output something that should
            # basically just not plot but also won't throw the viewing range.
            data = {
                'x': [Sub_df1['x'].max(), Sub_df1['x'].max()],
                'y_low': [Sub_df1['y'].max(), Sub_df1['y'].max()],
                'y_high': [Sub_df1['y'].max(), Sub_df1['y'].max()]
            }
            Sub_df1_tol1 = pd.DataFrame(data)
            return Sub_df1_tol1

        return Sub_df1_tol1

    def choose_tolerances(x_data1, y_data1, Sub_df1, color_to_plot):

        if any(item in color_to_plot for item in
               ['TrueBeam B', 'TrueBeam C', 'TrueBeam D', 'TrueBeam F']):
            # If this is true then will need to run the df_tol_TB tolerances
            Sub_df1_tol_TB = tolerances(x_data1, y_data1, Sub_df1, df_tol_TB)
        else:
            data = {
                'x': [Sub_df1['x'].max(), Sub_df1['x'].max()],
                'y_low': [Sub_df1['y'].max(), Sub_df1['y'].max()],
                'y_high': [Sub_df1['y'].max(), Sub_df1['y'].max()]
            }
            Sub_df1_tol_TB = pd.DataFrame(data)

        if any(item in color_to_plot
               for item in ['Linac B', 'Linac C', 'Linac D', 'Linac E']):
            # If this is true then will need to run the df_tol_TB tolerances
            Sub_df1_tol_Classic = tolerances(x_data1, y_data1, Sub_df1,
                                             df_tol_Classic)
        else:
            data = {
                'x': [Sub_df1['x'].max(), Sub_df1['x'].max()],
                'y_low': [Sub_df1['y'].max(), Sub_df1['y'].max()],
                'y_high': [Sub_df1['y'].max(), Sub_df1['y'].max()]
            }
            Sub_df1_tol_Classic = pd.DataFrame(data)

        return Sub_df1_tol_TB, Sub_df1_tol_Classic

    # Run the tolerances function to output the new dataframe
    Sub_df1_tol_TB, Sub_df1_tol_Classic = choose_tolerances(
        x_data1, y_data1, Sub_df1, color_to_plot)

    # Turn the dataframe into a new ColumnDataSource (again turning it into a
    # dictionary)
    src1_tol_TB = ColumnDataSource(Sub_df1_tol_TB.to_dict(orient='list'))
    src1_tol_Classic = ColumnDataSource(
        Sub_df1_tol_Classic.to_dict(orient='list'))

    # Add two lines to the plot using the new ColumnDataSource as the source,
    # one line for low tolerance and one line for high.
    p1.line(source=src1_tol_TB, x='x', y='y_low', color='firebrick')
    p1.line(source=src1_tol_TB, x='x', y='y_high', color='firebrick')
    p1.line(source=src1_tol_Classic, x='x', y='y_low', color='hotpink')
    p1.line(source=src1_tol_Classic, x='x', y='y_high', color='hotpink')

    ############################################################################
    ############################################################################

    ############################################################################
    ################## ADD MORE COMPLEX TOOLS TO THE PLOT ######################

    # Create tools here that will allow for some manipulation or inspection of
    # plotted data.
    #
    # As an example a 'HoverTool' will be added to the plot.
    #
    # Other useful tools and details of the syntax can be found here:
    # https://docs.bokeh.org/en/latest/docs/user_guide/tools.html

    # Create the hover tool (see website above for syntax/details).
    # This example creates a hover tool that displays:
    # 	Date: 			The value of the data-point as measued on the x-axis
    # 					(formatted for datetime)
    # 	Y-Axis:			The value of the data-point as measued on the y-axis
    # 	(x,y):			The x and y co-ordinates in plot space
    # 	Chamber Comb.:	The data stored under the 'Chamber' column for that
    # 					data-point.
    # 	Comments:		The data stored under the 'comments' column for that
    #					data-point.
    hover = HoverTool(tooltips=[('Date', '@x{%F}'), ('Y-Axis', '@y'),
                                ('(x,y)', '($x, $y)'),
                                ('Chamber Comb.', '@Chamber'),
                                ('Comments', '@comments')],
                      formatters={'x': 'datetime'})

    # Add the newly created tool to the plot.
    p1.add_tools(hover)

    ############################################################################
    ############################################################################

    ############################################################################
    ################# CREATE WIDGETS TO BE ADDED TO THE PLOT ###################

    # Create widgets here that will allow for some manipulation of the plotted
    # data. These widgets provide an interactive ability that can alter the data
    # that is plotted, provide update fnctions and call other programmatic
    # functions. This is done either using built in Bokeh functionality or
    # using more powerful but complex python and javascript based callbacks.
    #
    # As an example some 'Select' widgets, 'Checkbox' widgets and 'RangeSliders'
    # will be added to the plot.
    #
    # Other useful widgets and details of the syntax can be found here:
    # https://docs.bokeh.org/en/latest/docs/user_guide/interaction/widgets.html

    ######## 1)
    # Create the select widget (see website above for syntax/details). This
    # widget will be used for the callback example later to change data plotted
    # on the x/y-axis.
    # This example creates a select tool that displays:
    # 	Dropdown list containing a list of every field that was downloaded from
    # 	the database.
    # 	NB: 	When making a list it may be worth manually creating it to limit
    # 			it to the fields that can be plotted (e.g. not including fields
    # 			like 'Comments'). This will shorten the dropdown list but you
    # 			should err on the side of inclusion to make the final plot as
    # 			flexible as possible.
    #
    # Create a list of the availible options
    menu_axis = []
    for field in TableFields:
        menu_axis.append(field)
    menu_axis = sorted(menu_axis)
    # Select tool needs inputs for the title, a starting value and the just
    # created list to supply the available options.
    select_xaxis = Select(title='X-Axis Fields Available:',
                          value=x_axis_title1,
                          options=menu_axis)
    select_yaxis = Select(title='Y-Axis Fields Available:',
                          value=y_axis_title1,
                          options=menu_axis)

    ######## 2)
    # This select widget will be made in the same way and used to create a
    # dropdown list to change the legend position.
    #
    # Create a list of the availible options
    menu_legend = [
        'top_left', 'top_center', 'top_right', 'center_left', 'center',
        'center_right', 'bottom_left', 'bottom_center', 'bottom_right'
    ]
    # Create the select tool as above
    select_legend = Select(title='Legend Position',
                           value=legend_location,
                           options=menu_legend)

    ######## 3)
    # These checkbox widgets will be used to create a tool to select the
    # values that are being plotted from the fields that the legend is based on.
    #
    # NB: There is some built in Bokeh functionality for interavtive legends
    # that can fulfill some of the same goals where the number of options is
    # limited to something that can display on a reasonably sized legend. May
    # be a better and more robust solution where possible.

    # Create a list of all unique names in the column chosen to be matched to
    # markers (sorted).
    options_marker = sorted(df['machinename'].unique().tolist())
    # Create an index list for all of the values that should be pre-ticked.
    index_marker = [
        i for i in range(len(options_marker))
        if options_marker[i] in marker_to_plot
    ]
    # Create the checkbox, providing the list of availible options and a list
    # of what should be active (pre-ticked).
    checkbox_marker = CheckboxGroup(labels=options_marker,
                                    active=index_marker,
                                    visible=False)

    # Do the same for the column that was matched to colors.
    options_color = sorted(df['machinename'].unique().tolist())
    index_color = [
        i for i in range(len(options_color))
        if options_color[i] in color_to_plot
    ]
    checkbox_color = CheckboxGroup(labels=options_color, active=index_color)

    ######## 4)
    # Make some range sliders that will be used to manipulate the x-axis and
    # y-axis range.

    # Most of the manipulation will be done using a later function but will need
    # to create the bare minimum rangeslider first that can later be manipulated
    # (This seems to be the minimum number of parameters needed to create these
    # widgets). Note that a RangeSliders AND a DateRangeSlider needs to be
    # created for each axis.
    range_slider_x = RangeSlider(title='X-Axis Range',
                                 start=0,
                                 end=1,
                                 value=(0, 1),
                                 step=0.1)
    range_slider_y = RangeSlider(title='Y-Axis Range',
                                 start=0,
                                 end=1,
                                 value=(0, 1),
                                 step=0.1)
    range_slider_xdate = DateRangeSlider(title='X-Axis Range (Date)',
                                         start=date(2017, 1, 1),
                                         end=date(2017, 1, 2),
                                         value=(date(2017, 1,
                                                     1), date(2017, 1, 2)),
                                         step=1)
    range_slider_ydate = DateRangeSlider(title='Y-Axis Range (Date)',
                                         start=date(2017, 1, 1),
                                         end=date(2017, 1, 2),
                                         value=(date(2017, 1,
                                                     1), date(2017, 1, 2)),
                                         step=1)

    # Define the function that will be used now and also in the callbacks later.
    # This will allow the range_sliders to adjust to match any changes in the
    # data being plotted on the x/y axis.
    def range_slider(x_data1, y_data1, Sub_df1):

        # Start with the y-axis.
        # First need to check if 'adate' and if so edit the date range slider
        # but otherwise edit the normal slider.
        if y_data1 == 'adate':
            # Set the start, end and value fields to the full range.
            range_slider_ydate.start = Sub_df1['y'].min()
            range_slider_ydate.end = Sub_df1['y'].max()
            range_slider_ydate.value = (Sub_df1['y'].min(), Sub_df1['y'].max())
            # Step to 1 works for DateRangeSlider
            range_slider_ydate.step = 1
            # Make the DateRangeSlider visible and hide the normal RangeSlider
            range_slider_ydate.visible = True
            range_slider_y.visible = False
        else:
            # Set the start, end and value fields to the full range.
            range_slider_y.start = Sub_df1['y'].min()
            range_slider_y.end = Sub_df1['y'].max()
            range_slider_y.value = (Sub_df1['y'].min(), Sub_df1['y'].max())
            # Step to range/10000 should give sufficient granularity
            range_slider_y.step = (Sub_df1['y'].max() -
                                   Sub_df1['y'].min()) / 100000
            # Make the normal RangeSlider visible and hide the DateRangeSlider
            range_slider_y.visible = True
            range_slider_ydate.visible = False

        # Do the same for the x-axis
        if x_data1 == 'adate':
            range_slider_xdate.start = Sub_df1['x'].min()
            range_slider_xdate.end = Sub_df1['x'].max()
            range_slider_xdate.value = (Sub_df1['x'].min(), Sub_df1['x'].max())
            range_slider_xdate.step = 1
            range_slider_xdate.visible = True
            range_slider_x.visible = False
        else:
            range_slider_x.start = Sub_df1['x'].min()
            range_slider_x.end = Sub_df1['x'].max()
            range_slider_x.value = (Sub_df1['x'].min(), Sub_df1['x'].max())
            range_slider_x.step = (Sub_df1['x'].max() -
                                   Sub_df1['x'].min()) / 100000
            range_slider_x.visible = True
            range_slider_xdate.visible = False

        return

    # Run the function.
    range_slider(x_data1, y_data1, Sub_df1)

    ############################################################################
    ############################################################################

    ############################################################################
    ########################### CREATE A LAYOUT ################################

    # Create a layout to add widgets and arrange the display. This simple layout
    # displays the select widgets above the plot with the checkboxes to the
    # right (one above the other).
    #
    # More details can be found at:
    # https://docs.bokeh.org/en/latest/docs/user_guide/layout.html
    #
    # NB: More work to do here to make plots responsive to browser window size
    # (e.g. using sizing_mode = scale_both) but need to invstigate with/without
    # remote desktops.

    layout_checkbox = column([checkbox_marker, checkbox_color])
    layout_plots = column([
        select_xaxis, select_yaxis, select_legend, range_slider_x,
        range_slider_y, range_slider_xdate, range_slider_ydate, p1
    ])

    tab_layout = row([layout_plots, layout_checkbox])

    ############################################################################
    ############################################################################

    ############################################################################
    ####################### CREATE CALLBACK FUNCTIONS ##########################

    # CAVEAT: Callback functions are very complex and below is my (CB) rough
    # understanding of how they function based mainly on experience/trial and
    # error while writting these functions for other graphs. It should be taken
    # as a starting point but not as a definitive user guide.
    #
    # Callback functions are very powerful and can be based off of javascript or
    # python. The example presented here uses python but in future a javascript
    # copy should also be added.

    ######## 1)
    # This callback is designed to take inputs from the select and checkbox
    # widgets update the graph to plot the new data requested by the user.
    #
    # Syntax:
    # 	attr = 	The value passed from the on_change function before the callback
    # 			was named (e.g. in this example attr = 'value')
    # 	old = 	The value of the widget before it was changed (I.e. If a select
    # 			widget is changed from 'Output' to 'T/P Correction', then
    # 			old = 'Output'
    # 	new = 	The value of the widget after it was changed (I.e. If a select
    # 			widget is changed from 'Output' to 'T/P Correction', then
    # 			old = 'T/P Correction'
    #
    # 	NB: In general seen little need to use these inputs as you can generally
    # 	access the value of the widgets directly which seems to be more powerful
    # 	and flexible
    #
    # First define the callback function.
    def callback(attr, old, new):

        # Want to acquire the current values of all of the checkboxes and select
        # widgets to provide as inputs for the re-plot. For the checkboxes this
        # means itterating through the active list and outputting the labels
        # that are active
        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        marker_to_plot = color_to_plot
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value
        legend_location = select_legend.value

        # Use the pre-defined make_dataset function with these new inputs to
        # create a new version of the sub dataframe.
        Sub_df1 = make_dataset(color_to_plot, marker_to_plot,
                               plot1_xdata_to_plot, plot1_ydata_to_plot)

        # Use the pre-defined define_plot_parameters function with these new
        # inputs to update the plot parameters.
        x_axis_title1 = plot1_xdata_to_plot
        y_axis_title1 = plot1_ydata_to_plot
        define_plot_parameters([
            plot1_xdata_to_plot, plot1_ydata_to_plot, plot_title1,
            x_axis_title1, y_axis_title1, plot_size_height1, plot_size_width1,
            legend_location
        ])

        # Use the pre-defined tolerances function with these new inputs to
        # make a new version of the tolerances sub dataframe.
        Sub_df1_tol_TB, Sub_df1_tol_Classic = choose_tolerances(
            plot1_xdata_to_plot, plot1_ydata_to_plot, Sub_df1, color_to_plot)

        # Use the pre-defined range_slider function with these new inputs to
        # update the range sliders (this will make sure that the range sliders
        # start/end etc. match up with what's being plotted, as well as
        # displaying/hiding the RangeSlider/DateRangeSlider as needed
        range_slider(plot1_xdata_to_plot, plot1_ydata_to_plot, Sub_df1)

        # Update the ColumnDataSources using the newly created dataframes. The
        # plots look to these as the source so this changes what is being
        # plotted.
        src1.data = Sub_df1.to_dict(orient='list')
        src1_tol_TB.data = Sub_df1_tol_TB.to_dict(orient='list')
        src1_tol_Classic.data = Sub_df1_tol_Classic.to_dict(orient='list')

        return

    # Use the on_change function to call the now defined callback function
    # whenever the user changes the value in the widget.
    # NB: Other functions such as on_click are availible for other widgets.
    # Syntax:
    # 	First argument is passed to the callback as attr (see callback section
    # 	above)
    # 	Second argument is the name of the callback function to be called.
    select_xaxis.on_change('value', callback)
    select_yaxis.on_change('value', callback)
    select_legend.on_change('value', callback)
    checkbox_color.on_change('active', callback)
    checkbox_marker.on_change('active', callback)

    ######## 2)
    # This callback is designed to take inputs from the range sliders to change
    # visible range
    def callback_range(attr, old, new):

        # Check what is currently being plotted. Need this to know whether to
        # look for the values from the DateRangeSlider or the RangeSlider
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value

        # Start with the x-axis
        if plot1_xdata_to_plot == 'adate':
            # If it's 'adate' then need to look at the DateRangeSlider and
            # update the start and end values of the range using the values from
            # the slider.
            # NB: range_slider.value = left_value, right_value
            p1.x_range.start, p1.x_range.end = range_slider_xdate.value
        else:
            # If it's not 'adate' then need to look at the normal RangeSlider
            p1.x_range.start, p1.x_range.end = range_slider_x.value

        # Do the same for the y-axis
        if plot1_ydata_to_plot == 'adate':
            p1.y_range.start, p1.y_range.end = range_slider_ydate.value
        else:
            p1.y_range.start, p1.y_range.end = range_slider_y.value

        return

    # Use the on_change function to call the now defined callback function
    # whenever the user changes the value in the widget.
    range_slider_x.on_change('value', callback_range)
    range_slider_y.on_change('value', callback_range)
    range_slider_xdate.on_change('value', callback_range)
    range_slider_ydate.on_change('value', callback_range)

    ############################################################################
    ############################################################################

    ############################################################################
    ####################### RETURN TO THE MAIN SCRIPT ##########################

    # Now that the script is finished and the plot created we can return to the
    # main script.
    #
    # To pass back the data for the tab we need to return a Panel with:
    # 	child = layout (the one that we made earlier with the widget and plot)
    # 	title = 'Something that makes sense as a tab label for the user'

    return Panel(child=tab_layout, title='Electron Energy')
markers = ['hex', 'cross', 'triangle']

scatter_plot_subgroups = figure(plot_width=600, 
                                plot_height=400, 
                                title ='Iris', 
                                x_axis_label='petalLength', 
                                y_axis_label='petalWidth')

scatter_plot_subgroups.scatter(x='petalLength',
                               y='petalWidth',
                               source=iris,
                               legend='species',
                               fill_alpha=0.5,
                               size=15,
                               color=factor_cmap(field_name='species', palette='Dark2_3', factors=species),
                               marker=factor_mark('species', markers, species)
                              )

# move legend
scatter_plot_subgroups.legend.location = 'top_left'
show(scatter_plot_subgroups)
In [73]:
# scatter_plot_subgroups.scatter?
Subplots
In [74]:
from bokeh.layouts import gridplot

output_notebook()

# data
subplot_x1 = cars['Acceleration']; subplot_y1 = cars['Miles_per_Gallon']
示例#15
0
def make_summary_plot(source, table_source, pars_dict):

    tools = "pan,wheel_zoom,box_zoom,box_select,tap,hover,reset,crosshair"

    pars = [
        'M1_init', 'M2_init', 'P_init', 'q_init', 'product', 'stability',
        'termination_code'
    ]
    basic_tooltip = [(p, '@' + p) for p in pars]

    PRODUCTS = ['HB', 'He-WD', 'CE', 'UK', 'failed', 'sdO', 'sdB', 'sdA'] + \
               ['stable', 'CE', 'contact', 'merger'] +\
               ['single-lined', 'composite']
    MARKERS = ['square', 'triangle', 'asterisk', 'asterisk', 'diamond', 'circle', 'circle', 'circle'] + \
              ['circle', 'diamond', 'square', 'triangle', ] +\
              ['circle', 'circle']
    COLORS = ['red', 'green', 'purple', 'purple', 'gray', 'green', 'blue', 'orange'] + \
             ['red', 'green', 'blue', 'gray'] +\
             ['gray', 'blue']
    SIZES = [7, 7, 7, 7, 15, 7]

    v_func = """
            const norm = new Float64Array(xs.length)
            for (let i = 0; i < xs.length; i++) {
                if (xs[i] == 'sdB' || xs[i] == 'Fail' || xs[i] == 'CE') {
                        norm[i] = 15
                } else {
                        norm[i] = 7
                }
            }
            return norm
            """
    size_transform = mpl.CustomJSTransform(v_func=v_func)

    # Left Figure
    p1 = figure(x_axis_label=pars_dict['x1'],
                y_axis_label=pars_dict['y1'],
                active_drag='box_select',
                tools=tools,
                tooltips=basic_tooltip)

    p1.scatter(
        x="x1",
        y="y1",
        source=source,
        fill_alpha=0.4,
        size=transform('z1', size_transform),
        color=factor_cmap('z1', COLORS, PRODUCTS),
        marker=factor_mark('z1', MARKERS, PRODUCTS),
    )  # legend_group="z1",

    # Right Figure
    p2 = figure(x_axis_label=pars_dict['x2'],
                y_axis_label=pars_dict['y2'],
                active_drag='box_select',
                tools=tools,
                tooltips=basic_tooltip)

    p2.scatter(
        x="x2",
        y="y2",
        source=source,
        fill_alpha=0.4,
        size=transform('z2', size_transform),
        color=factor_cmap('z2', COLORS, PRODUCTS),
        marker=factor_mark('z2', MARKERS, PRODUCTS),
    )  # legend_group="z2",

    # color_bar2 = mpl.ColorBar(color_mapper=color_mapper, location=(0,0), title=pars_dict['color2'], title_text_font_size='12pt')
    # p2.add_layout(color_bar2, 'right')

    plot = gridplot([[p1, p2]])

    # add interaction when selecting a model
    callback = CustomJS(args=dict(summary_source=source,
                                  table_source=table_source),
                        code="""
            selected_indices = summary_source.selected.indices;
            
            console.log(summary_source.selected.indices[0]);
            console.log(summary_source);
            
            if (summary_source.selected.indices.length > 0){
                var data = summary_source.data;
                var ind = summary_source.selected.indices[0];
                var parameters = table_source.data['parameters']
                var values = table_source.data['values']
                
                parameters.forEach(function (par, index) {
                    values[index] = data[par][ind];
                });
                
                //table_source.data['parameters'] = x;
                table_source.data['values'] = values;
                
                table_source.change.emit();
            }
            
            """)
    p1.js_on_event('tap', callback)
    p2.js_on_event('tap', callback)

    return plot, p1, p2
           y_axis_type="log",
           plot_height=400,
           plot_width=700,
           tools=[
               HoverTool(tooltips=[(
                   'Country',
                   '@country'), ('Confirmed Cases',
                                 '@total_cases'), ('Date', '@date_formatted')])
           ])

p.scatter("date",
          "total_cases",
          source=source,
          fill_alpha=0.4,
          size=6,
          marker=factor_mark('country', MARKERS, COUNTRIES),
          color=factor_cmap('country', 'Category10_5', COUNTRIES))

output_file("COVID19_1.html", title="Total Number of Confirmed COVID-19 Cases")

show(p)

# %%
#Plotting log-scale number of cases for the selected countries. Hover-tool and series-hiding on.

from bokeh.plotting import figure, show, output_file
from bokeh.models import ColumnDataSource, CDSView, GroupFilter, HoverTool

source = ColumnDataSource(covid)
source.add(covid['date'].apply(lambda d: d.strftime('%Y-%m-%d')),
           'date_formatted')
示例#17
0
				x = 'x',
				y = 'y',
				# Some general parameters about marker size. These seem like
				# reasonable values but possible could alter these in a
				# callback?
				fill_alpha = 0.4,
				size = 12,
				# Create the legend using the created fields added in the legend
				# section. Use the factor_mark and factor_cmap functions to
				# match the colors/markers to the right lists.
				# NB: Always use legend_field for this not legend_group as the
				# former acts on the javascript side but the latter the Python
				# side. Therefore the former will update automatically when the
				# plot is changed with no need for a callback.
				legend_field = 'legend',
				marker = factor_mark('marker1', marker_palette, marker_list),
				color = factor_cmap('color1', color_palette, color_list)
				)


	######### Add plot parameters:
	# Run the Define_Plot_Parameters function to format the plot. Takes the plot
	# and the pre-defined list of default plot parameters as inputs.
	Define_Plot_Parameters(p1, list_plot_parameters)

	############################################################################
	############################################################################



示例#18
0
FATE = ['Died', 'Lived']
MARKERS = ['cross', 'circle']

# Set the Title a and size of plot
p = figure(plot_height=600,
           plot_width=971,
           title="Titanic Passenger Age & Fare by Survial Type")

# Construnct the colours
p.scatter("Fare",
          "Age",
          source=titanic_df,
          legend="Survived",
          fill_alpha=0.3,
          size=12,
          marker=factor_mark('Survived', MARKERS, FATE),
          color=factor_cmap('Survived', ['#3a6587', '#aeb3b7'], FATE))

# Set axis labels
p.xaxis.axis_label = 'Fare (In Pounds)'
p.yaxis.axis_label = 'Age (In Years)'

# Remove the Grid lines
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None

# change just some things about the x-axis
p.xaxis.axis_line_width = 2
p.xaxis.major_label_text_color = "black"
p.xaxis.axis_line_color = "#aeb3b7"
示例#19
0
from bokeh.plotting import figure, show, output_file
from bokeh.sampledata.iris import flowers
from bokeh.transform import factor_cmap, factor_mark

SPECIES = ['setosa', 'versicolor', 'virginica']
MARKERS = ['hex', 'circle_x', 'triangle']

p = figure(title = "Iris Morphology", background_fill_color="#fafafa")
p.xaxis.axis_label = 'Petal Length'
p.yaxis.axis_label = 'Sepal Width'

p.scatter("petal_length", "sepal_width", source=flowers, legend="species", fill_alpha=0.4, size=12,
          marker=factor_mark('species', MARKERS, SPECIES),
          color=factor_cmap('species', 'Category10_3', SPECIES))

output_file("marker_map.html")

show(p)
示例#20
0
def photometry_plot(obj_id, user, width=600, device="browser"):
    """Create object photometry scatter plot.

    Parameters
    ----------
    obj_id : str
        ID of Obj to be plotted.

    Returns
    -------
    dict
        Returns Bokeh JSON embedding for the desired plot.
    """

    data = pd.read_sql(
        DBSession()
        .query(
            Photometry,
            Telescope.nickname.label("telescope"),
            Instrument.name.label("instrument"),
        )
        .join(Instrument, Instrument.id == Photometry.instrument_id)
        .join(Telescope, Telescope.id == Instrument.telescope_id)
        .filter(Photometry.obj_id == obj_id)
        .filter(
            Photometry.groups.any(Group.id.in_([g.id for g in user.accessible_groups]))
        )
        .statement,
        DBSession().bind,
    )

    if data.empty:
        return None, None, None

    # get spectra to annotate on phot plots
    spectra = (
        Spectrum.query_records_accessible_by(user)
        .filter(Spectrum.obj_id == obj_id)
        .all()
    )

    data['color'] = [get_color(f) for f in data['filter']]

    # get marker for each unique instrument
    instruments = list(data.instrument.unique())
    markers = []
    for i, inst in enumerate(instruments):
        markers.append(phot_markers[i % len(phot_markers)])

    filters = list(set(data['filter']))
    colors = [get_color(f) for f in filters]

    color_mapper = CategoricalColorMapper(factors=filters, palette=colors)
    color_dict = {'field': 'filter', 'transform': color_mapper}

    labels = []
    for i, datarow in data.iterrows():
        label = f'{datarow["instrument"]}/{datarow["filter"]}'
        if datarow['origin'] is not None:
            label += f'/{datarow["origin"]}'
        labels.append(label)

    data['label'] = labels
    data['zp'] = PHOT_ZP
    data['magsys'] = 'ab'
    data['alpha'] = 1.0
    data['lim_mag'] = (
        -2.5 * np.log10(data['fluxerr'] * PHOT_DETECTION_THRESHOLD) + data['zp']
    )

    # Passing a dictionary to a bokeh datasource causes the frontend to die,
    # deleting the dictionary column fixes that
    del data['original_user_data']

    # keep track of things that are only upper limits
    data['hasflux'] = ~data['flux'].isna()

    # calculate the magnitudes - a photometry point is considered "significant"
    # or "detected" (and thus can be represented by a magnitude) if its snr
    # is above PHOT_DETECTION_THRESHOLD
    obsind = data['hasflux'] & (
        data['flux'].fillna(0.0) / data['fluxerr'] >= PHOT_DETECTION_THRESHOLD
    )
    data.loc[~obsind, 'mag'] = None
    data.loc[obsind, 'mag'] = -2.5 * np.log10(data[obsind]['flux']) + PHOT_ZP

    # calculate the magnitude errors using standard error propagation formulae
    # https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulae
    data.loc[~obsind, 'magerr'] = None
    coeff = 2.5 / np.log(10)
    magerrs = np.abs(coeff * data[obsind]['fluxerr'] / data[obsind]['flux'])
    data.loc[obsind, 'magerr'] = magerrs
    data['obs'] = obsind
    data['stacked'] = False

    split = data.groupby('label', sort=False)

    finite = np.isfinite(data['flux'])
    fdata = data[finite]
    lower = np.min(fdata['flux']) * 0.95
    upper = np.max(fdata['flux']) * 1.05

    xmin = data['mjd'].min() - 2
    xmax = data['mjd'].max() + 2

    # Layout parameters based on device type
    active_drag = None if "mobile" in device or "tablet" in device else "box_zoom"
    tools = (
        'box_zoom,pan,reset'
        if "mobile" in device or "tablet" in device
        else "box_zoom,wheel_zoom,pan,reset,save"
    )
    legend_loc = "below" if "mobile" in device or "tablet" in device else "right"
    legend_orientation = (
        "vertical" if device in ["browser", "mobile_portrait"] else "horizontal"
    )

    # Compute a plot component height based on rough number of legend rows added below the plot
    # Values are based on default sizing of bokeh components and an estimate of how many
    # legend items would fit on the average device screen. Note that the legend items per
    # row is computed more exactly later once labels are extracted from the data (with the
    # add_plot_legend() function).
    #
    # The height is manually computed like this instead of using built in aspect_ratio/sizing options
    # because with the new Interactive Legend approach (instead of the legacy CheckboxLegendGroup), the
    # Legend component is considered part of the plot and plays into the sizing computations. Since the
    # number of items in the legend can alter the needed heights of the plot, using built-in Bokeh options
    # for sizing does not allow for keeping the actual graph part of the plot at a consistent aspect ratio.
    #
    # For the frame width, by default we take the desired plot width minus 64 for the y-axis/label taking
    # up horizontal space
    frame_width = width - 64
    if device == "mobile_portrait":
        legend_items_per_row = 1
        legend_row_height = 24
        aspect_ratio = 1
    elif device == "mobile_landscape":
        legend_items_per_row = 4
        legend_row_height = 50
        aspect_ratio = 1.8
    elif device == "tablet_portrait":
        legend_items_per_row = 5
        legend_row_height = 50
        aspect_ratio = 1.5
    elif device == "tablet_landscape":
        legend_items_per_row = 7
        legend_row_height = 50
        aspect_ratio = 1.8
    elif device == "browser":
        # Width minus some base width for the legend, which is only a column to the right
        # for browser mode
        frame_width = width - 200

    height = (
        500
        if device == "browser"
        else math.floor(width / aspect_ratio)
        + legend_row_height * int(len(split) / legend_items_per_row)
        + 30  # 30 is the height of the toolbar
    )

    plot = figure(
        frame_width=frame_width,
        height=height,
        active_drag=active_drag,
        tools=tools,
        toolbar_location='above',
        toolbar_sticky=True,
        y_range=(lower, upper),
        min_border_right=16,
        x_axis_location='above',
        sizing_mode="stretch_width",
    )

    plot.xaxis.axis_label = 'MJD'
    now = Time.now().mjd
    plot.extra_x_ranges = {"Days Ago": Range1d(start=now - xmin, end=now - xmax)}
    plot.add_layout(LinearAxis(x_range_name="Days Ago", axis_label="Days Ago"), 'below')

    imhover = HoverTool(tooltips=tooltip_format)
    imhover.renderers = []
    plot.add_tools(imhover)

    model_dict = {}
    legend_items = []
    for i, (label, sdf) in enumerate(split):
        renderers = []

        # for the flux plot, we only show things that have a flux value
        df = sdf[sdf['hasflux']]

        key = f'obs{i}'
        model_dict[key] = plot.scatter(
            x='mjd',
            y='flux',
            color='color',
            marker=factor_mark('instrument', markers, instruments),
            fill_color=color_dict,
            alpha='alpha',
            source=ColumnDataSource(df),
        )
        renderers.append(model_dict[key])
        imhover.renderers.append(model_dict[key])

        key = f'bin{i}'
        model_dict[key] = plot.scatter(
            x='mjd',
            y='flux',
            color='color',
            marker=factor_mark('instrument', markers, instruments),
            fill_color=color_dict,
            source=ColumnDataSource(
                data=dict(
                    mjd=[],
                    flux=[],
                    fluxerr=[],
                    filter=[],
                    color=[],
                    lim_mag=[],
                    mag=[],
                    magerr=[],
                    stacked=[],
                    instrument=[],
                )
            ),
        )
        renderers.append(model_dict[key])
        imhover.renderers.append(model_dict[key])

        key = 'obserr' + str(i)
        y_err_x = []
        y_err_y = []

        for d, ro in df.iterrows():
            px = ro['mjd']
            py = ro['flux']
            err = ro['fluxerr']

            y_err_x.append((px, px))
            y_err_y.append((py - err, py + err))

        model_dict[key] = plot.multi_line(
            xs='xs',
            ys='ys',
            color='color',
            alpha='alpha',
            source=ColumnDataSource(
                data=dict(
                    xs=y_err_x, ys=y_err_y, color=df['color'], alpha=[1.0] * len(df)
                )
            ),
        )
        renderers.append(model_dict[key])

        key = f'binerr{i}'
        model_dict[key] = plot.multi_line(
            xs='xs',
            ys='ys',
            color='color',
            # legend_label=label,
            source=ColumnDataSource(data=dict(xs=[], ys=[], color=[])),
        )
        renderers.append(model_dict[key])

        legend_items.append(LegendItem(label=label, renderers=renderers))

    if device == "mobile_portrait":
        plot.xaxis.ticker.desired_num_ticks = 5
    plot.yaxis.axis_label = 'Flux (μJy)'
    plot.toolbar.logo = None

    add_plot_legend(plot, legend_items, width, legend_orientation, legend_loc)
    slider = Slider(
        start=0.0,
        end=15.0,
        value=0.0,
        step=1.0,
        title='Binsize (days)',
        max_width=350,
        margin=(4, 10, 0, 10),
    )

    callback = CustomJS(
        args={'slider': slider, 'n_labels': len(split), **model_dict},
        code=open(
            os.path.join(os.path.dirname(__file__), '../static/js/plotjs', 'stackf.js')
        )
        .read()
        .replace('default_zp', str(PHOT_ZP))
        .replace('detect_thresh', str(PHOT_DETECTION_THRESHOLD)),
    )

    slider.js_on_change('value', callback)

    # Mark the first and last detections
    detection_dates = data[data['hasflux']]['mjd']
    if len(detection_dates) > 0:
        first = round(detection_dates.min(), 6)
        last = round(detection_dates.max(), 6)
        first_color = "#34b4eb"
        last_color = "#8992f5"
        midpoint = (upper + lower) / 2
        line_top = 5 * upper - 4 * midpoint
        line_bottom = 5 * lower - 4 * midpoint
        y = np.linspace(line_bottom, line_top, num=5000)
        first_r = plot.line(
            x=np.full(5000, first),
            y=y,
            line_alpha=0.5,
            line_color=first_color,
            line_width=2,
        )
        plot.add_tools(
            HoverTool(
                tooltips=[("First detection", f'{first}')],
                renderers=[first_r],
            )
        )
        last_r = plot.line(
            x=np.full(5000, last),
            y=y,
            line_alpha=0.5,
            line_color=last_color,
            line_width=2,
        )
        plot.add_tools(
            HoverTool(
                tooltips=[("Last detection", f'{last}')],
                renderers=[last_r],
            )
        )

    # Mark when spectra were taken
    annotate_spec(plot, spectra, lower, upper)
    layout = column(slider, plot, width=width, height=height)

    p1 = Panel(child=layout, title='Flux')

    # now make the mag light curve
    ymax = (
        np.nanmax(
            (
                np.nanmax(data.loc[obsind, 'mag']) if any(obsind) else np.nan,
                np.nanmax(data.loc[~obsind, 'lim_mag']) if any(~obsind) else np.nan,
            )
        )
        + 0.1
    )
    ymin = (
        np.nanmin(
            (
                np.nanmin(data.loc[obsind, 'mag']) if any(obsind) else np.nan,
                np.nanmin(data.loc[~obsind, 'lim_mag']) if any(~obsind) else np.nan,
            )
        )
        - 0.1
    )

    plot = figure(
        frame_width=frame_width,
        height=height,
        active_drag=active_drag,
        tools=tools,
        y_range=(ymax, ymin),
        x_range=(xmin, xmax),
        toolbar_location='above',
        toolbar_sticky=True,
        x_axis_location='above',
        sizing_mode="stretch_width",
    )

    plot.xaxis.axis_label = 'MJD'
    now = Time.now().mjd
    plot.extra_x_ranges = {"Days Ago": Range1d(start=now - xmin, end=now - xmax)}
    plot.add_layout(LinearAxis(x_range_name="Days Ago", axis_label="Days Ago"), 'below')

    obj = DBSession().query(Obj).get(obj_id)
    if obj.dm is not None:
        plot.extra_y_ranges = {
            "Absolute Mag": Range1d(start=ymax - obj.dm, end=ymin - obj.dm)
        }
        plot.add_layout(
            LinearAxis(y_range_name="Absolute Mag", axis_label="m - DM"), 'right'
        )

    # Mark the first and last detections again
    detection_dates = data[obsind]['mjd']
    if len(detection_dates) > 0:
        first = round(detection_dates.min(), 6)
        last = round(detection_dates.max(), 6)
        midpoint = (ymax + ymin) / 2
        line_top = 5 * ymax - 4 * midpoint
        line_bottom = 5 * ymin - 4 * midpoint
        y = np.linspace(line_bottom, line_top, num=5000)
        first_r = plot.line(
            x=np.full(5000, first),
            y=y,
            line_alpha=0.5,
            line_color=first_color,
            line_width=2,
        )
        plot.add_tools(
            HoverTool(
                tooltips=[("First detection", f'{first}')],
                renderers=[first_r],
            )
        )
        last_r = plot.line(
            x=np.full(5000, last),
            y=y,
            line_alpha=0.5,
            line_color=last_color,
            line_width=2,
        )
        plot.add_tools(
            HoverTool(
                tooltips=[("Last detection", f'{last}')],
                renderers=[last_r],
                point_policy='follow_mouse',
            )
        )

    # Mark when spectra were taken
    annotate_spec(plot, spectra, ymax, ymin)

    imhover = HoverTool(tooltips=tooltip_format)
    imhover.renderers = []
    plot.add_tools(imhover)

    model_dict = {}

    # Legend items are individually stored instead of being applied
    # directly when plotting so that they can be separated into multiple
    # Legend() components if needed (to simulate horizontal row wrapping).
    # This is necessary because Bokeh does not support row wrapping with
    # horizontally-oriented legends out-of-the-box.
    legend_items = []
    for i, (label, df) in enumerate(split):
        renderers = []

        key = f'obs{i}'
        model_dict[key] = plot.scatter(
            x='mjd',
            y='mag',
            color='color',
            marker=factor_mark('instrument', markers, instruments),
            fill_color=color_dict,
            alpha='alpha',
            source=ColumnDataSource(df[df['obs']]),
        )
        renderers.append(model_dict[key])
        imhover.renderers.append(model_dict[key])

        unobs_source = df[~df['obs']].copy()
        unobs_source.loc[:, 'alpha'] = 0.8

        key = f'unobs{i}'
        model_dict[key] = plot.scatter(
            x='mjd',
            y='lim_mag',
            color=color_dict,
            marker='inverted_triangle',
            fill_color='white',
            line_color='color',
            alpha='alpha',
            source=ColumnDataSource(unobs_source),
        )
        renderers.append(model_dict[key])
        imhover.renderers.append(model_dict[key])

        key = f'bin{i}'
        model_dict[key] = plot.scatter(
            x='mjd',
            y='mag',
            color=color_dict,
            marker=factor_mark('instrument', markers, instruments),
            fill_color='color',
            source=ColumnDataSource(
                data=dict(
                    mjd=[],
                    flux=[],
                    fluxerr=[],
                    filter=[],
                    color=[],
                    lim_mag=[],
                    mag=[],
                    magerr=[],
                    instrument=[],
                    stacked=[],
                )
            ),
        )
        renderers.append(model_dict[key])
        imhover.renderers.append(model_dict[key])

        key = 'obserr' + str(i)
        y_err_x = []
        y_err_y = []

        for d, ro in df[df['obs']].iterrows():
            px = ro['mjd']
            py = ro['mag']
            err = ro['magerr']

            y_err_x.append((px, px))
            y_err_y.append((py - err, py + err))

        model_dict[key] = plot.multi_line(
            xs='xs',
            ys='ys',
            color='color',
            alpha='alpha',
            source=ColumnDataSource(
                data=dict(
                    xs=y_err_x,
                    ys=y_err_y,
                    color=df[df['obs']]['color'],
                    alpha=[1.0] * len(df[df['obs']]),
                )
            ),
        )
        renderers.append(model_dict[key])

        key = f'binerr{i}'
        model_dict[key] = plot.multi_line(
            xs='xs',
            ys='ys',
            color='color',
            source=ColumnDataSource(data=dict(xs=[], ys=[], color=[])),
        )
        renderers.append(model_dict[key])

        key = f'unobsbin{i}'
        model_dict[key] = plot.scatter(
            x='mjd',
            y='lim_mag',
            color='color',
            marker='inverted_triangle',
            fill_color='white',
            line_color=color_dict,
            alpha=0.8,
            source=ColumnDataSource(
                data=dict(
                    mjd=[],
                    flux=[],
                    fluxerr=[],
                    filter=[],
                    color=[],
                    lim_mag=[],
                    mag=[],
                    magerr=[],
                    instrument=[],
                    stacked=[],
                )
            ),
        )
        imhover.renderers.append(model_dict[key])
        renderers.append(model_dict[key])

        key = f'all{i}'
        model_dict[key] = ColumnDataSource(df)

        key = f'bold{i}'
        model_dict[key] = ColumnDataSource(
            df[
                [
                    'mjd',
                    'flux',
                    'fluxerr',
                    'mag',
                    'magerr',
                    'filter',
                    'zp',
                    'magsys',
                    'lim_mag',
                    'stacked',
                ]
            ]
        )

        legend_items.append(LegendItem(label=label, renderers=renderers))

    add_plot_legend(plot, legend_items, width, legend_orientation, legend_loc)

    plot.yaxis.axis_label = 'AB mag'
    plot.toolbar.logo = None

    slider = Slider(
        start=0.0,
        end=15.0,
        value=0.0,
        step=1.0,
        title='Binsize (days)',
        max_width=350,
        margin=(4, 10, 0, 10),
    )

    button = Button(label="Export Bold Light Curve to CSV")
    button.js_on_click(
        CustomJS(
            args={'slider': slider, 'n_labels': len(split), **model_dict},
            code=open(
                os.path.join(
                    os.path.dirname(__file__), '../static/js/plotjs', "download.js"
                )
            )
            .read()
            .replace('objname', obj_id)
            .replace('default_zp', str(PHOT_ZP)),
        )
    )

    # Don't need to expose CSV download on mobile
    top_layout = (
        slider if "mobile" in device or "tablet" in device else row(slider, button)
    )

    callback = CustomJS(
        args={'slider': slider, 'n_labels': len(split), **model_dict},
        code=open(
            os.path.join(os.path.dirname(__file__), '../static/js/plotjs', 'stackm.js')
        )
        .read()
        .replace('default_zp', str(PHOT_ZP))
        .replace('detect_thresh', str(PHOT_DETECTION_THRESHOLD)),
    )
    slider.js_on_change('value', callback)
    layout = column(top_layout, plot, width=width, height=height)

    p2 = Panel(child=layout, title='Mag')

    # now make period plot

    # get periods from annotations
    annotation_list = obj.get_annotations_readable_by(user)
    period_labels = []
    period_list = []
    for an in annotation_list:
        if 'period' in an.data:
            period_list.append(an.data['period'])
            period_labels.append(an.origin + ": %.9f" % an.data['period'])

    if len(period_list) > 0:
        period = period_list[0]
    else:
        period = None
    # don't generate if no period annotated
    if period is not None:
        # bokeh figure for period plotting
        period_plot = figure(
            frame_width=frame_width,
            height=height,
            active_drag=active_drag,
            tools=tools,
            y_range=(ymax, ymin),
            x_range=(-0.01, 2.01),  # initially one phase
            toolbar_location='above',
            toolbar_sticky=False,
            x_axis_location='below',
            sizing_mode="stretch_width",
        )

        # axis labels
        period_plot.xaxis.axis_label = 'phase'
        period_plot.yaxis.axis_label = 'mag'
        period_plot.toolbar.logo = None

        # do we have a distance modulus (dm)?
        obj = DBSession().query(Obj).get(obj_id)
        if obj.dm is not None:
            period_plot.extra_y_ranges = {
                "Absolute Mag": Range1d(start=ymax - obj.dm, end=ymin - obj.dm)
            }
            period_plot.add_layout(
                LinearAxis(y_range_name="Absolute Mag", axis_label="m - DM"), 'right'
            )

        # initiate hover tool
        period_imhover = HoverTool(tooltips=tooltip_format)
        period_imhover.renderers = []
        period_plot.add_tools(period_imhover)

        # initiate period radio buttons
        period_selection = RadioGroup(labels=period_labels, active=0)

        phase_selection = RadioGroup(labels=["One phase", "Two phases"], active=1)

        # store all the plot data
        period_model_dict = {}

        # iterate over each filter
        legend_items = []
        for i, (label, df) in enumerate(split):
            renderers = []
            # fold x-axis on period in days
            df['mjd_folda'] = (df['mjd'] % period) / period
            df['mjd_foldb'] = df['mjd_folda'] + 1.0

            # phase plotting
            for ph in ['a', 'b']:
                key = 'fold' + ph + f'{i}'
                period_model_dict[key] = period_plot.scatter(
                    x='mjd_fold' + ph,
                    y='mag',
                    color='color',
                    marker=factor_mark('instrument', markers, instruments),
                    fill_color=color_dict,
                    alpha='alpha',
                    # visible=('a' in ph),
                    source=ColumnDataSource(df[df['obs']]),  # only visible data
                )
                # add to hover tool
                period_imhover.renderers.append(period_model_dict[key])
                renderers.append(period_model_dict[key])

                # errorbars for phases
                key = 'fold' + ph + f'err{i}'
                y_err_x = []
                y_err_y = []

                # get each visible error value
                for d, ro in df[df['obs']].iterrows():
                    px = ro['mjd_fold' + ph]
                    py = ro['mag']
                    err = ro['magerr']
                    # set up error tuples
                    y_err_x.append((px, px))
                    y_err_y.append((py - err, py + err))
                # plot phase errors
                period_model_dict[key] = period_plot.multi_line(
                    xs='xs',
                    ys='ys',
                    color='color',
                    alpha='alpha',
                    # visible=('a' in ph),
                    source=ColumnDataSource(
                        data=dict(
                            xs=y_err_x,
                            ys=y_err_y,
                            color=df[df['obs']]['color'],
                            alpha=[1.0] * len(df[df['obs']]),
                        )
                    ),
                )
                renderers.append(period_model_dict[key])

            legend_items.append(LegendItem(label=label, renderers=renderers))

        add_plot_legend(
            period_plot, legend_items, width, legend_orientation, legend_loc
        )

        # set up period adjustment text box
        period_title = Div(text="Period (days): ")
        period_textinput = TextInput(value=str(period if period is not None else 0.0))
        period_textinput.js_on_change(
            'value',
            CustomJS(
                args={
                    'textinput': period_textinput,
                    'numphases': phase_selection,
                    'n_labels': len(split),
                    'p': period_plot,
                    **period_model_dict,
                },
                code=open(
                    os.path.join(
                        os.path.dirname(__file__), '../static/js/plotjs', 'foldphase.js'
                    )
                ).read(),
            ),
        )
        # a way to modify the period
        period_double_button = Button(label="*2", width=30)
        period_double_button.js_on_click(
            CustomJS(
                args={'textinput': period_textinput},
                code="""
                const period = parseFloat(textinput.value);
                textinput.value = parseFloat(2.*period).toFixed(9);
                """,
            )
        )
        period_halve_button = Button(label="/2", width=30)
        period_halve_button.js_on_click(
            CustomJS(
                args={'textinput': period_textinput},
                code="""
                        const period = parseFloat(textinput.value);
                        textinput.value = parseFloat(period/2.).toFixed(9);
                        """,
            )
        )
        # a way to select the period
        period_selection.js_on_click(
            CustomJS(
                args={'textinput': period_textinput, 'periods': period_list},
                code="""
                textinput.value = parseFloat(periods[this.active]).toFixed(9);
                """,
            )
        )
        phase_selection.js_on_click(
            CustomJS(
                args={
                    'textinput': period_textinput,
                    'numphases': phase_selection,
                    'n_labels': len(split),
                    'p': period_plot,
                    **period_model_dict,
                },
                code=open(
                    os.path.join(
                        os.path.dirname(__file__), '../static/js/plotjs', 'foldphase.js'
                    )
                ).read(),
            )
        )

        # layout
        if device == "mobile_portrait":
            period_controls = column(
                row(
                    period_title,
                    period_textinput,
                    period_double_button,
                    period_halve_button,
                    width=width,
                    sizing_mode="scale_width",
                ),
                phase_selection,
                period_selection,
                width=width,
            )
            # Add extra height to plot based on period control components added
            # 18 is the height of each period selection radio option (per default font size)
            # and the 130 encompasses the other components which are consistent no matter
            # the data size.
            height += 130 + 18 * len(period_labels)
        else:
            period_controls = column(
                row(
                    period_title,
                    period_textinput,
                    period_double_button,
                    period_halve_button,
                    phase_selection,
                    width=width,
                    sizing_mode="scale_width",
                ),
                period_selection,
                margin=10,
            )
            # Add extra height to plot based on period control components added
            # Numbers are derived in similar manner to the "mobile_portrait" case above
            height += 90 + 18 * len(period_labels)

        period_layout = column(period_plot, period_controls, width=width, height=height)

        # Period panel
        p3 = Panel(child=period_layout, title='Period')

        # tabs for mag, flux, period
        tabs = Tabs(tabs=[p2, p1, p3], width=width, height=height, sizing_mode='fixed')
    else:
        # tabs for mag, flux
        tabs = Tabs(tabs=[p2, p1], width=width, height=height + 90, sizing_mode='fixed')
    return bokeh_embed.json_item(tabs)
示例#21
0
    ("BowlerType", "@BowlerType"),
]


# Set the Title
p = figure(title = "Top Test Bowlers by Decade (1877-1919)",
    tooltips=TOOLTIPS_SCATTER, 
    x_range=(0, 30),
    y_range=(0, 200),
    plot_width=1280, plot_height=800)

p.title.text_font_size = '24pt'

# Construnct the colours
p.scatter("Average", "Wickets", source=titanic_df, legend="RightHand", fill_alpha=0.9, size=24,
          marker=factor_mark('RightHand', MARKERS, FATE),
          color=factor_cmap('RightHand', palette=['#aeb3b7', '#3a6587'], factors=FATE))

#Set the axis labels
p.xaxis.axis_label = 'Career Bowling Average'
p.yaxis.axis_label = 'Total Career Wickets'

# Remove the Grid lines
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None

# change just some things about the x-axis
p.xaxis.axis_line_width = 2
p.xaxis.major_label_text_color = "black"
p.xaxis.axis_line_color = "#aeb3b7"
示例#22
0
def get_total_infected_people_figure(colors):
    with open(SOURCES_FILE_PATH) as f:
        source_data = json.load(f)

    df = pd.DataFrame(source_data['image'])

    df = pd.DataFrame(df.stack(), columns=['rate']).reset_index()

    mapper = LinearColorMapper(palette=colors,
                               low=df.rate.min(),
                               high=df.rate.max())

    TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom"

    # Create a figure with a datetime type x-axis
    fig = figure(title=source_data['name'],
                 plot_height=900,
                 plot_width=900,
                 x_axis_label=source_data['x'],
                 y_axis_label=source_data['y'],
                 x_minor_ticks=5,
                 y_range=(0, 50),
                 x_range=(0, 50),
                 y_minor_ticks=5,
                 y_scale=Scale(),
                 toolbar_location='below',
                 tools=TOOLS,
                 tooltips=[])

    rects = fig.rect(x='level_0',
                     y='level_1',
                     width=1,
                     height=1,
                     source=df,
                     fill_color={
                         'field': 'rate',
                         'transform': mapper
                     },
                     line_color=None)

    stars = fig.scatter("petal_length",
                        "sepal_width",
                        source=flowers,
                        legend_field="species",
                        fill_alpha=0.4,
                        size=12,
                        marker=factor_mark('species', MARKERS, SPECIES),
                        color=factor_cmap('species', 'Category10_3', SPECIES))

    g1_hover = bkm.HoverTool(renderers=[rects], tooltips=[('rects', 'rects')])

    g2_hover = bkm.HoverTool(renderers=[stars], tooltips=[('stars', 'stars')])

    fig.add_tools(g1_hover, g2_hover)

    color_bar = ColorBar(color_mapper=mapper,
                         major_label_text_font_size="5pt",
                         ticker=BasicTicker(desired_num_ticks=len(colors)),
                         formatter=PrintfTickFormatter(format="%d%%"),
                         label_standoff=6,
                         border_line_color=None,
                         location=(0, 0))

    tap_tool_1 = TapTool(behavior='inspect',
                         callback=CustomJS(args=dict(),
                                           code=get_callback_function('red')),
                         renderers=[rects])

    tap_tool_2 = TapTool(
        behavior='inspect',
        callback=CustomJS(args=dict(), code=get_callback_function('violet')),
        renderers=[stars])

    fig.add_tools(tap_tool_1, tap_tool_2)

    fig.add_layout(color_bar, 'right')

    return fig
示例#23
0
def Gulmay_Output_Graph(conn):

	output_file("PDD_Graph.html") #????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????


	'''

	In order to make a simple plot easy to create we're going to define all of
	the user inputs up front. Then pull the data out of the database and
	add a simple tolerance dataframe if necessary.

	For a first plot this may be all that is needed but to make a more complex
	plot the writer may need to add details further down.

	Remember that:
		*	The dataframe will not have capital letters in the field names due
			to a quirk of the read_sql function.
		*	The date field MUST be called 'adate' and of the format 'datetime'
			in order for parts of the code to function correctly

	'''

	############################################################################
	############################################################################

	############################################################################
 	############################# USER INPUTS ##################################

	# Decide what the default viewing option is going to be. (i.e. the fields to
	# be plotted on the x and y axis when the graph is opened, the plot size
	# etc.).
	#
	# Decide on what data to plot on the x/y axis when opened (enter the field
	# names here)
	x_data1 = 'adate'
	y_data1 = 'output'
	# Decide what the plot formatting will be, inluding the plot title, axis
	# titles and the size of the plot. A good generic start point is to use the
	# field names as the axis titles but future plots could potentially use a
	# look up table to give more user friendly titles.
	plot_title1 = 'Gulmay Output'
	x_axis_title1 = x_data1
	y_axis_title1 = y_data1
	plot_size_height1 = 450
	plot_size_width1 = 800
	legend_location = 'bottom_left'
	# Set the fields that will display in the hovertool in addition to the x and
	# y fields (NB: Can have a maximum of 10 options here). (Useful example
	# defaults would be the comments field or maybe chamber/electrometer?)
	hover_tool_fields = ['comments', 'input by', 'checked by']
	# Create a list of the plot parameters that will be used as input to a
	# function later.
	list_plot_parameters = [x_data1, y_data1, plot_title1, x_axis_title1,
		y_axis_title1, plot_size_height1, plot_size_width1, legend_location]

	# Define the fields that the legend will be based off. If there is only
	# one field then put it in both columns.
	#
	# If the default options in the function are not acceptable then change the
	# boolean to True and then set the palette to the color and marker palettes
	# that you want (they will be mapped against a 'sorted' list of the unique
	# values from the fields).
	color_column = 'energy'
	custom_color_boolean = False
	custom_color_palette = []
	marker_column = 'energy'
	custom_marker_boolean = False
	custom_marker_palette = []
	# From the legend defined above give the values that will be pre-ticked when
	# the plot is opened. NB: Bokeh will throw an error if one of these lists is
	# empty (i.e. =[]) If only using color or marker then set the color_to plot
	# and then enter the command:  color_to_plot = marker_to_plot.
	# color_to_plot = ['Gulmay']
	marker_to_plot = ['100 kV', '150 kV', '220 kV']
	color_to_plot = marker_to_plot

	############################################################################
	#################### CREATE THE DATA FOR THE GRAPH #########################

	# Do this in a function so it can be used in an update callback later

	def Create_df():

		# Use the connection passed to the function to read the data into a
		# dataframe via an SQL query.
		df = pd.read_sql('select [gulmay session ID], [output], ' \
			'[chamber and electrometer], [Chamber factor], [Dose rate], ' \
			'[energy], [T/P factor], [Temp], [Press], [Comments], ' \
			'[Input by], [Checked by] from [gulmay output]', conn)

		# Delete empty rows where the data is very important to have
		df = df.dropna(subset=['gulmay session id'])
		df = df.dropna(subset=['energy'])

		# The format is complicated for this field but seems to be that the date is
		# always the first element and the machine is always the last regardless of
		# how many elements there are.
		# Seperate on the first '_'
		df_left = df['gulmay session id'].str.partition(sep = '_')
		# Seperate on the last '_'
		df_right = df['gulmay session id'].str.rpartition(sep = '_')
		# From these sperated dataframes add the appropriate columns back into
		# the main dataframe.
		df.loc[:,'adate'] = df_left[0]
		df.loc[:,'machinename'] = df_right[2]

		# Turn 'adate' into datetime.
		df.loc[:,'adate'] = pd.to_datetime(df.loc[:,'adate'], dayfirst=True)

		# Drop any columns where there is no data
		df = df.dropna(axis='columns', how='all')

		return df

	df = Create_df()

	# Create a list of the fields using the dataframe. By doing it now before
	# the extra legend fields are added it's easy to limit what is displayed in
	# the select widgets.
	TableFields = (list(df.columns))

	############################################################################
	############################################################################




 	############################################################################
 	################ CREATE THE DATAFRAME FOR THE TOLERANCES ###################

	# If you want to add tolerances change the boolean to True and construct the
	# dataframe in the correct format.
	tolerance_boolean = True
	# The format of the dataframe should be the first line being the x_axis
	# (with some values taken from the main dataframe to get the right
	# formatting). The subsequent columns are the tolerances [low, high].
	# NB: column names should match those from the main dataframe.
	if tolerance_boolean == True:
		df_tol1 = pd.DataFrame({'adate':[df['adate'].max(), df['adate'].max()],
								'output':[97, +103]})
	############################################################################
	############################################################################

	############################################################################
	############################################################################

	'''

	This is the end of the user input section. If you don't need to make any
	other changes you can end here.

	'''







	##########################################################################
	################### CREATE THE COLUMNS FOR THE LEGEND ######################

	(color_list, color_palette, marker_list, marker_palette, df,
		add_legend_to_df) = Create_Legend(df, color_column,
		custom_color_boolean, custom_color_palette, marker_column,
		custom_marker_boolean, custom_marker_palette)

	############################################################################
	############################################################################






 	############################################################################
 	################## FORMATTING AND CREATING A BASIC PLOT ####################

	######### Make Dataset:
	# Run the Make_Dataset function to create a sub dataframe that the plot will
	# be made from.
	Sub_df1 = Make_Dataset(	df, color_column, color_to_plot, marker_column,
		marker_to_plot, x_data1, y_data1	)

	# Make the ColumnDataSource (when making convert dataframe to a dictionary,
	# which is helpful for the callback).
	src1 = ColumnDataSource(Sub_df1.to_dict(orient='list'))


	######### Make Plot:
	# Create an empty plot (plot parameters will be applied later in a way that
	# can be manipulated in the callbacks)
	p1 = figure()
	# Create a scatter plot.
	p1.scatter(	source = src1,
				x = 'x',
				y = 'y',
				fill_alpha = 0.4,
				size = 12,
				# NB: Always use legend_field for this not legend_group as the
				# former acts on the javascript side but the latter the Python
				# side. Therefore the former will update automatically.
				legend_field = 'legend',
				marker = factor_mark('marker1', marker_palette, marker_list),
				color = factor_cmap('color1', color_palette, color_list)
				)


	# Run the Define_Plot_Parameters function to format the plot.
	Define_Plot_Parameters(p1, list_plot_parameters)

	############################################################################
	############################################################################






	############################################################################
 	############################ ADD TOLERANCES ################################

	# We defined the tolerances further up and now want to add the correct ones
	# to the plot. Only do this through if the boolean is set to True as
	# otherwise the user doesn't want tolerances.
	if tolerance_boolean == True:

		Sub_df1_tol1 = Make_Dataset_Tolerance(x_data1, y_data1, Sub_df1,
			df_tol1)

		src1_tol = ColumnDataSource(Sub_df1_tol1.to_dict(orient='list'))

		# Add two lines to the plot using the new ColumnDataSource as the
		# source, one line for low tolerance and one line for high.
		p1.line(source = src1_tol, x = 'x', y = 'y_low', color = 'firebrick')
		p1.line(source = src1_tol, x = 'x', y = 'y_high', color = 'firebrick')

	############################################################################
	############################################################################






 	############################################################################
 	################## ADD MORE COMPLEX TOOLS TO THE PLOT ######################

	######## 1)
	# Create a hover tool and add it to the plot

	hover1 = HoverTool()

	if len(hover_tool_fields) < 11:
		kwargs = {}
		i = 0
		for x in hover_tool_fields:
			i = i+1
			kwargs['Field'+str(i)] = x
	else:
		kwargs = {}
		msgbox('Too many fields selected to display on HoverTool ' \
			'(Max = 10). Please reduce number of fields selected')

	Update_HoverTool(hover1, x_data1, y_data1, **kwargs)

	p1.add_tools(hover1)


	############################################################################
	############################################################################






 	############################################################################
 	################# CREATE WIDGETS TO BE ADDED TO THE PLOT ###################

 	######## 1)
	# This funtion from Universal.py will be used to create dropdown lists to
	# change the data plotted on the x/y-axis.
	select_xaxis, select_yaxis = Create_Select_Axis(TableFields, x_axis_title1,
		y_axis_title1)


 	######## 2)
	# This function from Universal.py will be used to create a dropdown list to
	# change the legend position.
	select_legend = Create_Select_Legend(legend_location)


	######## 3)
	# This funtion from Universal.py will be used to create checkbox widgets to
	# change the data being plotted from the fields that the legend is based on.
	checkbox_color, checkbox_marker = Create_Checkbox_Legend(df, color_column,
		color_to_plot, marker_column, marker_to_plot)


	######## 4)
	# This funtion from Universal.py will be used to create a checkbox widget
	# to change the fields included in the hovertool.
	checkbox_hovertool = Create_Checkbox_HoverTool(TableFields,
		hover_tool_fields)


	######## 5)
	# Make an 'Update Button' to requery the database and get up to date data.
	update_button = Button(label='Update', button_type='success')

	######## 6)
	# Make a Range Button
	range_button = Button(label='Range', button_type='primary')

	######## 7)
	# Make some titles for the checkboxes
	color_title = Div(text='<b>Energy</b>')
	marker_title = Div(text='<b>Energ</b>')
	hover_title = Div(text='<b>Hovertool Fields</b>')

	############################################################################
	############################################################################






	############################################################################
	########################### CREATE A LAYOUT ################################

	# Create a layout where the widgets will be added and any scaling applied.
	if color_column == marker_column:
		layout_checkbox = column([color_title, checkbox_color, hover_title,
		checkbox_hovertool])
	else:
		layout_checkbox = column([color_title, checkbox_color, marker_title,
			checkbox_marker, hover_title, checkbox_hovertool])

	button_row = row([update_button, range_button])

	layout_plots = column([	button_row, select_xaxis, select_yaxis,
							select_legend,p1])

	tab_layout = row([layout_plots, layout_checkbox])

	############################################################################
	############################################################################





 	############################################################################
 	####################### CREATE CALLBACK FUNCTIONS ##########################

	# Create a big callback that does most stuff
	def callback(attr, old, new):

		# Want to acquire the current values of all of the checkboxes and select
		# widgets to provide as inputs for the re-plot.
		color_to_plot = [checkbox_color.labels[i] for i in
			checkbox_color.active]
		if color_column != marker_column:
			marker_to_plot = [checkbox_marker.labels[i] for i in
				checkbox_marker.active]
		else:
			marker_to_plot = color_to_plot
		hovertool_to_plot = [checkbox_hovertool.labels[i] for i in
			checkbox_hovertool.active]
		plot1_xdata_to_plot = select_xaxis.value
		plot1_ydata_to_plot = select_yaxis.value
		legend_location = select_legend.value
		# Set the new axis titles from the values just acquired.
		x_axis_title1 = plot1_xdata_to_plot
		y_axis_title1 = plot1_ydata_to_plot

		# Use the pre-defined Make_Dataset function with these new inputs to
		# create new versions of the sub dataframes.
		Sub_df1 = Make_Dataset(	df, color_column, color_to_plot, marker_column,
			marker_to_plot, plot1_xdata_to_plot, plot1_ydata_to_plot)

		# Use the pre-defined Define_Plot_Parameters function with these new
		# inputs to update the plot parameters.
		Define_Plot_Parameters(p1, [plot1_xdata_to_plot, plot1_ydata_to_plot,
	 		plot_title1, x_axis_title1, y_axis_title1, plot_size_height1,
			plot_size_width1, legend_location])

		# Update the hovertool
		if len(hovertool_to_plot) < 11:
			kwargs = {}
			i = 0
			for x in hovertool_to_plot:
				i = i+1
				kwargs['Field'+str(i)] = x
		else:
			kwargs = {}
			msgbox('Too many fields selected to display on HoverTool ' \
				'(Max = 10). Please reduce number of fields selected')
		Update_HoverTool(hover1, plot1_xdata_to_plot, plot1_ydata_to_plot,
			**kwargs)

		# Use the pre-defined tolerances function with these new inputs to
		# make a new version of the tolerances sub dataframe.
		if tolerance_boolean == True:
			Sub_df1_tol1 = Make_Dataset_Tolerance(plot1_xdata_to_plot,
				plot1_ydata_to_plot, Sub_df1, df_tol1)
			src1_tol.data = Sub_df1_tol1.to_dict(orient='list')

		# Update the ColumnDataSources
		src1.data = Sub_df1.to_dict(orient='list')

		return

	select_xaxis.on_change('value', callback)
	select_yaxis.on_change('value', callback)
	select_legend.on_change('value', callback)
	checkbox_color.on_change('active', callback)
	checkbox_marker.on_change('active', callback)
	checkbox_hovertool.on_change('active', callback)


	######## 2)
	# This callback is designed to update the plotted data with new values from
	# the database
	def callback_update():

		# Make a new version of the dataframe using the original Create_df
		# function that connects to the database.
		df = Create_df()
		df = add_legend_to_df(df)

		# The rest of this callback is a copy from the original callback above.
		color_to_plot = [checkbox_color.labels[i] for i in
			checkbox_color.active]
		if color_column != marker_column:
			marker_to_plot = [checkbox_marker.labels[i] for i in
				checkbox_marker.active]
		else:
			marker_to_plot = color_to_plot
		hovertool_to_plot = [checkbox_hovertool.labels[i] for i in
			checkbox_hovertool.active]
		plot1_xdata_to_plot = select_xaxis.value
		plot1_ydata_to_plot = select_yaxis.value
		legend_location = select_legend.value
		# Set the new axis titles from the values just acquired.
		x_axis_title1 = plot1_xdata_to_plot
		y_axis_title1 = plot1_ydata_to_plot

		Sub_df1 = Make_Dataset(	df, color_column, color_to_plot, marker_column,
			marker_to_plot, plot1_xdata_to_plot, plot1_ydata_to_plot)

		Define_Plot_Parameters(p1, [plot1_xdata_to_plot, plot1_ydata_to_plot,
	 		plot_title1, x_axis_title1, y_axis_title1, plot_size_height1,
			plot_size_width1, legend_location])

		if len(hovertool_to_plot) < 11:
			kwargs = {}
			i = 0
			for x in hovertool_to_plot:
				i = i+1
				kwargs['Field'+str(i)] = x
		else:
			kwargs = {}
			msgbox('Too many fields selected to display on HoverTool ' \
				'(Max = 10). Please reduce number of fields selected')

		Update_HoverTool(hover1, plot1_xdata_to_plot, plot1_ydata_to_plot,
			**kwargs)

		if tolerance_boolean == True:
			Sub_df1_tol1 = Make_Dataset_Tolerance(plot1_xdata_to_plot,
				plot1_ydata_to_plot, Sub_df1, df_tol1)
			src1_tol.data = Sub_df1_tol1.to_dict(orient='list')

		src1.data = Sub_df1.to_dict(orient='list')

		return

	update_button.on_click(callback_update)


	# Callback for the Range Button
	def callback_range():

		color_to_plot = [	checkbox_color.labels[i] for i in
							checkbox_color.active]
		if color_column != marker_column:
			marker_to_plot = [	checkbox_marker.labels[i] for i in
								checkbox_marker.active]
		else:
			marker_to_plot = color_to_plot
		plot1_xdata_to_plot = select_xaxis.value
		plot1_ydata_to_plot = select_yaxis.value

		# Use the pre-defined Make_Dataset function with these new inputs to
		# create new versions of the sub dataframes.
		Sub_df1 = Make_Dataset(	df, color_column, color_to_plot, marker_column,
			marker_to_plot, plot1_xdata_to_plot, plot1_ydata_to_plot)

		if (plot1_xdata_to_plot == 'adate') and (plot1_ydata_to_plot == 'output'):

			p1.x_range.start = Sub_df1['x'].max() - timedelta(weeks=53)
			p1.x_range.end = Sub_df1['x'].max() + timedelta(weeks=2)

			if plot1_ydata_to_plot == 'output':
				p1.y_range.start = 95
				p1.y_range.end = 105

		return

	range_button.on_click(callback_range)

	############################################################################
	############################################################################



 	############################################################################
 	####################### RETURN TO THE MAIN SCRIPT ##########################

	return Panel(child = tab_layout, title = 'Gulmay Output')
示例#24
0
def plot_scatter(label=None,
                 water=None,
                 stakeholders=None,
                 costs=None,
                 potAll=None):

    # needs some heavy refactoring...

    data_path = os.path.join(os.getcwd(), '..', 'input_files', 'input',
                             'measures')

    data_fname = 'stats_measures.csv'

    df = pd.read_csv(os.path.join(data_path, data_fname))

    fill_alpha = 0.7
    line_width = 1

    # Plain adding a column with marker sizes
    marker_size = len(df) * [10]

    df['marker_size'] = marker_size

    # Add the user defined measure, in case
    if not (label is None and water is None and stakeholders is None
            and costs is None and potAll is None):

        colour = 'gold'
        marker = 'hex'
        marker_size = 20

        row = pd.DataFrame([[
            label, water, colour, costs, potAll, stakeholders, marker,
            marker_size
        ]],
                           columns=[
                               'labels', 'dwl_Qref', 'colour', 'cost_sum',
                               'FI', 'nr_stakeholders', 'marker', 'marker_size'
                           ])

        df = df.append(row)

    subplot_width = 275
    subplot_height = subplot_width
    min_border = 0
    delta_offset_left = 50

    categories = df['labels']
    markers = df['marker']
    marker_sizes = df['marker_size']

    pot_ymin = 60
    pot_ymax = 180

    colours = df['colour']

    y = 'nr_stakeholders'

    toolset = ['pan', 'box_zoom', 'wheel_zoom', 'zoom_in', 'zoom_out', 'reset']

    subfig11 = figure(plot_width=subplot_width + delta_offset_left,
                      plot_height=subplot_height,
                      min_border_left=min_border,
                      min_border_bottom=min_border,
                      toolbar_location='above',
                      tools=toolset)
    x = 'dwl_Qref'

    v1 = 'dwl_Qref'
    v2 = 'nr_stakeholders'
    pp = pareto_points(df[[v1, v2]])
    subfig11.line(pp[v1], pp[v2], line_width=20, color='gray', line_alpha=0.25)

    scatter11 = subfig11.scatter(x,
                                 y,
                                 source=df,
                                 size='marker_size',
                                 marker=factor_mark('labels', markers,
                                                    categories),
                                 color=factor_cmap('labels', colours,
                                                   categories),
                                 fill_alpha=fill_alpha,
                                 line_width=line_width)
    subfig11.yaxis.axis_label = 'No. of stakeholders (-)'

    subfig11.add_tools(
        HoverTool(tooltips=[('', '@labels')], renderers=[scatter11]))

    y = 'FI'

    subfig21 = figure(plot_width=subplot_width + delta_offset_left,
                      plot_height=subplot_height,
                      min_border_left=min_border,
                      min_border_bottom=min_border,
                      tools=toolset,
                      toolbar_location=None,
                      x_range=subfig11.x_range)
    x = 'dwl_Qref'

    v1 = 'dwl_Qref'
    v2 = 'FI'
    pp = pareto_points(pd.concat([df[['dwl_Qref']], -df[['FI']]], axis=1))
    subfig21.line(pp[v1],
                  -pp[v2],
                  line_width=20,
                  color='gray',
                  line_alpha=0.25)

    scatter21 = subfig21.scatter(x,
                                 y,
                                 source=df,
                                 size='marker_size',
                                 marker=factor_mark('labels', markers,
                                                    categories),
                                 color=factor_cmap('labels', colours,
                                                   categories),
                                 fill_alpha=fill_alpha,
                                 line_width=line_width)
    subfig21.yaxis.axis_label = 'PotAll (-)'
    subfig21.y_range = Range1d(pot_ymax, pot_ymin)

    subfig21.add_tools(
        HoverTool(tooltips=[('', '@labels')], renderers=[scatter21]))

    subfig22 = figure(plot_width=subplot_width,
                      plot_height=subplot_height,
                      min_border_left=min_border,
                      min_border_bottom=min_border,
                      tools=toolset,
                      toolbar_location=None,
                      y_range=subfig21.y_range)
    x = 'nr_stakeholders'

    v1 = 'nr_stakeholders'
    v2 = 'FI'
    pp = pareto_points(
        pd.concat([df[['nr_stakeholders']], -df[['FI']]], axis=1))
    subfig22.line(pp[v1],
                  -pp[v2],
                  line_width=20,
                  color='gray',
                  line_alpha=0.25)

    scatter22 = subfig22.scatter(x,
                                 y,
                                 source=df,
                                 size='marker_size',
                                 marker=factor_mark('labels', markers,
                                                    categories),
                                 color=factor_cmap('labels', colours,
                                                   categories),
                                 fill_alpha=fill_alpha,
                                 line_width=line_width)
    subfig22.yaxis.major_label_text_font_size = '0pt'

    subfig22.add_tools(
        HoverTool(tooltips=[('', '@labels')], renderers=[scatter22]))

    y = 'cost_sum'

    subfig31 = figure(plot_width=subplot_width + delta_offset_left,
                      plot_height=subplot_height,
                      min_border_left=min_border,
                      min_border_bottom=min_border,
                      tools=toolset,
                      toolbar_location=None,
                      x_range=subfig11.x_range)
    x = 'dwl_Qref'

    v1 = 'dwl_Qref'
    v2 = 'cost_sum'
    pp = pareto_points(df[[v1, v2]])
    subfig31.line(pp[v1], pp[v2], line_width=20, color='gray', line_alpha=0.25)

    scatter31 = subfig31.scatter(x,
                                 y,
                                 source=df,
                                 size='marker_size',
                                 marker=factor_mark('labels', markers,
                                                    categories),
                                 color=factor_cmap('labels', colours,
                                                   categories),
                                 fill_alpha=fill_alpha,
                                 line_width=line_width)
    subfig31.yaxis.axis_label = 'Implementation costs (\u20AC)'
    subfig31.xaxis.axis_label = 'Water level lowering (m)'

    subfig31.add_tools(
        HoverTool(tooltips=[('', '@labels')], renderers=[scatter31]))

    subfig32 = figure(plot_width=subplot_width,
                      plot_height=subplot_height,
                      min_border_left=min_border,
                      min_border_bottom=min_border,
                      tools=toolset,
                      toolbar_location=None,
                      x_range=subfig22.x_range,
                      y_range=subfig31.y_range)
    x = 'nr_stakeholders'

    v1 = 'nr_stakeholders'
    v2 = 'cost_sum'
    subfig32.circle(0,
                    0,
                    line_width=20,
                    fill_color='gray',
                    color='gray',
                    line_alpha=0.25)

    scatter32 = subfig32.scatter(x,
                                 y,
                                 source=df,
                                 size='marker_size',
                                 marker=factor_mark('labels', markers,
                                                    categories),
                                 color=factor_cmap('labels', colours,
                                                   categories),
                                 fill_alpha=fill_alpha,
                                 line_width=line_width)
    subfig32.yaxis.major_label_text_font_size = '0pt'
    subfig32.xaxis.axis_label = 'No. of stakeholders (-)'

    subfig32.add_tools(
        HoverTool(tooltips=[('', '@labels')], renderers=[scatter32]))

    subfig33 = figure(plot_width=subplot_width,
                      plot_height=subplot_height,
                      min_border_left=min_border,
                      min_border_bottom=min_border,
                      tools=toolset,
                      toolbar_location=None,
                      y_range=subfig31.y_range)
    x = 'FI'

    v1 = 'FI'
    v2 = 'cost_sum'
    pp = pareto_points(
        pd.concat([-df[[v1]], df[[v2]]],
                  axis=1))  # pd.concat([df[[v1], -df[[v2]]], axis=1))
    #df[[v1, v2]])
    subfig33.line(-pp[v1],
                  pp[v2],
                  line_width=20,
                  color='gray',
                  line_alpha=0.25)

    scatter33 = subfig33.scatter(x,
                                 y,
                                 source=df,
                                 size='marker_size',
                                 marker=factor_mark('labels', markers,
                                                    categories),
                                 color=factor_cmap('labels', colours,
                                                   categories),
                                 fill_alpha=fill_alpha,
                                 line_width=line_width)
    subfig33.yaxis.major_label_text_font_size = '0pt'
    subfig33.x_range = Range1d(pot_ymax, pot_ymin)
    subfig33.xaxis.axis_label = 'PotAll (-)'

    subfig33.add_tools(
        HoverTool(tooltips=[('', '@labels')], renderers=[scatter33]))

    matrix = gridplot([[subfig11, None, None], [subfig21, subfig22, None],
                       [subfig31, subfig32, subfig33]],
                      toolbar_location='above')

    show(matrix)
示例#25
0
items = []

cmap = viridis(len(species))

counter = 0

for index, animal in enumerate(species):
    source = ColumnDataSource(
        dataframe.loc[dataframe['AnimalGroupParent'] == animal])
    scatters[animal] = m.scatter(x='x_mercator',
                                 y='y_mercator',
                                 source=source,
                                 fill_alpha=0.3,
                                 size=15,
                                 color=cmap[index],
                                 marker=factor_mark('AnimalGroupParent',
                                                    markers, species),
                                 visible=False,
                                 muted_alpha=0.00)
    items.append((animal, [scatters[animal]]))

    hover = m.select(dict(type=HoverTool))
    hover.tooltips = [
        ("Animal", "@AnimalGroupParent"),
    ]
    hover.mode = 'mouse'

legend = Legend(items=items)
m.add_layout(legend)
m.legend.location = 'top_left'
m.legend.click_policy = 'hide'
m.legend.label_text_font_size = "10px"
from bokeh.plotting import figure, show
from bokeh.sampledata.iris import flowers
from bokeh.transform import factor_cmap, factor_mark

SPECIES = ['setosa', 'versicolor', 'virginica']
MARKERS = ['hex', 'circle_x', 'triangle']

p = figure(title="Iris Morphology")
p.xaxis.axis_label = 'Petal Length'
p.yaxis.axis_label = 'Sepal Width'

p.scatter("petal_length",
          "sepal_width",
          source=flowers,
          legend_field="species",
          fill_alpha=0.4,
          size=12,
          marker=factor_mark('species', MARKERS, SPECIES),
          color=factor_cmap('species', 'Category10_3', SPECIES))

show(p)
示例#27
0
def make_Gaia_CM_diagram(source, table_source):
    tools = "pan,wheel_zoom,box_zoom,box_select,tap,hover,reset,crosshair"

    pars = [
        'M1_init', 'M2_init', 'P_init', 'q_init', 'product', 'stability',
        'termination_code'
    ]
    basic_tooltip = [(p, '@' + p) for p in pars]

    PRODUCTS = ['HB', 'He-WD', 'CE', 'UK', 'failed', 'sdB', 'sdA'] + \
               ['stable', 'CE', 'contact', 'merger']
    MARKERS = ['square', 'triangle', 'asterisk', 'asterisk', 'diamond', 'circle', 'circle'] + \
              ['circle', 'diamond', 'square', 'triangle', ]
    COLORS = ['red', 'green', 'purple', 'purple', 'gray', 'blue', 'orange'] + \
             ['red', 'green', 'blue', 'gray']
    SIZES = [7, 7, 7, 7, 15, 7]

    v_func = """
        const norm = new Float64Array(xs.length)
        for (let i = 0; i < xs.length; i++) {
            if (xs[i] == 'sdB' || xs[i] == 'Fail' || xs[i] == 'CE') {
                    norm[i] = 15
            } else {
                    norm[i] = 7
            }
        }
        return norm
        """
    size_transform = mpl.CustomJSTransform(v_func=v_func)

    # Left Figure

    booleans = [
        True if val != 0 else False for val in source.data['G_HeCoreBurning']
    ]
    view1 = CDSView(source=source, filters=[BooleanFilter(booleans)])

    p1 = figure(x_axis_label='Gaia BP-RP',
                y_axis_label='Gaia G mag',
                active_drag='box_select',
                tools=tools,
                tooltips=basic_tooltip,
                title="HeCoreBurning",
                y_range=(6, -5))

    p1.circle(hiparcos['bp_rp'], hiparcos['M_g'], size=1, color='gray')

    p1.scatter(x="BP-RP_HeCoreBurning",
               y="G_HeCoreBurning",
               source=source,
               fill_alpha=0.4,
               size=transform('z1', size_transform),
               color=factor_cmap('z1', COLORS, PRODUCTS),
               marker=factor_mark('z1', MARKERS, PRODUCTS),
               view=view1)

    # Right Figure

    booleans = [
        True if val != 0 else False for val in source.data['G_MLstart']
    ]
    view2 = CDSView(source=source, filters=[BooleanFilter(booleans)])

    p2 = figure(x_axis_label='Gaia BP-RP',
                y_axis_label='Gaia G mag',
                active_drag='box_select',
                tools=tools,
                tooltips=basic_tooltip,
                title="ML start",
                y_range=(6, -5))

    p2.circle(hiparcos['bp_rp'], hiparcos['M_g'], size=1, color='gray')

    p2.scatter(x="BP-RP_MLstart",
               y="G_MLstart",
               source=source,
               fill_alpha=0.4,
               size=transform('z1', size_transform),
               color=factor_cmap('z1', COLORS, PRODUCTS),
               marker=factor_mark('z1', MARKERS, PRODUCTS),
               view=view2)

    plot = gridplot([[p1, p2]])

    # add interaction when selecting a model
    callback = CustomJS(args=dict(summary_source=source,
                                  table_source=table_source),
                        code="""
                selected_indices = summary_source.selected.indices;

                console.log(summary_source.selected.indices[0]);
                console.log(summary_source);

                if (summary_source.selected.indices.length > 0){
                    var data = summary_source.data;
                    var ind = summary_source.selected.indices[0];
                    var parameters = table_source.data['parameters']
                    var values = table_source.data['values']

                    parameters.forEach(function (par, index) {
                        values[index] = data[par][ind];
                    });

                    //table_source.data['parameters'] = x;
                    table_source.data['values'] = values;

                    table_source.change.emit();
                }

                """)
    p1.js_on_event('tap', callback)
    p2.js_on_event('tap', callback)

    return plot, p1, p2
示例#28
0
def make_comparison_plot(source, pars_dict, titles=['', '']):
    tools = "pan,wheel_zoom,box_zoom,box_select,tap,hover,reset,crosshair"

    pars = [
        'M1_init', 'M2_init', 'P_init', 'q_init', 'product', 'stability',
        'termination_code'
    ]
    basic_tooltip = [(p, '@' + p) for p in pars]

    PRODUCTS = ['HB', 'He-WD', 'CE', 'UK', 'failed', 'sdB', 'sdA']
    MARKERS = [
        'square', 'triangle', 'asterisk', 'asterisk', 'diamond', 'circle',
        'circle'
    ]
    COLORS = ['red', 'green', 'purple', 'purple', 'gray', 'blue', 'orange']
    SIZES = [7, 7, 7, 7, 15, 7]

    v_func = """
    const norm = new Float64Array(xs.length)
    for (let i = 0; i < xs.length; i++) {
        if (xs[i] == 'sdB' || xs[i] == 'Fail') {
                norm[i] = 15
        } else {
                norm[i] = 7
        }
    }
    return norm
    """
    size_transform = mpl.CustomJSTransform(v_func=v_func)

    # Left Figure

    p1 = figure(x_axis_label=pars_dict['x1'],
                y_axis_label=pars_dict['y1'],
                active_drag='box_select',
                tools=tools,
                title=titles[0])  # , tooltips=basic_tooltip)

    p1.scatter(
        x="x1",
        y="y1",
        source=source,
        fill_alpha=0.4,
        size=transform('product_1', size_transform),
        color=factor_cmap('product_1', COLORS, PRODUCTS),
        marker=factor_mark('product_1', MARKERS, PRODUCTS),
    )

    # Right Figure

    p2 = figure(x_axis_label=pars_dict['x2'],
                y_axis_label=pars_dict['y2'],
                active_drag='box_select',
                tools=tools,
                title=titles[1])  # , tooltips=basic_tooltip)

    p2.scatter(
        x="x2",
        y="y2",
        source=source,
        fill_alpha=0.4,
        size=transform('product_2', size_transform),
        color=factor_cmap('product_2', COLORS, PRODUCTS),
        marker=factor_mark('product_2', MARKERS, PRODUCTS),
    )

    # add interaction when selecting a model
    callback = CustomJS(args=dict(summary_source=source),
                        code="""
                selected_indices = summary_source.selected.indices;
                """)
    p1.js_on_event('tap', callback)
    p2.js_on_event('tap', callback)

    plot = gridplot([[p1, p2]])

    return plot, p1, p2
示例#29
0
def comps_tab(comps):
    df = comps
    df['Close Date'] = pd.to_datetime(df['Close Date'])
    df = df.drop(columns=['index'])
    df['Size'] = 24
    df['Color'] = "#31AADE"
    df['xs'] = 'Close Date'
    df['ys'] = 'Finished Lot Value'

    SIZES = list(range(12, 36, 3))
    COLORS = Spectral6
    N_SIZES = len(SIZES)
    N_COLORS = len(COLORS)
    MARKERSOURCE = list(df['Site Condition'].unique())
    MARKERS = ['hex', 'circle_x', 'triangle', 'square']

    source = ColumnDataSource(df)

    columns = sorted(df.columns)
    discrete = [x for x in columns if df[x].dtype == object]
    continuous = [x for x in columns if x not in discrete]

    x_axis_select = Select(title='X-Axis', value='Close Date', options=columns)
    y_axis_select = Select(title='Y-Axis',
                           value='Finished Lot Value',
                           options=columns)
    size = Select(title='Size', value='None', options=['None'] + continuous)
    color = Select(title='Color', value='None', options=['None'] + continuous)
    kw = dict()
    x_title = x_axis_select.value.title()
    y_title = y_axis_select.value.title()
    df['xs'] = df[x_axis_select.value].values
    df['ys'] = df[y_axis_select.value].values
    x_title = x_axis_select.value.title()
    y_title = y_axis_select.value.title()

    kw = dict()
    if x_axis_select.value in discrete:
        kw['x_range'] = sorted(set(df['xs']))
    if y_axis_select.value in discrete:
        kw['y_range'] = sorted(set(df['ys']))
    kw['title'] = "%s vs %s" % (x_title, y_title)

    if x_axis_select.value in discrete:
        p.xaxis.major_label_orientation = pd.np.pi / 4

    df['Size'] = 24
    if size.value != 'None':
        if len(set(df[size.value])) > N_SIZES:
            groups = pd.qcut(df[size.value].values, N_SIZES, duplicates='drop')
        else:
            groups = pd.Categorical(df[size.value])
        df['Size'] = [SIZES[xx] for xx in groups.codes]

    df['Color'] = "#31AADE"
    if color.value != 'None':
        if len(set(df[color.value])) > N_COLORS:
            groups = pd.qcut(df[color.value].values,
                             N_COLORS,
                             duplicates='drop')
        else:
            groups = pd.Categorical(df[color.value])
        df['Color'] = [COLORS[xx] for xx in groups.codes]

    p = figure(plot_height=500,
               plot_width=800,
               tools='pan,box_zoom,hover,reset',
               **kw)
    p.xaxis.axis_label = x_title
    p.yaxis.axis_label = y_title
    map_options = GMapOptions(lat=df.Lat.mean(),
                              lng=df.Long.mean(),
                              map_type="roadmap",
                              zoom=8)
    pmap = gmap(Google_API,
                map_options,
                plot_width=360,
                plot_height=400,
                title="CMA Map",
                toolbar_location="above")
    pmap.circle(x="Long",
                y="Lat",
                size=15,
                fill_color='Color',
                fill_alpha=0.25,
                line_color='black',
                line_width=.08,
                source=source)

    callback = CustomJS(code="""
            var tooltips = document.getElementsByClassName("bk-tooltip");
            for (var i = 0, len = tooltips.length; i < len; i ++) {
            tooltips[i].style.top = "10px"; // unset what bokeh.js sets
            tooltips[i].style.left = "800px";
            tooltips[i].style.bottom = "";
            tooltips[i].style.right = "";
            }
            """)

    p.scatter(x='xs',
              y='ys',
              color='Color',
              size='Size',
              line_color="white",
              alpha=0.6,
              marker=factor_mark('Site Condition', MARKERS, MARKERSOURCE),
              hover_color='white',
              hover_alpha=0.5,
              source=source)

    hover = HoverTool(tooltips=[(x_title, '@xs'), (y_title, '@ys'),
                                ('Name', '@Neighborhood'),
                                ('FLV', '@{Finished Lot Value}{$0,0}'),
                                ('Community Count', '@{Community Count}'),
                                ('Market_Tier', '@{Market Tier}'),
                                ('Close Date', '@DateString'),
                                ('Lot Count', '@{Lot Count}'),
                                ('Site_Condition', '@{Site Condition}'),
                                ('Seller', '@Seller'),
                                ('Entitlements', '@Entitlements'),
                                ('Market', '@Market')],
                      callback=callback)

    def select_df():

        # filter df here based on widget inputs
        selected = df
        # (df['Square Footage (1)'] <= float(sf_slider.value[1]))

        return selected

    def update():
        df = select_df()

        df['xs'] = df[x_axis_select.value].values
        df['ys'] = df[y_axis_select.value].values
        x_title = x_axis_select.value.title()
        y_title = y_axis_select.value.title()

        kw = dict()
        if x_axis_select.value in discrete:
            kw['x_range'] = sorted(set(df['xs']))
        if y_axis_select.value in discrete:
            kw['y_range'] = sorted(set(df['ys']))
        kw['title'] = "%s vs %s" % (x_title, y_title)

        if x_axis_select.value in discrete:
            p.xaxis.major_label_orientation = pd.np.pi / 4

        df['Size'] = 24
        if size.value != 'None':
            if len(set(df[size.value])) > N_SIZES:
                groups = pd.qcut(df[size.value].values,
                                 N_SIZES,
                                 duplicates='drop')
            else:
                groups = pd.Categorical(df[size.value])
            df['Size'] = [SIZES[xx] for xx in groups.codes]

        df['Color'] = "#31AADE"
        if color.value != 'None':
            if len(set(df[color.value])) > N_COLORS:
                groups = pd.qcut(df[color.value].values,
                                 N_COLORS,
                                 duplicates='drop')
            else:
                groups = pd.Categorical(df[color.value])
            df['Color'] = [COLORS[xx] for xx in groups.codes]

        source = df
        return source

    controls = [x_axis_select, y_axis_select, size, color]

    for control in controls:
        control.on_change('value', lambda attr, old, new: update())

    button = Button(label="Download", button_type="success")
    button.callback = df.to_csv(
        os.path.abspath(
            os.path.join(os.path.dirname(__file__), '..', 'data', 'Downloads',
                         'sales_comps_' + str(date) + '.csv')))
    table = DataTable(source=source,
                      editable=True,
                      height=600,
                      width=1400,
                      fit_columns=True,
                      scroll_to_selection=True)

    widgets = column([*controls, button], width=180, height=250)
    widgets.sizing_mode = "fixed"

    # Make a tab with the layout

    p.add_tools(hover)
    l = layout([[column([widgets]), p, pmap], table], sizing_mode='fixed')
    # l = layout(table)
    update()

    tab = Panel(child=l, title='Comps')
    return tab
示例#30
0
def Photon_Output_Graph(conn):

    output_file(
        "Photon_Output_Graph.html"
    )  #????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

    ############################################################################
    ############################# USER INPUTS ##################################

    # Decide what the default viewing option is going to be. (i.e. the fields to
    # be plotted on the x and y axis when the graph is opened).
    # NB: Have it set that if axis is 'adate' then will automatically update
    # to plot datetime.
    x_data1 = 'adate'
    y_data1 = 'graph % diff in output'
    plot_title1 = 'Photon Output Results'
    x_axis_title1 = x_data1
    y_axis_title1 = y_data1
    plot_size_height1 = 450
    plot_size_width1 = 800
    legend_location = 'bottom_left'
    hover_tool_fields = ['chamber and electrometer', 'comments']
    # Create a list of the plot parameters that will be used as input to a
    # function later.
    list_plot_parameters = [
        x_data1, y_data1, plot_title1, x_axis_title1, y_axis_title1,
        plot_size_height1, plot_size_width1, legend_location
    ]
    # Define the fields that the legend will be based off. If there is only
    # one field then put it in both columns.
    color_column = 'energy'
    custom_color_boolean = True
    custom_color_palette = [
        '#FF0000', 'black', 'yellow', 'purple', '#008F8F', '#FF00FF', 'white'
    ]
    marker_column = 'machinename'
    custom_marker_boolean = True
    custom_marker_palette = [
        'circle_x', 'square', 'square_x', 'diamond', 'hex', 'x',
        'circle_cross', 'square_cross', 'diamond_cross', 'dash', 'cross',
        'inverted_triangle', 'circle', 'triangle', 'asterisk'
    ]
    # From the legend defined above give the values that will be pre-ticked when
    # the plot is opened. NB: Bokeh will throw an error if one of these lists is
    # empty (i.e. =[]) If only using color or marker then set the color_to plot
    # and then enter the command:  marker_to_plot = color_to_plot.
    color_to_plot = ['6MV', '10MV']
    marker_to_plot = ['TrueBeam B', 'TrueBeam C', 'TrueBeam D']

    ############################################################################
    #################### CREATE THE DATA FOR THE GRAPH #########################

    # Do this in a function so it can be used in an update callback later

    def Create_df():

        # Use the connection passed to the function to read the data into a
        # dataframe via an SQL query.
        df = pd.read_sql( 'SELECT [Protocol ID], [Energy], ' \
             '[chamber and electrometer], [Chamber factor], ' \
             '[Gantry angle], [Temp], [Press], [T/P factor], ' \
             '[output], [QI], [Comments], ' \
             '[Graph % Diff in output], [Graph % diff in QI] ' \
             'FROM [phcal_Graph] ' \
             , conn )

        # Delete empty rows where the data is very important to have
        df = df.dropna(subset=['protocol id'], how='any')
        df = df.dropna(subset=['energy'], how='any')

        # The format is complicated for this field but seems to be that the date is
        # always the first element and the machine is always the last regardless of
        # how many elements there are.
        # Seperate on the first '_'
        df_left = df['protocol id'].str.partition(sep='_')
        # Seperate on the last '_'
        df_right = df['protocol id'].str.rpartition(sep='_')
        # From these sperated dataframes add the appropriate columns back into the
        # main dataframe.
        df.loc[:, 'adate'] = df_left[0]
        df.loc[:, 'machinename'] = df_right[2]
        # Turn 'adate' into datetime.
        df.loc[:, 'adate'] = pd.to_datetime(df.loc[:, 'adate'], dayfirst=True)

        # Drop any rows that aren't related to the Truebeams (ditches the old
        # uneeded data). Might be possible to put this in the SQL query but
        # difficult as machinename is embedded in the protocol ID.
        df = df[df['machinename'].isin(
            ['TrueBeam B', 'TrueBeam C', 'TrueBeam D', 'TrueBeam F'])]

        # Drop any columns where there is no data (likely because of the
        # dropping of the old linacs (e.g. data that used to be collected from
        # them that is no longer collected for the Truebeams))
        df = df.dropna(axis='columns', how='all')

        return df

    df = Create_df()

    # Create a list of the fields using the dataframe. By doing it now before
    # the extra legend fields are added it's easy to limit what is displayed in
    # the select widgets.
    TableFields = (list(df.columns))

    ############################################################################
    ############################################################################

    ############################################################################
    ################ CREATE THE DATAFRAME FOR THE TOLERANCES ###################

    # If you want to add tolerances change the boolean to True and construct the
    # dataframe in the correct format.
    tolerance_boolean = True
    # The format of the dataframe should be the first line being the x_axis
    # (with some values taken from the main dataframe to get the right
    # formatting). The subsequent columns are the tolerances [low, high].
    # NB: column names should match those from the main dataframe.
    if tolerance_boolean == True:
        df_tol1 = pd.DataFrame({
            'adate': [df['adate'].max(), df['adate'].max()],
            'output': [98, 102],
            'graph % diff in output': [-2, 2]
        })

        # Added a seperate qi tolerance as multiple energes can appear
        # simultaneously so need an special tolerance function to deal with
        # this.
        df_tol1_qi = pd.DataFrame({
            'adate': [df['adate'].max(), df['adate'].max()],
            'qi_6MV': [0.64, 0.68],
            'qi_6XFFF': [0.61, 0.65],
            'qi_10MV': [0.71, 0.75],
            'qi_10XFFF': [0.68, 0.72]
        })

        def special_tolerance(color_to_plot, x_data1, y_data1, Sub_df1,
                              df_tol1_qi):

            energy_list = ['6MV', '6XFFF', '10MV', '10XFFF']
            data = {}

            if (x_data1 != 'adate') or (y_data1 != 'qi'):
                for x in range(0, len(energy_list)):
                    data.update({
                        'x_' + energy_list[x]:
                        [Sub_df1['x'].max(), Sub_df1['x'].max()],
                        'y_low_' + energy_list[x]:
                        [Sub_df1['y'].max(), Sub_df1['y'].max()],
                        'y_high_' + energy_list[x]:
                        [Sub_df1['y'].max(), Sub_df1['y'].max()]
                    })
            else:
                # Get a list of the column headers
                headers1 = df_tol1_qi.columns.values.tolist()
                # Check if the xdata is what is in the df_tol1 as the x_axis (if not no
                # point plotting tolerances as all tolerances are vs this column).
                max_x = Sub_df1['x'].max() + pd.DateOffset(weeks=2)
                min_x = Sub_df1['x'].min() + pd.DateOffset(weeks=-2)

                for x in range(0, len(energy_list)):
                    if energy_list[x] in color_to_plot:
                        data.update({
                            'x_' + energy_list[x]: [min_x, max_x],
                            'y_low_' + energy_list[x]: [
                                df_tol1_qi['qi_' + energy_list[x]][0],
                                df_tol1_qi['qi_' + energy_list[x]][0]
                            ],
                            'y_high_' + energy_list[x]: [
                                df_tol1_qi['qi_' + energy_list[x]][1],
                                df_tol1_qi['qi_' + energy_list[x]][1]
                            ]
                        })
                    else:
                        data.update({
                            'x_' + energy_list[x]:
                            [Sub_df1['x'].max(), Sub_df1['x'].max()],
                            'y_low_' + energy_list[x]:
                            [Sub_df1['y'].max(), Sub_df1['y'].max()],
                            'y_high_' + energy_list[x]:
                            [Sub_df1['y'].max(), Sub_df1['y'].max()]
                        })

            Sub_df1_tol1_qi = pd.DataFrame(data)

            return Sub_df1_tol1_qi

    ############################################################################
    ############################################################################

    ############################################################################
    ############################################################################
    '''

	This is the end of the user input section. If you don't need to make any
	other changes you can end here.

	'''

    ############################################################################
    ################### CREATE THE COLUMNS FOR THE LEGEND ######################

    (color_list, color_palette, marker_list, marker_palette, df,
     add_legend_to_df) = Create_Legend(df, color_column, custom_color_boolean,
                                       custom_color_palette, marker_column,
                                       custom_marker_boolean,
                                       custom_marker_palette)

    ############################################################################
    ############################################################################

    ############################################################################
    ################## FORMATTING AND CREATING A BASIC PLOT ####################

    ######### Make Dataset:
    # Run the Make_Dataset function to create two sub dataframs that the plots
    # will be made from.
    Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                           marker_to_plot, x_data1, y_data1)

    # Make the ColumnDataSource (when making convert dataframe to a dictionary,
    # which is helpful for the callback).
    src1 = ColumnDataSource(Sub_df1.to_dict(orient='list'))

    ######### Make Plot:
    # Create an empty plot (plot parameters will be applied later in a way that
    # can be manipulated in the callbacks)
    p1 = figure()
    p1.scatter(
        source=src1,
        x='x',
        y='y',
        fill_alpha=0.4,
        size=12,
        # NB: Always use legend_field for this not legend_group as the
        # former acts on the javascript side but the latter the Python
        # side. Therefore the former will update automatically.
        legend_field='legend',
        marker=factor_mark('marker1', marker_palette, marker_list),
        color=factor_cmap('color1', color_palette, color_list))

    # Run the Define_Plot_Parameters function to set the plot parameters
    Define_Plot_Parameters(p1, list_plot_parameters)

    ############################################################################
    ############################################################################

    ############################################################################
    ############################ ADD TOLERANCES ################################

    # We defined the tolerances further up and now want to add the correct ones
    # to the plot. Done in such a way that they are updated with the callbacks
    # later.
    if tolerance_boolean == True:

        Sub_df1_tol1 = Make_Dataset_Tolerance(x_data1, y_data1, Sub_df1,
                                              df_tol1)

        src1_tol = ColumnDataSource(Sub_df1_tol1.to_dict(orient='list'))

        p1.line(source=src1_tol, x='x', y='y_low', color='firebrick')
        p1.line(source=src1_tol, x='x', y='y_high', color='firebrick')

        Sub_df1_tol1_qi = special_tolerance(color_to_plot, x_data1, y_data1,
                                            Sub_df1, df_tol1_qi)

        src1_tol_qi = ColumnDataSource(Sub_df1_tol1_qi.to_dict(orient='list'))

        p1.line(source=src1_tol_qi, x='x_6MV', y='y_low_6MV', color='yellow')
        p1.line(source=src1_tol_qi, x='x_6MV', y='y_high_6MV', color='yellow')
        p1.line(source=src1_tol_qi,
                x='x_6XFFF',
                y='y_low_6XFFF',
                color='mediumorchid')
        p1.line(source=src1_tol_qi,
                x='x_6XFFF',
                y='y_high_6XFFF',
                color='mediumorchid')
        p1.line(source=src1_tol_qi,
                x='x_10MV',
                y='y_low_10MV',
                color='firebrick')
        p1.line(source=src1_tol_qi,
                x='x_10MV',
                y='y_high_10MV',
                color='firebrick')
        p1.line(source=src1_tol_qi,
                x='x_10XFFF',
                y='y_low_10XFFF',
                color='black')
        p1.line(source=src1_tol_qi,
                x='x_10XFFF',
                y='y_high_10XFFF',
                color='black')

    ############################################################################
    ############################################################################

    ############################################################################
    ################## ADD MORE COMPLEX TOOLS TO THE PLOT ######################

    ######## 1)
    # Create a hover tool and add it to the plot
    hover1 = HoverTool()

    if len(hover_tool_fields) < 11:
        kwargs = {}
        i = 0
        for x in hover_tool_fields:
            i = i + 1
            kwargs['Field' + str(i)] = x
    else:
        kwargs = {}
        msgbox('Too many fields selected to display on HoverTool ' \
         '(Max = 10). Please reduce number of fields selected')

    Update_HoverTool(hover1, x_data1, y_data1, **kwargs)

    p1.add_tools(hover1)

    ############################################################################
    ############################################################################

    ############################################################################
    ################# CREATE WIDGETS TO BE ADDED TO THE PLOT ###################

    ######## 1)
    # This select funtion will be used to create dropdown lists to change the
    # data plotted on the x/y-axis.
    select_xaxis, select_yaxis = Create_Select_Axis(TableFields, x_axis_title1,
                                                    y_axis_title1)

    ######## 2)
    # This select widget will be used to create dropdown lists to change the
    # legend position.
    select_legend = Create_Select_Legend(legend_location)

    ######## 3)
    # These checkbox widgets will be used to create a tool to select the machine
    # and energy that are being plotted.
    checkbox_color, checkbox_marker = Create_Checkbox_Legend(
        df, color_column, color_to_plot, marker_column, marker_to_plot)

    ######## 4)
    # These checkbox widgets will be used to create a tool to select the machine
    # and energy that are being plotted.
    checkbox_hovertool = Create_Checkbox_HoverTool(TableFields,
                                                   hover_tool_fields)

    ######## 5)
    # Make an 'Update Button' to requery the database and get up to date data.
    update_button = Button(label='Update', button_type='success')

    ######## 6)
    # Make a Range Button
    range_button = Button(label='Range', button_type='primary')

    ######## 7)
    # Make some titles for the checkboxes
    color_title = Div(text='<b>Energy Choice</b>')
    marker_title = Div(text='<b>Machine Choice</b>')
    hover_title = Div(text='<b>Hovertool Fields</b>')

    ############################################################################
    ############################################################################

    ############################################################################
    ############################ CREATE A LAYOUT ###############################

    # Create a layout where the widgets will be added and any scaling applied.
    if color_column == marker_column:
        layout_checkbox = column(
            [color_title, checkbox_color, hover_title, checkbox_hovertool])
    else:
        layout_checkbox = column([
            color_title, checkbox_color, marker_title, checkbox_marker,
            hover_title, checkbox_hovertool
        ])

    button_row = row([update_button, range_button])

    layout_plots = column(
        [button_row, select_xaxis, select_yaxis, select_legend, p1])

    tab_layout = row([layout_plots, layout_checkbox])

    ############################################################################
    ############################################################################

    ############################################################################
    ####################### CREATE CALLBACK FUNCTIONS ##########################

    # Create a big callback that does most stuff
    def callback(attr, old, new):

        # Want to acquire the current values of all of the checkboxes and select
        # widgets to provide as inputs for the re-plot.
        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        if color_column != marker_column:
            marker_to_plot = [
                checkbox_marker.labels[i] for i in checkbox_marker.active
            ]
        else:
            marker_to_plot = color_to_plot
        hovertool_to_plot = [
            checkbox_hovertool.labels[i] for i in checkbox_hovertool.active
        ]
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value
        legend_location = select_legend.value
        # Set the new axis titles
        x_axis_title1 = plot1_xdata_to_plot
        y_axis_title1 = plot1_ydata_to_plot

        # Use the pre-defined Make_Dataset function with these new inputs to
        # create new versions of the sub dataframes.
        Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                               marker_to_plot, plot1_xdata_to_plot,
                               plot1_ydata_to_plot)

        # Use the pre-defined Define_Plot_Parameters function with these new
        # inputs to update the plot.
        Define_Plot_Parameters(p1, [
            plot1_xdata_to_plot, plot1_ydata_to_plot, plot_title1,
            x_axis_title1, y_axis_title1, plot_size_height1, plot_size_width1,
            legend_location
        ])

        # Update the hovertool
        if len(hovertool_to_plot) < 11:
            kwargs = {}
            i = 0
            for x in hovertool_to_plot:
                i = i + 1
                kwargs['Field' + str(i)] = x
        else:
            kwargs = {}
            msgbox('Too many fields selected to display on HoverTool ' \
             '(Max = 10). Please reduce number of fields selected')

        Update_HoverTool(hover1, plot1_xdata_to_plot, plot1_ydata_to_plot,
                         **kwargs)

        print(hover1.tooltips)
        print(p1.hover.tooltips)
        print(hover1)
        print(p1.hover)

        # Use the pre-defined Make_Dataset_Tolerance function with these new
        # inputs to update the tolerances.
        if tolerance_boolean == True:
            Sub_df1_tol1 = Make_Dataset_Tolerance(plot1_xdata_to_plot,
                                                  plot1_ydata_to_plot, Sub_df1,
                                                  df_tol1)
            Sub_df1_tol1_qi = special_tolerance(color_to_plot,
                                                plot1_xdata_to_plot,
                                                plot1_ydata_to_plot, Sub_df1,
                                                df_tol1_qi)

        # Update the ColumnDataSources.
        src1.data = Sub_df1.to_dict(orient='list')
        if tolerance_boolean == True:
            src1_tol.data = Sub_df1_tol1.to_dict(orient='list')
            src1_tol_qi.data = Sub_df1_tol1_qi.to_dict(orient='list')

        return

    select_xaxis.on_change('value', callback)
    select_yaxis.on_change('value', callback)
    select_legend.on_change('value', callback)
    checkbox_color.on_change('active', callback)
    checkbox_marker.on_change('active', callback)
    checkbox_hovertool.on_change('active', callback)

    # Callback for the Update Button
    def callback_update():

        # Make a new version of the dataframe using the original Create_df
        # function that connects to the database.
        df = Create_df()
        df = add_legend_to_df(df)

        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        if color_column != marker_column:
            marker_to_plot = [
                checkbox_marker.labels[i] for i in checkbox_marker.active
            ]
        else:
            marker_to_plot = color_to_plot
        hovertool_to_plot = [
            checkbox_hovertool.labels[i] for i in checkbox_hovertool.active
        ]
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value
        x_axis_title1 = plot1_xdata_to_plot
        y_axis_title1 = plot1_ydata_to_plot
        legend_location = select_legend.value

        Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                               marker_to_plot, plot1_xdata_to_plot,
                               plot1_ydata_to_plot)

        Define_Plot_Parameters(p1, [
            plot1_xdata_to_plot, plot1_ydata_to_plot, plot_title1,
            x_axis_title1, y_axis_title1, plot_size_height1, plot_size_width1,
            legend_location
        ])

        if len(hovertool_to_plot) < 11:
            kwargs = {}
            i = 0
            for x in hovertool_to_plot:
                i = i + 1
                kwargs['Field' + str(i)] = x
        else:
            kwargs = {}
            msgbox('Too many fields selected to display on HoverTool ' \
             '(Max = 10). Please reduce number of fields selected')

        Update_HoverTool(hover1, plot1_xdata_to_plot, plot1_ydata_to_plot,
                         **kwargs)

        if tolerance_boolean == True:
            Sub_df1_tol1 = Make_Dataset_Tolerance(plot1_xdata_to_plot,
                                                  plot1_ydata_to_plot, Sub_df1,
                                                  df_tol1)
            Sub_df1_tol1_qi = special_tolerance(color_to_plot,
                                                plot1_xdata_to_plot,
                                                plot1_ydata_to_plot, Sub_df1,
                                                df_tol1_qi)
            src1_tol.data = Sub_df1_tol1.to_dict(orient='list')
            src1_tol_qi.data = Sub_df1_tol1_qi.to_dict(orient='list')

        src1.data = Sub_df1.to_dict(orient='list')

        return

    update_button.on_click(callback_update)

    # Callback for the Range Button
    def callback_range():

        color_to_plot = [
            checkbox_color.labels[i] for i in checkbox_color.active
        ]
        if color_column != marker_column:
            marker_to_plot = [
                checkbox_marker.labels[i] for i in checkbox_marker.active
            ]
        else:
            marker_to_plot = color_to_plot
        plot1_xdata_to_plot = select_xaxis.value
        plot1_ydata_to_plot = select_yaxis.value

        # Use the pre-defined Make_Dataset function with these new inputs to
        # create new versions of the sub dataframes.
        Sub_df1 = Make_Dataset(df, color_column, color_to_plot, marker_column,
                               marker_to_plot, plot1_xdata_to_plot,
                               plot1_ydata_to_plot)

        if (plot1_xdata_to_plot == 'adate') and (
            (plot1_ydata_to_plot == 'graph % diff in output') or
            (plot1_ydata_to_plot == 'output') or plot1_ydata_to_plot == 'qi'):

            p1.x_range.start = Sub_df1['x'].max() - timedelta(weeks=53)
            p1.x_range.end = Sub_df1['x'].max() + timedelta(weeks=2)

            if plot1_ydata_to_plot == 'output':
                p1.y_range.start = 97
                p1.y_range.end = 103
            elif plot1_ydata_to_plot == 'graph % diff in output':
                p1.y_range.start = -3
                p1.y_range.end = 3
            elif plot1_ydata_to_plot == 'qi':
                p1.y_range.start = 0.55
                p1.y_range.end = 0.8
        return

    range_button.on_click(callback_range)

    ############################################################################
    ############################################################################

    ############################################################################
    ####################### RETURN TO THE MAIN SCRIPT ##########################

    return Panel(child=tab_layout, title='Photon Output')