Esempio n. 1
0
        only_visible=True,
        follow="end",
        follow_interval=span * 1000,
        max_interval=60 * 1000 * 60 * 24,
        min_interval=1000,
        range_padding_units='absolute',
        range_padding=1000,
    ))
#other_property = here)
p.yaxis.visible = False

p.xaxis.formatter = DatetimeTickFormatter(milliseconds='%H:%M:%S.%2N',
                                          seconds="%H:%M:%S",
                                          minsec="%H:%M:%S",
                                          minutes="%H:%M:%S",
                                          hourmin="%H:%M:%S",
                                          hours="%H:%M:%S",
                                          days=['%m/%d', '%a%d'],
                                          months=['%m/%Y', '%b %Y'],
                                          years=['%Y'])

r1 = p.line([], [],
            color="yellow",
            line_width=line_width,
            y_range_name="pressures")
r2 = p.line([], [],
            color="skyblue",
            line_width=line_width,
            y_range_name="temps")
r3 = p.line([], [], color="green", line_width=line_width, y_range_name="temps")
Esempio n. 2
0
    def line_plot(fig, x, y, source, color, label=None,
            x_axis_type='date', **kwargs):
        """
        Add a single time series to a :obj:`bokeh.plotting.figure.Figure`
        object using data from a datetime indexed :obj:`pandas.DataFrame` with
        an interactive hover tool. 

        Interactive hover shows the values of all time series data and date
        that is added to the figure.

        Arguments:
            fig (:obj:`bokeh.plotting.figure.Figure`): a figure instance to add 
                the line to.
            x (str): name of the datetime index or column in the 
                :obj:`pandas.DataFrame` containing data to plot.
            y (str): name of the column in the :obj:`pandas.DataFrame` to plot.
            source (:obj:`bokeh.models.sources.ColumnDataSource`): column data 
                source created from the :obj:`pandas.DataFrame` with data to 
                plot.
            color (str): color of plot line, see Bokeh for color options.
            label (str or :obj:`None`): default :obj:`None`. Label for plot 
                legend (for ``y``).
            x_axis_type (:obj:`str` or :obj:`None`): default 'date'. If "date" 
                then the x-axis will be formatted as month-day-year. 

        Returns:
            :obj:`None`

        Example:

            To use the :meth:`Plot.line_plot` function we first need to create
            a :obj:`bokeh.models.sources.ColumnDataSource` from a
            :obj:`pandas.DataFrame`. Let's say we want to plot the monthly time
            series of corrected latent energy, starting from a config.ini file,

            >>> from fluxdataqaqc import Data, QaQc, Plot
            >>> d = Data('path/to/config.ini')
            >>> q = QaQc(d)
            >>> q.correct_data()
            
            Now the :obj:`.QaQc` should have the "LE_corr" (corrected latent
            energy) column, we can now make a
            :obj:`bokeh.models.sources.ColumnDataSource` from
            :attr:`fluxdataqaqc.QaQc.df` or
            :attr:`fluxdataqaqc.QaQc.monthly_df`,

            >>> from bokeh.plotting import ColumnDataSource, figure, show
            >>> source = ColumnDataSource(q.monthly_df)
            >>> # create the figure before using line_plot
            >>> fig = figure(x_axis_label='date', y_axis_label='Corrected LE')
            >>> Plot.line_plot(
            >>>     fig, 'date', 'LE_corr', source, color='red', line_width=3
            >>> )
            >>> show(fig)

            Notice, ``line_width`` is not an argument to :meth:`Plot.line_plot`
            but it is an acceptable keyword argument to
            :obj:`bokeh.plotting.figure.Figure` and therefore will work as
            expected.


        Note:
            This method is also available from the :obj:`.Data` and :obj:`.QaQc`
            objects.
        """
        hover_mode = kwargs.pop('mode','vline')
        if label is None:
            fig.line(x,y, source=source, color=color, **kwargs)
        else:
            #label=dict(value=label) # old label requirement bokeh < 2? 
            fig.line(x,y,source=source,color=color,legend_label=label,**kwargs)
            fig.legend.location = "top_left"
            fig.legend.click_policy="hide"
        # add Hover tool with additional tips if more than one line
        if len(fig.hover) == 0:
            if x_axis_type == 'date':
                Hover = HoverTool(
                    tooltips=[
                        (x,'@{}{}'.format(x,'{%F}')), 
                        (y,'@{}'.format(y))
                    ], 
                    formatters={'@{}'.format(x): 'datetime'},
                    mode = hover_mode 
                )
                fig.add_tools(Hover)
            else: 
                Hover = HoverTool(
                    tooltips=[
                        (x,'@{}'.format(x)), 
                        (y,'@{}'.format(y))
                    ], 
                    mode = hover_mode 
                )
                fig.add_tools(Hover)
        else:
            fig.hover[0].tooltips.append((y,'@{}'.format(y)))
        # enforce datetime x axis it date
        if x_axis_type == 'date':
            fig.xaxis.formatter = DatetimeTickFormatter(days="%d-%b-%Y")
Esempio n. 3
0
import pandas as pd

from bokeh.models import HoverTool
from bokeh.models.formatters import DatetimeTickFormatter
from bokeh.plotting import figure, ColumnDataSource

from app import db
from app.decorators import data_quality

# creates your plot
date_formatter = DatetimeTickFormatter(microseconds=['%f'],
                                       milliseconds=['%S.%2Ns'],
                                       seconds=[':%Ss'],
                                       minsec=[':%Mm:%Ss'],
                                       minutes=['%H:%M:%S'],
                                       hourmin=['%H:%M:'],
                                       hours=["%H:%M"],
                                       days=["%d %b"],
                                       months=["%d %b %Y"],
                                       years=["%b %Y"])


