Динамическое обновление нескольких линий в обратном вызове в боке - PullRequest
0 голосов
/ 04 мая 2018

У меня есть вариант использования, когда у меня есть несколько линейных графиков (с легендами), и мне нужно обновить линейные графики на основе условия столбца. Ниже приведен пример двух наборов данных, в зависимости от страны, источник данных столбца изменяется. Но проблема, с которой я сталкиваюсь, заключается в том, что количество столбцов не является фиксированным для источника данных, и даже типы могут различаться. Итак, когда я обновляю источник данных на основе обратного вызова, когда выбрана новая страна, я получаю эту ошибку:

Error: attempted to retrieve property array for nonexistent field 'pay_conv_7d.content'. 

Я предполагаю, потому что в новом источнике данных столбец pay_conv_7d.content не существует, но на моем графике эти строки уже были. Я пытался решить эту проблему различными способами (создавая общие столбцы для выбора всей страны - добавляя отсутствующий столбец в источник данных при обратном вызове, но все еще получал проблемы.

Есть ли какой-нибудь чистый способ обновления многострочных графиков с помощью обратного вызова, и не делать много хакерского пути? Любые идеи или помощь будут очень признательны. Большое спасибо заранее! :)

def setup_multiline_plots(x_axis, y_axis, title_text, data_source, plot):
    num_categories = len(data_source.data['categories'])
    legends_list = list(data_source.data['categories'])
    colors_list = Spectral11[0:num_categories]
    # xs = [data_source.data['%s.'%x_axis].values] * num_categories
    # ys = [data_source.data[('%s.%s')%(y_axis,column)] for column in data_source.data['categories']]
    # data_source.data['x_series'] = xs
    # data_source.data['y_series'] = ys
    # plot.multi_line('x_series', 'y_series', line_color=colors_list,legend='categories', line_width=3, source=data_source)
    plot_list = []
    for (colr, leg, column) in zip(colors_list, legends_list, data_source.data['categories']):
        xs, ys = '%s.'%x_axis, ('%s.%s')%(y_axis,column)
        plot.line(xs,ys, source=data_source, color=colr, legend=leg, line_width=3, name=ys)
        plot_list.append(ys)
    data_source.data['plot_names'] = data_source.data.get('plot_names',[]) + plot_list
    plot.title.text = title_text

def update_plot(country, timeseries_df, timeseries_source,
                aggregate_df, aggregate_source, category,
                plot_pay_7d, plot_r_pay_90d):

    aggregate_metrics = aggregate_df.loc[aggregate_df.country == country]
    aggregate_metrics = aggregate_metrics.nlargest(10, 'cost')
    category_types = list(aggregate_metrics[category].unique())
    timeseries_df = timeseries_df[timeseries_df[category].isin(category_types)]
    timeseries_multi_line_metrics = get_multiline_column_datasource(timeseries_df, category, country)

    # len_series = len(timeseries_multi_line_metrics.data['time.'])
    # previous_legends = timeseries_source.data['plot_names']
    # current_legends = timeseries_multi_line_metrics.data.keys()
    # common_legends = list(set(previous_legends) & set(current_legends))
    # additional_legends_list = list(set(previous_legends) - set(current_legends))
    # for legend in additional_legends_list:
    #     zeros = pd.Series(np.array([0] * len_series), name=legend)
    #     timeseries_multi_line_metrics.add(zeros, legend)
    # timeseries_multi_line_metrics.data['plot_names'] = previous_legends

    timeseries_source.data = timeseries_multi_line_metrics.data
    aggregate_source.data = aggregate_source.from_df(aggregate_metrics)

def get_multiline_column_datasource(df, category, country):

    df_country = df[df.country == country]
    df_pivoted = pd.DataFrame(df_country.pivot_table(index='time', columns=category, aggfunc=np.sum).reset_index())
    df_pivoted.columns = df_pivoted.columns.to_series().str.join('.')
    categories = list(set([column.split('.')[1] for column in list(df_pivoted.columns)]))[1:]
    data_source = ColumnDataSource(df_pivoted)
    data_source.data['categories'] = categories

1 Ответ

0 голосов
/ 04 мая 2018

Недавно мне пришлось обновить данные на глифе Multiline. Отметьте мой вопрос , если хотите взглянуть на мой алгоритм.

Я думаю, вы можете обновить ColumnDataSource как минимум тремя способами:

  1. Вы можете создать фрейм данных для создания нового CDS

    cds = ColumnDataSource(df_pivoted)
    data_source.data = cds.data
    
  2. Вы можете создать словарь и присвоить его атрибуту данных напрямую

    d = {
        'xs0': [[7.0, 986.0], [17.0, 6.0], [7.0, 67.0]],
        'ys0': [[79.0, 69.0], [179.0, 169.0], [729.0, 69.0]],
        'xs1': [[17.0, 166.0], [17.0, 116.0], [17.0, 126.0]],
        'ys1': [[179.0, 169.0], [179.0, 1169.0], [1729.0, 169.0]],
        'xs2': [[27.0, 276.0], [27.0, 216.0], [27.0, 226.0]],
        'ys2': [[279.0, 269.0], [279.0, 2619.0], [2579.0, 2569.0]]
    }
    data_source.data = d
    

    Здесь, если вам нужны столбцы разных размеров или пустые столбцы, вы можете заполнить пробелы значениями NaN, чтобы сохранить размеры столбцов. И я думаю, что это решение вашего вопроса:

    import numpy as np
    d = {
        'xs0': [[7.0, 986.0], [17.0, 6.0], [7.0, 67.0]],
        'ys0': [[79.0, 69.0], [179.0, 169.0], [729.0, 69.0]],
        'xs1': [[17.0, 166.0], [np.nan], [np.nan]],
        'ys1': [[179.0, 169.0], [np.nan], [np.nan]],
        'xs2': [[np.nan], [np.nan], [np.nan]],
        'ys2': [[np.nan], [np.nan], [np.nan]]
    }
    data_source.data = d
    
  3. Или, если вам нужно изменить только несколько значений, вы можете использовать метод patch. Проверьте документацию здесь .

    В следующем примере показано, как исправить все элементы столбца. В этом случае

        source = ColumnDataSource(data=dict(foo=[10, 20, 30], bar=[100, 200, 300]))
        patches = {
            'foo' : [ (slice(2), [11, 12]) ],
            'bar' : [ (0, 101), (2, 301) ],
        }
        source.patch(patches)
    

    После этой операции значение source.data будет:

        dict(foo=[11, 22, 30], bar=[101, 200, 301])
    

ПРИМЕЧАНИЕ : Важно сделать обновление за один раз, чтобы избежать проблем с производительностью

...