@data_quality(name='hbdet_bias', caption=' ')
def hbdet_bias_plot(start_date, end_date):
    """Return a <div> element with a weather downtime plot.

    The plot shows the downtime for the period between start_date (inclusive) and end_date (exclusive).

    Params:
    -------
    start_date: date
def set_graph_and_legend_properties(plot_graph: figure(), graph_title: str) -> figure():
    """
    Sets the Properties of the graph and the legend of the graph
    :param plot_graph:
    :param legends:
    :param graph_title:
    :return:
    """
    # Add Tool - Hovertool
    # Hover Tool Properties
    # @Todo - Add hovertool tips
    # hover_tool_tips = set_hover_tool_tips()
    # plot_graph.add_tools(hover_tool_tips)

    # Remove Logo
    plot_graph.toolbar.logo = None

    # Legend related formatting
    # legend = Legend(items=legends, location=(0, 0))
    plot_graph.legend.click_policy = "hide"
    plot_graph.legend.background_fill_color = "#2F2F2F"
    plot_graph.legend.label_text_color = "white"
    plot_graph.legend.border_line_color = "#2F2F2F"
    plot_graph.legend.inactive_fill_color = "#2F2F2F"
    plot_graph.legend.location = "top_left"
    # plot_graph.add_layout(legend, 'right')

    # X-Axis related formatting
    plot_graph.xgrid.grid_line_color = "white"
    plot_graph.xgrid.grid_line_dash = [6, 4]
    plot_graph.xgrid.grid_line_alpha = .3
    plot_graph.xaxis.axis_line_color = "white"
    plot_graph.xaxis.axis_label_text_color = "white"
    plot_graph.xaxis.major_label_text_color = "white"
    plot_graph.xaxis.major_tick_line_color = "white"
    plot_graph.xaxis.minor_tick_line_color = "white"
    plot_graph.xaxis.formatter = DatetimeTickFormatter(microseconds=["%b '%y"],
                                                       milliseconds=["%b '%y"],
                                                       seconds=["%b '%y"],
                                                       minsec=["%b '%y"],
                                                       minutes=["%b '%y"],
                                                       hourmin=["%b '%y"],
                                                       hours=["%b '%y"],
                                                       days=["%b '%y"],
                                                       months=["%b '%y"],
                                                       years=["%b '%y"])

    # Y-axis related formatting
    plot_graph.ygrid.grid_line_color = "white"
    plot_graph.ygrid.grid_line_dash = [6, 4]
    plot_graph.ygrid.grid_line_alpha = .3
    plot_graph.yaxis.axis_line_color = "white"
    plot_graph.yaxis.axis_label_text_color = "white"
    plot_graph.yaxis.major_label_text_color = "white"
    plot_graph.yaxis.major_tick_line_color = "white"
    plot_graph.yaxis.minor_tick_line_color = "white"

    # Graph related Formatting
    plot_graph.min_border_left = 80
    plot_graph.title.text = graph_title
    plot_graph.title.text_color = "white"
    plot_graph.title.text_font = "times"
    plot_graph.title.text_font_style = "normal"
    plot_graph.title.text_font_size = "14pt"
    plot_graph.title.align = "center"
    plot_graph.background_fill_color = '#2F2F2F'
    plot_graph.border_fill_color = '#2F2F2F'
    plot_graph.outline_line_color = '#444444'

    return plot_graph
Esempio n. 5
0
def main(ini_path, figure_show_flag=False, figure_save_flag=True,
         figure_size=(1000, 300), start_date=None, end_date=None,
         crop_str=''):
    """Plot daily average, median, quantile data for all years by crop

    Args:
        ini_path (str): file path of the project INI file
        figure_show_flag (bool): if True, show figures
        figure_save_flag (bool): if True, save figures
        figure_size (tuple): width, height of figure in pixels
        start_date (str): ISO format date string (YYYY-MM-DD)
        end_date (str): ISO format date string (YYYY-MM-DD)
        crop_str (str): comma separate list or range of crops to compare

    Returns:
        None
    """

    # Input/output names
    # input_folder = 'daily_stats'
    # output_folder = 'daily_plots'

    # Only process a subset of the crops
    crop_keep_list = list(util.parse_int_set(crop_str))
    # These crops will not be processed (if set)
    crop_skip_list = [44, 45, 46]

    # Input field names
    date_field = 'Date'
    doy_field = 'DOY'
    year_field = 'Year'
    # month_field = 'Month'
    # day_field = 'Day'
#    pmeto_field = 'PMETo'
    precip_field = 'PPT'
    # t30_field = 'T30'

    etact_field = 'ETact'
    etpot_field = 'ETpot'
    etbas_field = 'ETbas'
    irrig_field = 'Irrigation'
    season_field = 'Season'
    runoff_field = 'Runoff'
    dperc_field = 'DPerc'
    # niwr_field = 'NIWR'

    # Number of header lines in data file
    # header_lines = 2

    # Additional figure controls
    # figure_dynamic_size = False
    figure_ylabel_size = '12pt'

    # Delimiter
    sep = ','
    # sep = r"\s*"

#    sub_x_range_flag = True

    logging.info('\nPlot mean daily data by crop')
    logging.info('  INI: {}'.format(ini_path))

    # Check that the INI file can be read
    crop_et_sec = 'CROP_ET'
    config = util.read_ini(ini_path, crop_et_sec)

    # Get the project workspace and daily ET folder from the INI file
    try:
        project_ws = config.get(crop_et_sec, 'project_folder')
    except:
        logging.error(
            'ERROR: The project_folder ' +
            'parameter is not set in the INI file')
        sys.exit()
    try:
        input_ws = os.path.join(
            project_ws, config.get(crop_et_sec, 'daily_output_folder'))
    except:
        logging.error(
            'ERROR: The daily_output_folder ' +
            'parameter is not set in the INI file')
        sys.exit()
    try:
        output_ws = os.path.join(
            project_ws, config.get(crop_et_sec, 'daily_plots_folder'))
    except:
        if 'stats' in input_ws:
            output_ws = input_ws.replace('stats', 'plots')
        else:
            output_ws = os.path.join(project_ws, 'daily_stats_folder')

    # Check workspaces
    if not os.path.isdir(input_ws):
        logging.error(('\nERROR: The input ET folder {0} ' +
                       'could be found\n').format(input_ws))
        sys.exit()
    if not os.path.isdir(output_ws):
        os.mkdir(output_ws)

    # Range of data to plot
    try:
        year_start = dt.datetime.strptime(start_date, '%Y-%m-%d').year
        logging.info('  Start Year:  {0}'.format(year_start))
    except:
        year_start = None
    try:
        year_end = dt.datetime.strptime(end_date, '%Y-%m-%d').year
        logging.info('  End Year:    {0}'.format(year_end))
    except:
        year_end = None
    if year_start and year_end and year_end < year_start:
        logging.error('\n  ERROR: End date must be after start date\n')
        sys.exit()
    
    # # Windows only a
    # if figure_dynamic_size:
    #     :
    #        logging.info('Setting plots width/height dynamically')
    #        from win32api import GetSystemMetrics
    #        figure_width = int(0.92 * GetSystemMetrics(0))
    #        figure_height = int(0.28 * GetSystemMetrics(1))
    #        logging.info('  {0} {1}'.format(GetSystemMetrics(0),
    #  GetSystemMetrics(1)))
    #        logging.info('  {0} {1}'.format(figure_width, figure_height))
    #     :
    #        figure_width = 1200
    #        figure_height = 300

    # Regular expressions
    data_re = re.compile('(?P<CELLID>\w+)_crop_(?P<CROP>\d+).csv$', re.I)
    # data_re = re.compile('(?P<CELLID>\w+)_daily_crop_(?P<CROP>\d+).csv$',
    #  re.I)

    # Build list of all data files
    data_file_list = sorted(
        [os.path.join(input_ws, f_name) for f_name in os.listdir(input_ws)
         if data_re.match(f_name)])
    if not data_file_list:
        logging.error(
            '  ERROR: No daily ET files were found\n' +
            '  ERROR: Check the folder_name parameters\n')
        sys.exit()

    # Process each file
    for file_path in data_file_list:
        file_name = os.path.basename(file_path)
        logging.debug('')
        logging.info('  {0}'.format(file_name))

        # station, crop_num = os.path.splitext(file_name)[0].split(
        # '_daily_crop_')
        station, crop_num = os.path.splitext(file_name)[0].split('_crop_')
        crop_num = int(crop_num)
        logging.debug('    Station:         {0}'.format(station))
        logging.debug('    Crop Num:        {0}'.format(crop_num))
        if station == 'temp':
            logging.debug('      Skipping')
            continue
        elif crop_skip_list and crop_num in crop_skip_list:
            logging.debug('    Skipping, crop number in crop_skip_list')
            continue
        elif crop_keep_list and crop_num not in crop_keep_list:
            logging.debug('    Skipping, crop number not in crop_keep_list')
            continue

        # Get crop name
        with open(file_path, 'r') as file_f:
            crop_name = file_f.readline().split('-', 1)[1].strip()
            logging.debug('    Crop:            {0}'.format(crop_name))

        # Read data from file into record array (structured array)
        daily_df = pd.read_csv(file_path, header=0, comment='#', sep=sep)
        logging.debug('    Fields: {0}'.format(
            ', '.join(daily_df.columns.values)))
        daily_df[date_field] = pd.to_datetime(daily_df[date_field])
        daily_df.set_index(date_field, inplace=True)
        daily_df[year_field] = daily_df.index.year
        # daily_df[year_field] = daily_df[date_field].map(lambda x: x.year)

        # Get PMET type from fieldnames in daily .csv
        field_names = daily_df.columns
        PMET_str = field_names[4]
#        if 'PMETr' in field_names:
#            PMET_str='PMETr'
#        else:
#            PMET_str='PMETo'

        # Build list of unique years
        year_array = np.sort(np.unique(
            np.array(daily_df[year_field]).astype(np.int)))
        logging.debug('    All Years: {0}'.format(
            ', '.join(list(util.ranges(year_array.tolist())))))
        # logging.debug('    All Years: {0}'.format(
        #    ','.join(map(str, year_array.tolist()))))

        # Don't include the first year in the stats
        crop_year_start = min(daily_df[year_field])
        logging.debug('    Skipping {}, first year'.format(crop_year_start))
        daily_df = daily_df[daily_df[year_field] > crop_year_start]

        # Check if start and end years have >= 365 days
        crop_year_start = min(daily_df[year_field])
        crop_year_end = max(daily_df[year_field])
        if sum(daily_df[year_field] == crop_year_start) < 365:
            logging.debug(
                '    Skipping {}, missing days'.format(crop_year_start))
            daily_df = daily_df[daily_df[year_field] > crop_year_start]
        if sum(daily_df[year_field] == crop_year_end) < 365:
            logging.debug(
                '    Skipping {}, missing days'.format(crop_year_end))
            daily_df = daily_df[daily_df[year_field] < crop_year_end]

        # Only keep years between year_start and year_end
        # Adjust crop years
        if year_start:
            daily_df = daily_df[daily_df[year_field] >= year_start]
            crop_year_start = max(year_start, crop_year_start)
        if year_end:
            daily_df = daily_df[daily_df[year_field] <= year_end]
            crop_year_end = min(year_end, crop_year_end)

        year_sub_array = np.sort(
            np.unique(np.array(daily_df[year_field]).astype(np.int)))
        logging.debug('    Plot Years: {0}'.format(
            ', '.join(list(util.ranges(year_sub_array.tolist())))))

        # Build separate arrays for each field of non-crop specific data
        dt_array = daily_df.index.date
        doy_array = daily_df[doy_field].values.astype(np.int)
        pmet_array = daily_df[PMET_str].values
        precip_array = daily_df[precip_field].values

        # Remove leap days
        # leap_array = (doy_array == 366)
        # doy_sub_array = np.delete(doy_array, np.where(leap_array)[0])

        # Build separate arrays for each set of crop specific fields
        etact_array = daily_df[etact_field].values
        etpot_array = daily_df[etpot_field].values
        etbas_array = daily_df[etbas_field].values
        irrig_array = daily_df[irrig_field].values
        season_array = daily_df[season_field].values
        runoff_array = daily_df[runoff_field].values
        dperc_array = daily_df[dperc_field].values
        kc_array = etact_array / pmet_array
        kcb_array = etbas_array / pmet_array
        
        # build dataframes for grouby input
        doy_df = pd.DataFrame(doy_array)
        pmet_df = pd.DataFrame(pmet_array.transpose())
        etact_df = pd.DataFrame(etact_array.transpose())
#        etpot_df = pd.DataFrame(etpot_array.transpose())
#        etbas_df = pd.DataFrame(etbas_array.transpose())
#        irrig_df = pd.DataFrame(irrig_array.transpose())
        season_df = pd.DataFrame(season_array.transpose())
#        runoff_df = pd.DataFrame(runoff_array.transpose())
#        dperc_df = pd.DataFrame(dperc_array.transpose())
        kc_df = pd.DataFrame(kc_array.transpose())
        kcb_df = pd.DataFrame(kcb_array.transpose())

        # groupby stats
#        doy_mean = doy_df[0].groupby(doy_df[0]).mean().values
        season_median = season_df[0].groupby(doy_df[0]).median().values
        kc_median = kc_df[0].groupby(doy_df[0]).median().values
        kcb_median = kcb_df[0].groupby(doy_df[0]).median().values
#        etbas_median = etbas_df[0].groupby(doy_df[0]).median().values
        pmet_median = pmet_df[0].groupby(doy_df[0]).median().values
#        etpot_median = etpot_df[0].groupby(doy_df[0]).median().values
        etact_median = etact_df[0].groupby(doy_df[0]).median().values
        # 25% and 75% Percentiles of all years
        kc_q25 = kc_df[0].groupby(doy_df[0]).quantile(0.25).values
        kcb_q25 = kcb_df[0].groupby(doy_df[0]).quantile(0.25).values
#        etbas_q25 = etbas_df[0].groupby(doy_df[0]).quantile(0.25).values
#        pmet_q25 = pmet_df[0].groupby(doy_df[0]).quantile(0.25).values
#        etpot_q25 = etpot_df[0].groupby(doy_df[0]).quantile(0.25).values
        etact_q25 = etact_df[0].groupby(doy_df[0]).quantile(0.25).values
        kc_q75 = kc_df[0].groupby(doy_df[0]).quantile(0.75).values
        kcb_q75 = kcb_df[0].groupby(doy_df[0]).quantile(0.75).values
#        etbas_q75 = etbas_df[0].groupby(doy_df[0]).quantile(0.75).values
#        etpot_q75 = etpot_df[0].groupby(doy_df[0]).quantile(0.75).values
        etact_q75 = etact_df[0].groupby(doy_df[0]).quantile(0.75).values
#        pmet_q75 = pmet_df[0].groupby(doy_df[0]).quantile(0.75).values

        # NIWR is ET - precip + runoff + deep percolation
        # Don't include deep percolation when irrigating
        # niwr_array = etact_array - (precip_array - runoff_array)
        # niwr_array[irrig_array==0] += dperc_array[irrig_array == 0]

        # Remove leap days
        # etact_sub_array = np.delete(etact_array, np.where(leap_array)[0])
        # niwr_sub_array = np.delete(niwr_array, np.where(leap_array)[0])
        
        # Manually create date range array for display of month/day on x-axis
        x_range = Range1d(dt.datetime(2000, 1, 1), dt.datetime(2000, 12, 31))
        np_x_range = np.arange(dt.datetime(2000, 1, 1), dt.datetime(2001, 1, 1),
                               dt.timedelta(days=1)).astype(dt.datetime)

        # Timeseries figures of daily data
        output_name = '{0}_crop_{1:02d}_avg'.format(
            station, int(crop_num), crop_year_start, crop_year_end)
        output_path = os.path.join(output_ws, output_name + '.html')

        f = output_file(output_path, title=output_name)
        TOOLS = 'xpan,xwheel_zoom,box_zoom,reset,save'

        f1 = figure(x_axis_type='datetime', x_range=x_range,
                    width=figure_size[0], height=figure_size[1],
                    tools=TOOLS, toolbar_location="right",
                    active_scroll="xwheel_zoom")
        # title='Evapotranspiration', x_axis_type='datetime',
#        if refet_type == 'ETo':    
        f1.line(np_x_range, etact_median, color='blue', legend='ETact Median')
        f1.line(np_x_range, etact_q75, color='red',
                legend='ETact 75th percentile')
        f1.line(np_x_range, etact_q25, color='green',
                legend='ETact 25th percentile')
        f1.line(np_x_range, pmet_median, color='black',
                legend=PMET_str+' Median', line_dash="dashed")
#        else:
#            f1.line(np_x_range, et_median, color='blue',
        #  legend='ETr Median')
#            f1.line(np_x_range, etbas_q75, color='red',
        #  legend='ETr 75th percentile')
#            f1.line(np_x_range, etpot_q25, color='green',
        #  legend='ETr 25th percentile')
#                # line_dash="dashdot")
        # f1.title = 'Evapotranspiration [mm]'
        f1.grid.grid_line_alpha = 0.3
        f1.yaxis.axis_label = 'Evapotranspiration [mm]'
        f1.yaxis.axis_label_text_font_size = figure_ylabel_size
        f1.xaxis.formatter = DatetimeTickFormatter(years=['%m/%d'],
                                                   months=['%m/%d'],
                                                   days=['%m/%d'])
        # f1.xaxis.bounds = x_bounds

        f2 = figure(x_axis_type='datetime', x_range=x_range,
                    width=figure_size[0], height=figure_size[1],
                    tools=TOOLS, toolbar_location="right",
                    active_scroll="xwheel_zoom")
        f2.line(np_x_range, kc_median, color='blue', legend='Kc Median')
        f2.line(np_x_range, kc_q75, color='red', legend='Kc 75th percentile')
        f2.line(np_x_range, kc_q25, color='green', legend='Kc 25th percentile')
        f2.line(np_x_range, season_median, color='black',
                legend='Season Median', line_dash="dashed")
#         f2.title = 'Kc and Kcb (dimensionless)'
        f2.grid.grid_line_alpha = 0.3
        f2.yaxis.axis_label = 'Kc (dimensionless)'
        f2.yaxis.axis_label_text_font_size = figure_ylabel_size
        f2.xaxis.formatter = DatetimeTickFormatter(years=['%m/%d'],
                                                   months=['%m/%d'],
                                                   days=['%m/%d'])

        f3 = figure(x_axis_type='datetime', x_range=x_range,
                    width=figure_size[0], height=figure_size[1],
                    tools=TOOLS, toolbar_location="right",
                    active_scroll="xwheel_zoom")
        f3.line(np_x_range, kcb_median, color='blue', legend='Kcb Median')
        f3.line(np_x_range, kcb_q75, color='red', legend='Kcb 75th percentile')
        f3.line(np_x_range, kcb_q25, color='green',
                legend='Kcb 25th percentile')
        f3.line(np_x_range, season_median, color='black',
                legend='Season Median', line_dash="dashed")
        # f3.title = 'PPT and Irrigation [mm]'
        f3.grid.grid_line_alpha = 0.3
#        f3.xaxis.axis_label = 'Day of Year'
        f3.xaxis.axis_label_text_font_size = figure_ylabel_size
        f3.yaxis.axis_label = 'Kcb (dimensionless)'
        f3.yaxis.axis_label_text_font_size = figure_ylabel_size
        f3.xaxis.formatter = DatetimeTickFormatter(years=['%m/%d'],
                                                   months=['%m/%d'],
                                                   days=['%m/%d'])

        if figure_show_flag:
            # Open in a browser
            show(column([f1, f2, f3], sizing_mode='stretch_both'))
            # show(vplot(f1, f2, f3))
        if figure_save_flag:
            save(column([f1, f2, f3], sizing_mode='stretch_both'))
            # save(vplot(f1, f2, f3))
        del f1, f2, f3, f

        # Cleanup
        del etact_array, etpot_array, etbas_array
        del irrig_array, season_array
        del runoff_array, dperc_array
        del kc_array, kcb_array
        # del niwr_array
        # del etact_sub_array, niwr_sub_array

        # Cleanup
        del file_path, daily_df
        del dt_array, year_array, year_sub_array, doy_array
        del pmet_array
        del precip_array
        gc.collect()
Esempio n. 6
0
def plot2html(df, title, interval, log, line, ma):
    df = df.iloc[1:]
    up = df.close > df.open
    dn = df.open > df.close

    kwargs = dict(title=title,
                  tools='xpan, xwheel_zoom, box_zoom, reset',
                  active_drag='box_zoom')
    if log:
        kwargs['y_axis_type'] = 'log'
    plot = figure(x_axis_type='datetime', sizing_mode='stretch_both', **kwargs)
    plot.toolbar.active_scroll = plot.select_one(WheelZoomTool)
    plot.background_fill_alpha = 0
    plot.border_fill_alpha = 0
    plot.grid.grid_line_alpha = 0.2
    plot.outline_line_alpha = 0.4
    plot.xaxis.axis_line_color = 'whitesmoke'
    plot.yaxis.axis_line_color = 'whitesmoke'
    plot.xaxis.axis_line_alpha = 0
    plot.yaxis.axis_line_alpha = 0
    plot.xaxis.major_tick_line_alpha = 0
    plot.yaxis.major_tick_line_alpha = 0
    plot.xaxis.minor_tick_line_alpha = 0
    plot.yaxis.minor_tick_line_alpha = 0
    dtf = DatetimeTickFormatter()
    dtf.milliseconds = ['%T']
    dtf.seconds = dtf.minsec = ['%T']
    dtf.hours = dtf.hourmin = dtf.minutes = ['%R']
    dtf.days = ['%F']
    dtf.months = ['%F']
    dtf.years = ['%F']
    plot.xaxis.formatter = dtf

    if line:
        plot.line(df.time, df.close, color='#55bb77')
    else:
        pass

    if ma:
        for i, n in enumerate([50, 200]):
            dma = df.close.rolling(n).mean()
            col = bokeh.palettes.Category20[20][i % 20]
            plot.line(df.time, dma, color=col, legend_label='MA-%i' % n)
        plot.legend.background_fill_color = '#222222'
        plot.legend.background_fill_alpha = 0.6
        plot.legend.label_text_color = 'whitesmoke'

    if not line:
        totime = {
            '1m': 60,
            '5m': 5 * 60,
            '15m': 15 * 60,
            '30m': 30 * 60,
            '1h': 60 * 60,
            '2h': 2 * 60 * 60,
            '4h': 4 * 60 * 60,
            '6h': 6 * 60 * 60,
            '12h': 12 * 60 * 60,
            '1d': 24 * 60 * 60,
            '1w': 7 * 24 * 60 * 60
        }
        w = totime[interval] * 0.7 * 1000
        plot.segment(df.time[up],
                     df.hi[up],
                     df.time[up],
                     df.lo[up],
                     color='#33dd99')
        plot.segment(df.time[dn],
                     df.hi[dn],
                     df.time[dn],
                     df.lo[dn],
                     color='#ff8866')
        plot.vbar(df.time[up],
                  w,
                  df.open[up],
                  df.close[up],
                  fill_color='#558866',
                  line_color='#33dd99')
        plot.vbar(df.time[dn],
                  w,
                  df.open[dn],
                  df.close[dn],
                  fill_color='#cc9988',
                  line_color='#ff8866')

    script, div = plot_html(plot)
    return div + script
Esempio n. 7
0
def app(doc, hist_storage_, data_storage_, freq_storage_, depolarizer, names):

    # вспомогательные глобальные

    data_source = ColumnDataSource({key: [] for key in names})
    fit_handler = {
        "fit_line": None,
        "input_fields": {},
        "fit_indices": tuple()
    }
    utc_plus_7h = 7 * 3600
    time_coef = 10**3  # Пересчёт времени в мс для формата datetime Bokeh
    fit_line_points_amount = 300  # Количество точек для отрисовки подгоночной кривой
    depol_list = []

    datetime_formatter = DatetimeTickFormatter(
        milliseconds=['%M:%S:%3Nms'],
        seconds=['%H:%M:%S'],
        minsec=['%H:%M:%S'],
        minutes=['%H:%M:%S'],
        hourmin=['%H:%M:%S'],
        hours=['%H:%M:%S'],
        days=["%d.%m"],
        months=["%Y-%m-%d"],
    )

    # Гистограмма пятна
    img, img_x_std, img_y_std = hist_storage_.get_hist_with_std()
    hist_source = ColumnDataSource(data=dict(image=[img]))
    width_ = config.GEM_X * 5
    hist_height_ = config.GEM_Y * 5
    hist_fig = figure(plot_width=width_,
                      plot_height=hist_height_,
                      x_range=(0, config.GEM_X),
                      y_range=(0, config.GEM_Y))

    hist_fig.image(image='image',
                   x=0,
                   y=0,
                   dw=config.GEM_X,
                   dh=config.GEM_Y,
                   palette="Spectral11",
                   source=hist_source)

    hist_label = Label(
        x=0,
        y=0,
        x_units='screen',
        y_units='screen',
        text=f"x_std={'%.2f' % img_x_std},y_std={'%.2f' % img_y_std}",
        render_mode='css',
        border_line_color='black',
        border_line_alpha=1.0,
        background_fill_color='white',
        background_fill_alpha=1.0)

    hist_fig.add_layout(hist_label)

    hist_buffer_len = config.hist_buffer_len - 1
    hist_slider = RangeSlider(start=0,
                              end=hist_buffer_len,
                              value=(0, hist_buffer_len),
                              step=1,
                              title="Срез пятна (от..до) сек назад")

    def hist_update():
        img, img_x_std, img_y_std = hist_storage_.get_hist_with_std(
            hist_buffer_len - hist_slider.value[1],
            hist_buffer_len - hist_slider.value[0])
        hist_label.text = f"x_std={'%.2f' % img_x_std},y_std={'%.2f' % img_y_std}"
        hist_source.data = {'image': [img]}

    # График асимметрии

    asym_fig = figure(
        plot_width=width_,
        plot_height=400,
        tools="box_zoom, xbox_select, wheel_zoom, pan, save, reset",
        active_scroll="wheel_zoom",
        active_drag="pan",
        toolbar_location="below",
        lod_threshold=100,
        x_axis_location=None,
        x_range=DataRange1d())

    asym_fig.yaxis.axis_label = "мм"
    asym_fig.extra_x_ranges = {
        "time_range": asym_fig.x_range,
        "depolarizer": asym_fig.x_range,
        "sec": asym_fig.x_range
    }

    depol_axis = LinearAxis(x_range_name="depolarizer",
                            axis_label='Деполяризатор',
                            major_label_overrides={},
                            major_label_orientation=pi / 2)

    asym_fig.add_layout(
        LinearAxis(x_range_name="time_range",
                   axis_label='Время',
                   formatter=datetime_formatter), 'below')

    # Прямая, с которой идёт отсчёт времени для подгонки
    zone_of_interest = Span(location=0,
                            dimension='height',
                            line_color='green',
                            line_dash='dashed',
                            line_width=3)

    sec_axis = LinearAxis(
        x_range_name='sec',
        axis_label='Секунды')  # Секундная ось сверху (настр. диапазон)
    sec_axis.formatter = FuncTickFormatter(
        code=
        f"return ((tick - {zone_of_interest.location}) / {time_coef}).toFixed(1);"
    )

    def double_tap(event):
        """Двойной клик для перемещения отсчёта времени для подгонки"""
        zone_of_interest.location = event.x
        sec_axis.formatter = FuncTickFormatter(
            code=f"return ((tick - {event.x}) / {time_coef}).toFixed(1);")

    asym_fig.add_layout(depol_axis, 'below')
    asym_fig.add_layout(sec_axis, 'above')
    asym_fig.add_layout(zone_of_interest)
    asym_fig.on_event(DoubleTap, double_tap)

    def draw_selected_area(attr, old, new):
        """Подсветка выделенной для подгонки области"""

        # Удаляет предыдущую выделенную область
        asym_fig.renderers = [
            r for r in asym_fig.renderers if r.name != 'fit_zone'
        ]

        if not new.indices:
            fit_handler["fit_indices"] = tuple()
            return

        l_time_ = data_source.data['time'][min(new.indices)]
        r_time_ = data_source.data['time'][max(new.indices)]

        if l_time_ != r_time_:
            fit_handler["fit_indices"] = (l_time_, r_time_)
            box_select = BoxAnnotation(left=l_time_,
                                       right=r_time_,
                                       name="fit_zone",
                                       fill_alpha=0.1,
                                       fill_color='red')
            asym_fig.add_layout(box_select)

    asym_box_select_overlay = asym_fig.select_one(BoxSelectTool).overlay
    asym_box_select_overlay.line_color = "firebrick"

    data_source.on_change('selected', draw_selected_area)

    def create_whisker(data_name: str):
        """ Создает усы для data_name от time

        :param data_name: имя поля данных из data_storage
                (у данных должны быть поля '_up_error', '_down_error')
        :return: Bokeh Whisker
        """
        return Whisker(source=data_source,
                       base="time",
                       upper=data_name + "_up_error",
                       lower=data_name + "_down_error")

    def create_render(data_name: str, glyph: str, color: str):
        """ Рисует data_name от time

        :param data_name: имя поля данных из data_storage
        :param glyph: ['circle', 'square']
        :param color: цвет
        :return: Bokeh fig
        """
        if glyph == 'circle':
            func = asym_fig.circle
        elif glyph == 'square':
            func = asym_fig.square
        else:
            raise ValueError('Неверное значение glyph')
        return func('time',
                    data_name,
                    source=data_source,
                    name=data_name,
                    color=color,
                    nonselection_alpha=1,
                    nonselection_color=color)

    # Список линий на графике асимметрии: data_name, name, glyph, color
    asym_renders_name = [('y_one_asym', 'ΔY ONE', 'circle', 'black'),
                         ('y_cog_asym', 'ΔY COG', 'circle', 'green'),
                         ('x_one_asym', 'ΔX ONE', 'square', 'black'),
                         ('x_cog_asym', 'ΔX COG', 'square', 'green')]

    pretty_names = dict([(data_name, name)
                         for data_name, name, *_ in asym_renders_name])
    asym_renders = [
        create_render(data_name, glyph, color)
        for data_name, _, glyph, color in asym_renders_name
    ]
    asym_error_renders = [
        create_whisker(data_name) for data_name, *_ in asym_renders_name
    ]

    for render, render_error in zip(asym_renders, asym_error_renders):
        asym_fig.add_layout(render_error)
        render.js_on_change(
            'visible',
            CustomJS(args=dict(x=render_error),
                     code="x.visible = cb_obj.visible"))

    asym_fig.add_layout(
        Legend(items=[(pretty_names[r.name], [r]) for r in asym_renders],
               click_policy="hide",
               location="top_left",
               background_fill_alpha=0.2,
               orientation="horizontal"))

    # Вывод информации о точке при наведении мыши
    asym_fig.add_tools(
        HoverTool(
            renderers=asym_renders,
            formatters={"time": "datetime"},
            mode='vline',
            tooltips=[
                ("Время", "@time{%F %T}"),
                *[(pretty_names[r.name],
                   f"@{r.name}{'{0.000}'} ± @{r.name + '_error'}{'{0.000}'}")
                  for r in asym_renders],
                ("Деполяризатор", f"@depol_energy{'{0.000}'}")
            ]))

    # Окно ввода периода усреднения
    period_input = TextInput(value='300', title="Время усреднения (с):")

    # Глобальный список параметров, для сохранения результатов запросов к data_storage
    params = {'last_time': 0, 'period': int(period_input.value)}

    def update_data():
        """
        Обновляет данные для пользовательского интерфейса, собирая их у data_storage
        """
        if params['period'] != int(period_input.value):
            data_source.data = {name: [] for name in names}
            params['period'] = int(period_input.value)
            params['last_time'] = 0
            depol_axis.ticker = []
            depol_axis.major_label_overrides.clear()
            depol_list.clear()

        points, params['last_time'] = data_storage_.get_mean_from(
            params['last_time'], params['period'])

        if not points['time']:
            return

        points['time'] = [(i + utc_plus_7h) * time_coef for i in points['time']
                          ]  # Учёт сдвижки UTC+7 для отрисовки

        for time, energy in zip(points['time'], points['depol_energy']):
            if energy == 0:
                continue
            depol_axis.major_label_overrides[time] = str(energy)
            depol_list.append(time)

        depol_axis.ticker = depol_list  # TODO: оптимизировать
        data_source.stream({key: np.array(val)
                            for key, val in points.items()},
                           rollover=250)

    def period_correction_func(attr, old, new):
        """Проверка введенного значения на целое число больше нуля"""
        if not new.isdigit() or int(new) <= 0:
            period_input.value = old

    period_input.on_change('value', period_correction_func)

    # Создание панели графиков (вкладок)

    def create_fig(data_names: list,
                   colors: list,
                   y_axis_name: str,
                   ers: str = None):
        """Создаёт график data_names : time. Если в data_names несколько имён,
        то они будут на одном графике. Возвращает fig.

        :param data_names: список с именами полей данных из data_storage
        :param colors: список цветов, соотв. элементам из fig_names
        :param y_axis_name: имя оси Y
        :param ers: 'err', 'pretty' --- вид усов (у данных должны быть поля '_up_error', '_down_error'),
                       'err' --- усы обыкновенные
                       'pretty' --- усы без шляпки и цветом совпадающим с цветом точки
        :return fig --- Bokeh figure
        """

        if len(data_names) != len(colors):
            raise IndexError('Кол-во цветов и графиков не совпадает')

        fig = figure(plot_width=width_,
                     plot_height=300,
                     tools="box_zoom, wheel_zoom, pan, save, reset",
                     active_scroll="wheel_zoom",
                     lod_threshold=100,
                     x_axis_type="datetime")

        for fig_name, color in zip(data_names, colors):

            if ers == 'err':
                fig.add_layout(
                    Whisker(source=data_source,
                            base="time",
                            upper=fig_name + '_up_error',
                            lower=fig_name + '_down_error'))
            elif ers == 'pretty':
                fig.add_layout(
                    Whisker(source=data_source,
                            base="time",
                            upper=fig_name + '_up_error',
                            lower=fig_name + '_down_error',
                            line_color=color,
                            lower_head=None,
                            upper_head=None))

            fig.circle('time',
                       fig_name,
                       source=data_source,
                       size=5,
                       color=color,
                       nonselection_alpha=1,
                       nonselection_color=color)

        fig.yaxis.axis_label = y_axis_name
        fig.xaxis.axis_label = 'Время'
        fig.xaxis.formatter = datetime_formatter
        fig.x_range = asym_fig.x_range

        return fig

    figs = [(create_fig(['y_one_l'], ['black'], 'Y [мм]', 'err'), 'Y ONE L'),
            (create_fig(['y_one_r'], ['black'], 'Y [мм]', 'err'), 'Y ONE R'),
            (create_fig(['y_cog_l'], ['black'], 'Y [мм]', 'err'), 'Y COG L'),
            (create_fig(['y_cog_r'], ['black'], 'Y [мм]', 'err'), 'Y COG R'),
            (create_fig(['rate' + i for i in ['_l', '_r']], ['red', 'blue'],
                        'Усл. ед.', 'pretty'), 'Rate'),
            (create_fig(['corrected_rate' + i for i in ['_l', '_r']],
                        ['red', 'blue'], 'Усл. ед.', 'pretty'), 'Corr. rate'),
            (create_fig(['delta_rate'], ['black'], 'Корр. лев. - корр. пр.',
                        'err'), 'Delta corr. rate'),
            (create_fig(['charge'], ['blue'], 'Ед.'), 'Charge')]

    tab_handler = Tabs(
        tabs=[Panel(child=fig, title=fig_name) for fig, fig_name in figs],
        width=width_)

    # Окно статуса деполяризатора

    depol_status_window = Div(text="Инициализация...", width=500, height=500)

    depol_start_stop_buttons = RadioButtonGroup(
        labels=["Старт", "Стоп"], active=(0 if depolarizer.is_scan else 1))

    fake_depol_button = Button(label="Деполяризовать", width=200)
    fake_depol_button.on_click(GEM.depolarize)

    depol_input_harmonic_number = TextInput(value=str(
        '%.1f' % depolarizer.harmonic_number),
                                            title=f"Номер гармоники",
                                            width=150)

    depol_input_attenuation = TextInput(value=str('%.1f' %
                                                  depolarizer.attenuation),
                                        title=f"Аттенюатор (дБ)",
                                        width=150)

    depol_input_speed = TextInput(
        value=str(depolarizer.frequency_to_energy(depolarizer.speed, n=0)),
        title=f"Скорость ({'%.1f' % depolarizer.speed} Гц):",
        width=150)

    depol_input_step = TextInput(
        value=str(depolarizer.frequency_to_energy(depolarizer.step, n=0)),
        title=f"Шаг ({'%.1f' % depolarizer.step} Гц):",
        width=150)

    depol_input_initial = TextInput(
        value=str(depolarizer.frequency_to_energy(depolarizer.initial)),
        title=f"Начало ({'%.1f' % depolarizer.initial} Гц):",
        width=150)

    depol_input_final = TextInput(
        value=str(depolarizer.frequency_to_energy(depolarizer.final)),
        title=f"Конец ({'%.1f' % depolarizer.final} Гц):",
        width=150)

    depol_dict = {
        "speed": (depol_input_speed, depolarizer.set_speed),
        "step": (depol_input_step, depolarizer.set_step),
        "initial": (depol_input_initial, depolarizer.set_initial),
        "final": (depol_input_final, depolarizer.set_final),
        "harmonic_number":
        (depol_input_harmonic_number, depolarizer.set_harmonic_number),
        "attenuation": (depol_input_attenuation, depolarizer.set_attenuation)
    }

    def change_value_generator(value_name):
        """Возвращает callback функцию для параметра value_name деполяризатора"""
        def change_value(attr, old, new):
            if float(old) == float(new):
                return

            depol_input, depol_set = depol_dict[value_name]
            depol_current = depolarizer.get_by_name(value_name)
            try:
                if value_name in ['harmonic_number', 'attenuation']:
                    new_val = float(new)
                elif value_name in ['speed', 'step']:
                    new_val = depolarizer.energy_to_frequency(float(new), n=0)
                else:
                    new_val = depolarizer.energy_to_frequency(float(new))

                if depol_current == new_val:
                    return

                depol_set(new_val)
                if value_name not in ['harmonic_number', 'attenuation']:
                    name = depol_input.title.split(' ')[0]
                    depol_input.title = name + f" ({'%.1f' % new_val} Гц):"

            except ValueError as e:
                if value_name in ['harmonic_number', 'attenuation']:
                    depol_input.value = str(depol_current)
                elif value_name in ['speed', 'step']:
                    depol_input.value = str(
                        depolarizer.frequency_to_energy(depol_current, n=0))
                else:
                    depol_input.value = str(
                        depolarizer.frequency_to_energy(depol_current))
                print(e)

        return change_value

    depol_input_harmonic_number.on_change(
        'value', change_value_generator('harmonic_number'))
    depol_input_attenuation.on_change('value',
                                      change_value_generator("attenuation"))
    depol_input_speed.on_change('value', change_value_generator("speed"))
    depol_input_step.on_change('value', change_value_generator("step"))
    depol_input_initial.on_change('value', change_value_generator("initial"))
    depol_input_final.on_change('value', change_value_generator("final"))

    def update_depol_status(
    ):  # TODO: самому пересчитывать начало и конец сканирования по частотам
        """Обновляет статус деполяризатора,
        если какое-то значение поменялось другим пользователем"""
        depol_start_stop_buttons.active = 0 if depolarizer.is_scan else 1

        depol_status_window.text = f"""
<p>Сканирование: 
<font color={'"green">включено' if depolarizer.is_scan else '"red">выключено'}</font></p>
<p/>Частота {"%.1f" % depolarizer.current_frequency} (Гц)</p>
<p/>Энергия {"%.3f" % depolarizer.current_energy} МэВ</p>"""

        for value_name in ['speed', 'step']:
            depol_input, _ = depol_dict[value_name]
            depol_value = depolarizer.frequency_to_energy(
                depolarizer.get_by_name(value_name), n=0)
            if float(depol_input.value) != depol_value:
                depol_input.value = str(depol_value)

        for value_name in ['initial', 'final']:
            depol_input, _ = depol_dict[value_name]
            freq = depolarizer.get_by_name(value_name)
            energy = depolarizer.frequency_to_energy(freq)
            if float(depol_input.value) != energy:
                depol_input.value = str(energy)
            else:
                name = depol_input.title.split(' ')[0]
                depol_input.title = name + f" ({'%.1f' % freq} Гц):"

        for value_name in ['attenuation', 'harmonic_number']:
            depol_input, _ = depol_dict[value_name]
            depol_value = depolarizer.get_by_name(value_name)
            if float(depol_input.value) != depol_value:
                depol_input.value = str(int(depol_value))

    depol_start_stop_buttons.on_change(
        "active", lambda attr, old, new:
        (depolarizer.start_scan() if new == 0 else depolarizer.stop_scan()))

    # Подгонка

    fit_line_selection_widget = Select(title="Fitting line:",
                                       width=200,
                                       value=asym_renders[0].name,
                                       options=[(render.name,
                                                 pretty_names[render.name])
                                                for render in asym_renders])

    options = [name for name in fit.function_handler.keys()]
    if not options:
        raise IndexError("Пустой function_handler в fit.py")

    fit_function_selection_widget = Select(title="Fitting function:",
                                           value=options[0],
                                           options=options,
                                           width=200)

    fit_button = Button(label="FIT", width=200)

    def make_parameters_table():
        """Создание поля ввода данных для подгонки: начальное значение, fix и т.д."""
        name = fit_function_selection_widget.value

        t_width = 10
        t_height = 12

        rows = [
            row(Paragraph(text="name", width=t_width, height=t_height),
                Paragraph(text="Fix", width=t_width, height=t_height),
                Paragraph(text="Init value", width=t_width, height=t_height),
                Paragraph(text="step (error)", width=t_width, height=t_height),
                Paragraph(text="limits", width=t_width, height=t_height),
                Paragraph(text="lower_limit", width=t_width, height=t_height),
                Paragraph(text="upper_limit", width=t_width, height=t_height))
        ]

        fit_handler["input_fields"] = {}

        for param, value in fit.get_function_params(name):
            fit_handler["input_fields"][param] = {}
            fit_handler["input_fields"][param]["fix"] = CheckboxGroup(
                labels=[""], width=t_width, height=t_height)
            fit_handler["input_fields"][param]["Init value"] = TextInput(
                width=t_width, height=t_height, value=str(value))
            fit_handler["input_fields"][param]["step (error)"] = TextInput(
                width=t_width, height=t_height, value='1')
            fit_handler["input_fields"][param]["limits"] = CheckboxGroup(
                labels=[""], width=t_width, height=t_height)
            fit_handler["input_fields"][param]["lower_limit"] = TextInput(
                width=t_width, height=t_height)
            fit_handler["input_fields"][param]["upper_limit"] = TextInput(
                width=t_width, height=t_height)

            rows.append(
                row(Paragraph(text=param, width=t_width, height=t_height),
                    fit_handler["input_fields"][param]["fix"],
                    fit_handler["input_fields"][param]["Init value"],
                    fit_handler["input_fields"][param]["step (error)"],
                    fit_handler["input_fields"][param]["limits"],
                    fit_handler["input_fields"][param]["lower_limit"],
                    fit_handler["input_fields"][param]["upper_limit"]))

        return column(rows)

    def clear_fit():
        """Удаление подогнанной кривой"""
        if fit_handler["fit_line"] in asym_fig.renderers:
            asym_fig.renderers.remove(fit_handler["fit_line"])

    energy_window = Div(text="Частота: , энергия: ")
    clear_fit_button = Button(label="Clear", width=200)
    clear_fit_button.on_click(clear_fit)

    def fit_callback():
        if not fit_handler["fit_indices"]:
            return

        name = fit_function_selection_widget.value
        line_name = fit_line_selection_widget.value

        left_time_, right_time_ = fit_handler["fit_indices"]

        left_ind_ = bisect.bisect_left(data_source.data['time'], left_time_)
        right_ind_ = bisect.bisect_right(data_source.data['time'],
                                         right_time_,
                                         lo=left_ind_)

        if left_ind_ == right_ind_:
            return

        clear_fit()

        x_axis = data_source.data['time'][left_ind_:right_ind_]
        y_axis = data_source.data[line_name][left_ind_:right_ind_]
        y_errors = data_source.data[line_name +
                                    '_up_error'][left_ind_:right_ind_] - y_axis

        init_vals = {
            name: float(val["Init value"].value)
            for name, val in fit_handler["input_fields"].items()
        }

        steps = {
            "error_" + name: float(val["step (error)"].value)
            for name, val in fit_handler["input_fields"].items()
        }

        fix_vals = {
            "fix_" + name: True
            for name, val in fit_handler["input_fields"].items()
            if val["fix"].active
        }

        limit_vals = {
            "limit_" + name:
            (float(val["lower_limit"].value), float(val["upper_limit"].value))
            for name, val in fit_handler["input_fields"].items()
            if val["limits"].active
        }

        kwargs = {}
        kwargs.update(init_vals)
        kwargs.update(steps)
        kwargs.update(fix_vals)
        kwargs.update(limit_vals)

        # Предобработка времени, перевод в секунды, вычитание сдвига (для лучшей подгонки)
        left_ = zone_of_interest.location
        x_time = x_axis - left_  # Привёл время в интервал от 0
        x_time /= time_coef  # Перевёл в секунды

        # Создание точек, которые передадутся в подогнанную функцию с параметрами,
        # и точек, которые соответсвуют реальным временам на графике (т.е. без смещения к 0)

        fit_line_real_x_axis = np.linspace(left_time_, right_time_,
                                           fit_line_points_amount)
        fit_line_x_axis = fit_line_real_x_axis - left_
        fit_line_x_axis /= time_coef

        m = fit.create_fit_func(name, x_time, y_axis, y_errors, kwargs)

        fit.fit(m)
        params_ = m.get_param_states()
        for param in params_:
            fit_handler["input_fields"][
                param['name']]["Init value"].value = "%.3f" % param['value']
            fit_handler["input_fields"][
                param['name']]["step (error)"].value = "%.3f" % param['error']
            if param['name'] == "depol_time":
                freq = freq_storage_.find_closest_freq(param['value'] +
                                                       left_ / time_coef -
                                                       utc_plus_7h)
                freq_error = abs(depolarizer.speed * param['error'])
                energy = depolarizer.frequency_to_energy(
                    freq) if freq != 0 else 0
                energy_error = depolarizer.frequency_to_energy(
                    freq_error, depolarizer._F0, 0)
                energy_window.text = "<p>Частота: %8.1f +- %.1f Hz,</p> <p>Энергия: %7.3f +- %.1f МэВ</p>" % (
                    freq, freq_error, energy, energy_error)

        fit_handler["fit_line"] = asym_fig.line(
            fit_line_real_x_axis,
            fit.get_line(name, fit_line_x_axis, [x['value'] for x in params_]),
            color="red",
            line_width=2)

    fit_button.on_click(fit_callback)

    # Инициализация bokeh app, расположение виджетов
    column_1 = column(gridplot([tab_handler], [asym_fig], merge_tools=False),
                      period_input,
                      width=width_ + 50)
    widgets_ = WidgetBox(depol_start_stop_buttons, depol_input_harmonic_number,
                         depol_input_attenuation, depol_input_speed,
                         depol_input_step, depol_input_initial,
                         depol_input_final, depol_status_window)

    row_21 = column(hist_fig, hist_slider)
    column_21 = column(widgets_)
    if config.GEM_idle:
        column_22 = column(fit_button, clear_fit_button, fake_depol_button,
                           fit_line_selection_widget,
                           fit_function_selection_widget, energy_window,
                           make_parameters_table())
        make_parameters_table_id = 6
    else:
        column_22 = column(fit_button, clear_fit_button,
                           fit_line_selection_widget,
                           fit_function_selection_widget, energy_window,
                           make_parameters_table())
        make_parameters_table_id = 5

    def rebuild_table(attr, old, new):
        column_22.children[make_parameters_table_id] = make_parameters_table()

    fit_function_selection_widget.on_change("value", rebuild_table)

    row_22 = row(column_21, column_22)
    column_2 = column(row_21, row_22, width=width_ + 50)
    layout_ = layout([[column_1, column_2]])

    # Настройка документа Bokeh

    update_data()
    doc.add_periodic_callback(hist_update,
                              1000)  # TODO запихнуть в один callback
    doc.add_periodic_callback(update_data, 1000)  # TODO: подобрать периоды
    doc.add_periodic_callback(update_depol_status, 1000)
    doc.title = "Laser polarimeter"
    doc.add_root(layout_)
Esempio n. 8
0
def score_plot(session, event):
    from bokeh.plotting import figure
    from bokeh.models.sources import ColumnDataSource
    from bokeh.models.formatters import DatetimeTickFormatter

    submissions = get_submissions(session, event.name, None)
    submissions = [
        get_submission_by_id(session, sub_id) for sub_id, _, _ in submissions
        if get_submission_by_id(session, sub_id).is_public_leaderboard
        and get_submission_by_id(session, sub_id).is_valid
    ]
    score_names = [score_type.name for score_type in event.score_types]
    scoress = np.array([[
        score.valid_score_cv_bag
        for score in submission.ordered_scores(score_names)
    ] for submission in submissions]).T

    score_plot_df = pd.DataFrame()
    score_plot_df['submitted at (UTC)'] = [
        submission.submission_timestamp for submission in submissions
    ]
    score_plot_df['contributivity'] = [
        submission.contributivity for submission in submissions
    ]
    score_plot_df['historical contributivity'] = [
        submission.historical_contributivity for submission in submissions
    ]
    for score_name in score_names:  # to make sure the column is created
        score_plot_df[score_name] = 0
    for score_name, scores in zip(score_names, scoress):
        score_plot_df[score_name] = scores

    score_name = event.official_score_name
    score_plot_df = score_plot_df[
        score_plot_df['submitted at (UTC)'] > event.opening_timestamp]
    score_plot_df = score_plot_df.sort_values('submitted at (UTC)')
    score_plot_df = add_pareto(score_plot_df, score_name,
                               event.official_score_type.worst,
                               event.official_score_type.is_lower_the_better)

    is_open = (score_plot_df['submitted at (UTC)'] >
               event.public_opening_timestamp).values

    max_contributivity = max(0.0000001,
                             max(score_plot_df['contributivity'].values))
    max_historical_contributivity = max(
        0.0000001, max(score_plot_df['historical contributivity'].values))

    fill_color_1 = (176, 23, 31)
    fill_color_2 = (16, 78, 139)
    fill_colors_1 = color_gradient(
        fill_color_1,
        score_plot_df['contributivity'].values / max_contributivity)
    fill_colors_2 = color_gradient(
        fill_color_2, score_plot_df['historical contributivity'].values /
        max_historical_contributivity)
    fill_colors = np.minimum(fill_colors_1, fill_colors_2).astype(int)
    fill_colors = ["#%02x%02x%02x" % (c[0], c[1], c[2]) for c in fill_colors]

    score_plot_df['x'] = score_plot_df['submitted at (UTC)']
    score_plot_df['y'] = score_plot_df[score_name]
    score_plot_df['line_color'] = 'royalblue'
    score_plot_df['circle_size'] = 8
    score_plot_df['line_color'] = 'royalblue'
    score_plot_df.loc[is_open, 'line_color'] = 'coral'
    score_plot_df['fill_color'] = fill_colors
    score_plot_df['fill_alpha'] = 0.5
    score_plot_df['line_width'] = 0
    score_plot_df['label'] = 'closed phase'
    score_plot_df.loc[is_open, 'label'] = 'open phase'

    source = ColumnDataSource(score_plot_df)
    pareto_df = score_plot_df[score_plot_df[score_name +
                                            ' pareto'] == 1].copy()
    pareto_df = pareto_df.append(pareto_df.iloc[-1])
    pareto_df.iloc[-1,
                   pareto_df.columns.get_loc('x')] = (max(score_plot_df['x']))
    pareto_df = make_step_df(pareto_df,
                             event.official_score_type.is_lower_the_better)
    source_pareto = ColumnDataSource(pareto_df)

    tools = ['pan,wheel_zoom,box_zoom,reset,previewsave,tap']
    p = figure(plot_width=900, plot_height=600, tools=tools, title='Scores')

    p.circle('x',
             'y',
             size='circle_size',
             line_color='line_color',
             fill_color='fill_color',
             fill_alpha='fill_alpha',
             line_width=1,
             source=source,
             legend='label')
    p.line('x',
           'y',
           line_width=3,
           line_color='goldenrod',
           source=source_pareto,
           legend='best score',
           alpha=0.9)

    p.xaxis.formatter = DatetimeTickFormatter(
        hours=['%d %B %Y'],
        days=['%d %B %Y'],
        months=['%d %B %Y'],
        years=['%d %B %Y'],
    )
    p.xaxis.major_label_orientation = np.pi / 4

    if event.official_score_type.is_lower_the_better:
        p.yaxis.axis_label = score_name + ' (the lower the better)'
        p.legend.location = 'top_right'
    else:
        p.yaxis.axis_label = score_name + ' (the greater the better)'
        p.legend.location = 'bottom_right'
    p.xaxis.axis_label = 'submission timestamp (UTC)'
    p.xaxis.axis_label_text_font_size = '14pt'
    p.yaxis.axis_label_text_font_size = '14pt'
    p.legend.label_text_font_size = '14pt'
    p.title.text_font_size = '16pt'
    p.xaxis.major_label_text_font_size = '10pt'
    p.yaxis.major_label_text_font_size = '10pt'
    return p
Esempio n. 9
0
def deceased_cases():
    dec_cases_excel = 'https://www.skane.se/globalassets/lagesbild-covid-19-i-skane/avlidna-per-dag.xlsx'

    apd = pd.read_excel(dec_cases_excel, sheet_name='Blad1', usecols="A:F")
    apd.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
    apd.dropna()
    date = apd['Date'].copy().tolist()
    date = fix_dates(date)
    tickers = fix_mondays(date).astype(int) / 10**6
    tot = apd['Totalt antal avlidna i Skåne'].tolist()
    tot = [int(i) for i in tot]

    totps = apd['Totalt antal avlidna på sjukhus'].tolist()
    totps = [int(i) for i in totps]
    dagps = apd['Dagligt antal avlidna på sjukhus'].tolist()
    dagps = [int(i) for i in dagps]

    totus = apd['Totalt antal avlidna utanför sjukhus'].tolist()
    totus = [int(i) for i in totus]
    dagus = apd['Dagligt antal avlidna utanför sjukhus'].tolist()
    dagus = [int(i) for i in dagus]

    legend_cases = [
        'Dagligt antal avlidna på sjukhus',
        'Dagligt antal avlidna utanför sjukhus'
    ]
    vart = ['Daps', 'Daus']
    colors = ["#5069c8", "#bfc8f6"]

    data = {
        'Date': datetime(date),
        'Tot': tot,
        'Totps': totps,
        'Daps': dagps,
        'Totus': totus,
        'Daus': dagus
    }

    min_x_range = max(date) - timedelta(days=30)
    max_x_range = max(date) + timedelta(days=1)

    p = figure(y_range=(0, max(max(totps), max(totus)) * 1.1),
               title="Avlidna per dag",
               x_axis_type='datetime',
               x_range=(min_x_range, max_x_range),
               plot_width=950,
               tools="xpan",
               plot_height=300,
               x_axis_location="above")

    p.add_tools(
        HoverTool(tooltips=[
            ('Datum', '@Date{%F}'),
            ('Totalt antal avlidna i Skåne', '@Tot'),
            ('Totalt antal avlidna på sjukhus', '@Totps'),
            ('Totalt antal avlidna utanför sjukhus', '@Totus'),
            ('Dagligt antal avlidna på sjukhus', '@Daps'),
            ('Dagligt antal avlidna utanför sjukhus', '@Daus'),
        ],
                  formatters={'@Date': 'datetime'}))

    p.xaxis.axis_label = 'Datum'
    p.xaxis.ticker = FixedTicker(ticks=list(tickers))
    p.yaxis.axis_label = 'Totala Fall'
    p.toolbar_location = None
    p.grid.grid_line_alpha = 0.3

    p.extra_y_ranges["dfall"] = Range1d(start=0,
                                        end=max(data['Daps']) +
                                        max(data['Daus']))
    p.vbar_stack(vart,
                 x='Date',
                 y_range_name="dfall",
                 width=60000000,
                 color=colors,
                 source=data,
                 legend_label=["%s" % x for x in legend_cases])
    p.add_layout(LinearAxis(y_range_name="dfall", axis_label="Dagliga Fall"),
                 'right')

    p.line(y='Totps',
           x='Date',
           color="#5069c8",
           legend_label="Totalt antal avlidna på sjukhus",
           source=data)
    p.line(y='Totus',
           x='Date',
           color="#c75650",
           legend_label="Totalt antal avlidna utanför sjukhus",
           source=data)

    p.xaxis.formatter = DatetimeTickFormatter(days=["%Y-%m-%d"])
    p.legend.location = "top_left"
    p.legend.background_fill_alpha = 0.2
    p.legend.border_line_alpha = 0.0

    select = figure(
        title="Dra i mitten eller kanterna av rutan för att ändra ovan",
        plot_height=130,
        plot_width=950,
        y_range=p.y_range,
        x_axis_type="datetime",
        y_axis_type=None,
        tools="",
        toolbar_location=None,
        background_fill_color="#efefef")

    range_tool = RangeTool(x_range=p.x_range)
    range_tool.overlay.fill_color = "navy"
    range_tool.overlay.fill_alpha = 0.2

    select.line('Date', 'Totps', color="#5069c8", source=data)
    select.line('Date', 'Totus', color="#c75650", source=data)
    select.ygrid.grid_line_color = None
    select.add_tools(range_tool)
    select.toolbar.active_multi = range_tool
    select.xaxis.formatter = DatetimeTickFormatter(days=["%Y-%m-%d"])

    return column(p, select)