diff --git a/taxcalc/calculate.py b/taxcalc/calculate.py index 938eea401..14f34ee48 100644 --- a/taxcalc/calculate.py +++ b/taxcalc/calculate.py @@ -38,8 +38,7 @@ ce_aftertax_expanded_income, mtr_graph_data, atr_graph_data, xtr_graph_plot, dec_graph_data, dec_graph_plot, - pch_graph_data, pch_graph_plot, - qin_graph_data, qin_graph_plot) + pch_graph_data, pch_graph_plot) # import pdb @@ -991,7 +990,7 @@ def pch_graph(self, calc): title='') return fig - def decile_graph(self, calc, set_bottom_decile_result_to_zero=True): + def decile_graph(self, calc, hide_negative_incomes=True): """ Create graph that shows percentage change in aftertax expanded income (from going from policy in self to policy in calc) for @@ -1001,8 +1000,6 @@ def decile_graph(self, calc, set_bottom_decile_result_to_zero=True): immediately in an interactive or notebook session (following the instructions in the documentation of the xtr_graph_plot utility function). - Note that some deciles may contain filing units with negative - or zero baseline (self) expanded income. Parameters ---------- @@ -1011,11 +1008,16 @@ def decile_graph(self, calc, set_bottom_decile_result_to_zero=True): where both self and calc have calculated taxes for this year before being used by this method - set_bottom_decile_result_to_zero : boolean - specify whether or not bottom decile (which contains filing - units with non-positive expanded income) result is shown in the - graph (default value is True; set to False to show the bottom - decile result) + hide_negative_incomes : boolean + if True (which is the default), the bottom table bin containing + filing units with non-positive expanded_income is not shown in + the graph and the table bin containing filing units with positive + expanded_income in the bottom decile is shown with its bar width + adjusted to the number of weighted filing units in bottom decile + who have positive expanded_income; if False, the bottom table bin + containing filing units with non-positive expanded_income is shown, + which may be misleading because the percentage change is correctly + calculated with a negative divisor. Returns ------- @@ -1030,9 +1032,8 @@ def decile_graph(self, calc, set_bottom_decile_result_to_zero=True): income_measure='expanded_income', tax_to_diff='combined') # construct data for graph - data = dec_graph_data(diff_table, year=self.current_year) - if set_bottom_decile_result_to_zero: - data['bars'][0]['value'] = 0 + data = dec_graph_data(diff_table, year=self.current_year, + hide_negative_incomes=hide_negative_incomes) # construct figure from data fig = dec_graph_plot(data, width=850, @@ -1042,56 +1043,6 @@ def decile_graph(self, calc, set_bottom_decile_result_to_zero=True): title='') return fig - def quintile_graph(self, calc, set_bottom_quintile_result_to_zero=True): - """Create graph that shows percentage change in aftertax expanded - income (from going from policy in self to policy in calc) for - each expanded-income quintile and subgroups of the top quintile. - The graph can be written to an HTML file (using the - write_graph_file utility function) or shown on the screen - immediately in an interactive or notebook session (following - the instructions in the documentation of the xtr_graph_plot - utility function). - Note that some quintiles may contain filing units with negative - or zero baseline (self) expanded income. - - Parameters - ---------- - calc : Calculator object - calc represents the reform while self represents the baseline, - where both self and calc have calculated taxes for this year - before being used by this method - - set_bottom_quintile_result_to_zero : boolean - specify whether or not bottom quintile (which contains filing - units with non-positive expanded income) result is shown in the - graph (default value is True; set to False to show the bottom - quintile result) - - Returns - ------- - graph that is a bokeh.plotting figure object - """ - # check that two Calculator objects are comparable - assert isinstance(calc, Calculator) - assert calc.current_year == self.current_year - assert calc.array_len == self.array_len - diff_table = self.difference_table(calc, - groupby='weighted_deciles', - income_measure='expanded_income', - tax_to_diff='combined') - # construct data for graph - data = qin_graph_data(diff_table, year=self.current_year) - if set_bottom_quintile_result_to_zero: - data['bars'][0]['value'] = 0 - # construct figure from data - fig = qin_graph_plot(data, - width=850, - height=500, - xlabel='', - ylabel='', - title='') - return fig - @staticmethod def read_json_param_objects(reform, assump): """ diff --git a/taxcalc/consumption.json b/taxcalc/consumption.json index bb895d9f3..5bc110552 100644 --- a/taxcalc/consumption.json +++ b/taxcalc/consumption.json @@ -94,7 +94,7 @@ "_BEN_vet_value": { "long_name": "Consumption value of veterans benefits", - "description": "Consumption value per dollar of veterans benefits, some of which are in-kind benefits (about 40% are in-kind medical benefits).", + "description": "Consumption value per dollar of veterans benefits, some of which are in-kind benefits (about 40% are in-kind medical benefits and overall about 51% are in-kind benefits).", "section_1": "", "section_2": "", "notes": "", diff --git a/taxcalc/tests/test_utils.py b/taxcalc/tests/test_utils.py index 874fb341c..e362847e7 100644 --- a/taxcalc/tests/test_utils.py +++ b/taxcalc/tests/test_utils.py @@ -87,17 +87,17 @@ def test_create_tables(cps_subsample): tax_to_diff='combined') assert isinstance(diff, pd.DataFrame) expected = [0.00, - 0.02, - 0.58, - 0.72, - 0.67, - 0.78, - 0.77, - 0.64, - 0.56, - 0.17, - 0.53] - tabcol = 'perc_aftertax' + -0.02, + -0.58, + -0.72, + -0.67, + -0.78, + -0.77, + -0.64, + -0.56, + -0.17, + -0.53] + tabcol = 'pc_aftertaxinc' if not np.allclose(diff[tabcol].values, expected, atol=0.005, rtol=0.0, equal_nan=True): test_failure = True @@ -112,19 +112,19 @@ def test_create_tables(cps_subsample): tax_to_diff='iitax') assert isinstance(diff, pd.DataFrame) expected = [0.00, - 0.02, - 0.58, - 0.72, - 0.67, - 0.78, - 0.77, - 0.64, - 0.56, - 0.22, - 0.08, - 0.06, - 0.53] - tabcol = 'perc_aftertax' + -0.02, + -0.58, + -0.72, + -0.67, + -0.78, + -0.77, + -0.64, + -0.56, + -0.22, + -0.08, + -0.06, + -0.53] + tabcol = 'pc_aftertaxinc' if not np.allclose(diff[tabcol].values, expected, atol=0.005, rtol=0.0, equal_nan=True): test_failure = True @@ -139,26 +139,26 @@ def test_create_tables(cps_subsample): tax_to_diff='iitax') assert isinstance(diff, pd.DataFrame) expected = [0.00, - 0.01, - 0.03, - 0.24, - 0.78, - 0.66, - 0.76, - 0.67, - 0.78, - 0.77, - 0.64, - 0.56, - 0.22, - 0.08, - 0.08, - 0.07, - 0.05, - 0.03, + -0.01, + -0.03, + -0.24, + -0.78, + -0.66, + -0.76, + -0.67, + -0.78, + -0.77, + -0.64, + -0.56, + -0.22, + -0.08, + -0.08, + -0.07, + -0.05, + -0.03, 0.00, - 0.53] - tabcol = 'perc_aftertax' + -0.53] + tabcol = 'pc_aftertaxinc' if not np.allclose(diff[tabcol].values, expected, atol=0.005, rtol=0.0, equal_nan=True): test_failure = True @@ -172,7 +172,8 @@ def test_create_tables(cps_subsample): income_measure='expanded_income', tax_to_diff='combined') assert isinstance(diff, pd.DataFrame) - expected = [171711, + expected = [0, + 171711, 15725179, 26767322, 33151429, @@ -193,7 +194,8 @@ def test_create_tables(cps_subsample): print('diff', tabcol) for val in diff[tabcol].values: print('{:.0f},'.format(val)) - expected = [0.03, + expected = [0.00, + 0.03, 2.94, 5.00, 6.20, @@ -214,28 +216,30 @@ def test_create_tables(cps_subsample): print('diff', tabcol) for val in diff[tabcol].values: print('{:.2f},'.format(val)) - expected = [0.02, - 0.63, - 0.72, - 0.69, - 0.77, - 0.75, - 0.75, - 0.62, - 0.59, - 0.28, - 0.53, - 0.52, - 0.23, - 0.06] - tabcol = 'perc_aftertax' + expected = [0.00, + -0.02, + -0.63, + -0.72, + -0.69, + -0.77, + -0.75, + -0.75, + -0.62, + -0.59, + -0.28, + -0.53, + -0.52, + -0.23, + -0.06] + tabcol = 'pc_aftertaxinc' if not np.allclose(diff[tabcol].values, expected, atol=0.005, rtol=0.0, equal_nan=True): test_failure = True print('diff', tabcol) for val in diff[tabcol].values: print('{:.2f},'.format(val)) - expected = [-0.02, + expected = [0.00, + -0.02, -0.63, -0.72, -0.69, @@ -264,7 +268,8 @@ def test_create_tables(cps_subsample): income_measure='expanded_income', result_type='weighted_sum') assert isinstance(dist, pd.DataFrame) - expected = [-58122959, + expected = [0, + -58122959, -69644449, -67116585, 47133880, @@ -285,7 +290,8 @@ def test_create_tables(cps_subsample): print('dist', tabcol) for val in dist[tabcol].values: print('{:.0f},'.format(val)) - expected = [1202, + expected = [0, + 1202, 13625, 22333, 27220, @@ -306,7 +312,8 @@ def test_create_tables(cps_subsample): print('dist', tabcol) for val in dist[tabcol].values: print('{:.0f},'.format(val)) - expected = [795716514, + expected = [0, + 795716514, 2643384899, 3946422611, 5277286335, @@ -327,7 +334,8 @@ def test_create_tables(cps_subsample): print('dist', tabcol) for val in dist[tabcol].values: print('{:.0f},'.format(val)) - expected = [782122416, + expected = [0, + 782122416, 2478134056, 3682019346, 4789142820, @@ -707,17 +715,9 @@ def test_add_quantile_bins(): default_labels = set(range(1, 101)) for lab in bin_labels: assert lab in default_labels - # custom labels dfb = add_quantile_bins(dfx, 'expanded_income', 100, weight_by_income_measure=True) assert 'bins' in dfb - custom_labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] - dfb = add_quantile_bins(dfx, 'expanded_income', 10, - labels=custom_labels) - assert 'bins' in dfb - bin_labels = dfb['bins'].unique() - for lab in bin_labels: - assert lab in custom_labels def test_dist_table_sum_row(cps_subsample): @@ -988,10 +988,10 @@ def test_dec_qin_graph_plots(cps_subsample): assert calc1.current_year == calc2.current_year calc1.calc_all() calc2.calc_all() - fig_dec = calc1.decile_graph(calc2) - assert fig_dec - fig_qin = calc1.quintile_graph(calc2) - assert fig_qin + fig_dec_hide = calc1.decile_graph(calc2) + assert fig_dec_hide + fig_dec_show = calc1.decile_graph(calc2, hide_negative_incomes=False) + assert fig_dec_show def test_nonsmall_diffs(): diff --git a/taxcalc/utils.py b/taxcalc/utils.py index f3095ba98..6f232fd69 100644 --- a/taxcalc/utils.py +++ b/taxcalc/utils.py @@ -96,7 +96,6 @@ 'mean', 'tot_change', 'share_of_change', - 'perc_aftertax', 'pc_aftertaxinc'] DIFF_TABLE_LABELS = ['All Tax Units', @@ -107,32 +106,27 @@ 'Average Tax Change', 'Total Tax Difference', 'Share of Overall Change', - 'Change as % of After-Tax Income', '% Change in After-Tax Income'] -DECILE_ROW_NAMES = ['0-10', '10-20', '20-30', '30-40', '40-50', +DECILE_ROW_NAMES = ['0-10zn', '0-10p', '10-20', '20-30', '30-40', '40-50', '50-60', '60-70', '70-80', '80-90', '90-100', 'all', '90-95', '95-99', 'Top 1%'] -QUINTILE_ROW_NAMES = ['0-20', '20-40', '40-60', '60-80', '80-100', - 'all', - '80-90', '90-95', '95-99', 'Top 1%'] - -STANDARD_ROW_NAMES = ['<$0K', '$0-10K', '$10-20K', '$20-30K', '$30-40K', +STANDARD_ROW_NAMES = ['<=$0K', '$0-10K', '$10-20K', '$20-30K', '$30-40K', '$40-50K', '$50-75K', '$75-100K', '$100-200K', '$200-500K', '$500-1000K', '>$1000K', 'all'] -STANDARD_INCOME_BINS = [-9e99, 0, 9999, 19999, 29999, 39999, 49999, +STANDARD_INCOME_BINS = [-9e99, 1e-9, 9999, 19999, 29999, 39999, 49999, 74999, 99999, 199999, 499999, 1000000, 9e99] -LARGE_INCOME_BINS = [-9e99, 0, 9999, 19999, 29999, 39999, 49999, +LARGE_INCOME_BINS = [-9e99, 1e-9, 9999, 19999, 29999, 39999, 49999, 74999, 99999, 200000, 9e99] -SMALL_INCOME_BINS = [-9e99, 0, 4999, 9999, 14999, 19999, 24999, 29999, 39999, - 49999, 74999, 99999, 199999, 499999, 999999, 1499999, - 1999999, 4999999, 9999999, 9e99] +SMALL_INCOME_BINS = [-9e99, 1e-9, 4999, 9999, 14999, 19999, 24999, 29999, + 39999, 49999, 74999, 99999, 199999, 499999, 999999, + 1499999, 1999999, 4999999, 9999999, 9e99] def unweighted_sum(pdf, col_name): @@ -150,7 +144,7 @@ def weighted_sum(pdf, col_name): def add_quantile_bins(pdf, income_measure, num_bins, - weight_by_income_measure=False, labels=None): + weight_by_income_measure=False): """ Add a column of income bins to specified Pandas DataFrame, pdf, with the new column being named 'bins'. The bins hold equal number of @@ -173,8 +167,7 @@ def add_quantile_bins(pdf, income_measure, num_bins, bin_edges = list(min_cumsum + np.arange(0, (num_bins + 1)) * bin_width) bin_edges[-1] = 9e99 # raise top of last bin to include all observations bin_edges[0] = -9e99 # lower bottom of 1st bin to include all observations - if not labels: - labels = range(1, (num_bins + 1)) + labels = range(1, (num_bins + 1)) pdf['bins'] = pd.cut(pdf['cumsum_temp'], bins=bin_edges, labels=labels) pdf.drop('cumsum_temp', axis=1, inplace=True) return pdf @@ -259,7 +252,10 @@ def create_distribution_table(vdf, groupby, income_measure, result_type): extra rows containing top-decile detail consisting of statistics for the 0.90-0.95 quantile range (bottom half of top decile), for the 0.95-0.99 quantile range, and - for the 0.99-1.00 quantile range (top one percent). + for the 0.99-1.00 quantile range (top one percent); and the returned + table may have a fourth extra row that shows bottom-decile detail + with the bottom decile split into filing units with non-positive and + positive values of the specified income_measure variable. result_type : String object options for input: 'weighted_sum' or 'weighted_avg'; @@ -272,9 +268,10 @@ def create_distribution_table(vdf, groupby, income_measure, result_type): Notes ----- Taxpayer Characteristics: - c04470 : Total itemized deduction - c00100 : AGI (Defecit) + c04470 : Total itemized deductions + + c00100 : AGI c09600 : Alternative minimum tax @@ -356,6 +353,16 @@ def stat_dataframe(gpdf): # append sum row row = get_sums(dist_table)[dist_table.columns] dist_table = dist_table.append(row) + # replace bottom decile row with non-positive and positive rows + if groupby == 'weighted_deciles' and pdf[income_measure].min() <= 0: + pdf = gpdf.get_group(1) # bottom decile as its own DataFrame + pdf = copy.deepcopy(pdf) # eliminates Pandas warning in pd.cut() + pdf['bins'] = pd.cut(pdf[income_measure], + bins=[-9e99, 1e-9, 9e99], + labels=[1, 2]) + gpdfx = pdf.groupby('bins', as_index=False) + rows = stat_dataframe(gpdfx) + dist_table = pd.concat([rows, dist_table.iloc[1:11]]) # append top-decile-detail rows if groupby == 'weighted_deciles': pdf = gpdf.get_group(10) # top decile as its own DataFrame @@ -365,8 +372,8 @@ def stat_dataframe(gpdf): pdf['bins'].replace(to_replace=[6, 7, 8, 9], value=[1, 1, 1, 1], inplace=True) pdf['bins'].replace(to_replace=[10], value=[2], inplace=True) - gpdf = pdf.groupby('bins', as_index=False) - rows = stat_dataframe(gpdf) + gpdfx = pdf.groupby('bins', as_index=False) + rows = stat_dataframe(gpdfx) dist_table = dist_table.append(rows, ignore_index=True) # optionally construct weighted_avg table if result_type == 'weighted_avg': @@ -403,7 +410,10 @@ def create_difference_table(vdf1, vdf2, groupby, income_measure, tax_to_diff): extra rows containing top-decile detail consisting of statistics for the 0.90-0.95 quantile range (bottom half of top decile), for the 0.95-0.99 quantile range, and - for the 0.99-1.00 quantile range (top one percent). + for the 0.99-1.00 quantile range (top one percent); and the returned + table may have a fourth extra row that shows bottom-decile detail + with the bottom decile split into filing units with non-positive and + positive values of the specified income_measure variable. income_measure : String object options for input: 'expanded_income', 'c00100'(AGI) @@ -487,6 +497,16 @@ def weighted_share_of_total(gpdf, colname, total): row['perc_inc'] = sums_perc_inc row['share_of_change'] = 1.0 # avoid rounding error diffs = diffs_without_sums.append(row) + # replace bottom decile row with non-positive and positive rows + if groupby == 'weighted_deciles' and pdf[income_measure].min() <= 0: + pdf = gpdf.get_group(1) # bottom decile as its own DataFrame + pdf = copy.deepcopy(pdf) # eliminates Pandas warning in pd.cut() + pdf['bins'] = pd.cut(pdf[income_measure], + bins=[-9e99, 1e-9, 9e99], + labels=[1, 2]) + gpdfx = pdf.groupby('bins', as_index=False) + rows = stat_dataframe(gpdfx) + diffs = pd.concat([rows, diffs.iloc[1:11]]) # append top-decile-detail rows if groupby == 'weighted_deciles': pdf = gpdf.get_group(10) # top decile as its own DataFrame @@ -532,16 +552,14 @@ def weighted_share_of_total(gpdf, colname, total): res2['atinc1'] = res1['aftertax_income'] res2['atinc2'] = res2['aftertax_income'] diffs = diff_table_stats(res2, groupby, baseline_income_measure) - diffs['perc_aftertax'] = diffs['tot_change'] / diffs['atinc1'] - diffs['perc_aftertax'].replace(to_replace=np.nan, value=0, inplace=True) diffs['pc_aftertaxinc'] = (diffs['atinc2'] / diffs['atinc1']) - 1.0 diffs['pc_aftertaxinc'].replace(to_replace=np.nan, value=0, inplace=True) # delete intermediate atinc1 and atinc2 columns del diffs['atinc1'] del diffs['atinc2'] # convert some columns to percentages - percent_columns = ['perc_inc', 'perc_cut', 'share_of_change', - 'perc_aftertax', 'pc_aftertaxinc'] + percent_columns = ['perc_inc', 'perc_cut', + 'share_of_change', 'pc_aftertaxinc'] for col in percent_columns: diffs[col] *= 100.0 # set print display format for float table elements @@ -1427,7 +1445,7 @@ def bootstrap_se_ci(data, seed, num_samples, statistic, alpha): return bsest -def dec_graph_data(diff_table, year): +def dec_graph_data(diff_table, year, hide_negative_incomes=True): """ Prepare data needed by dec_graph_plot utility function. @@ -1446,7 +1464,11 @@ def dec_graph_data(diff_table, year): # construct dictionary containing the bar data required by dec_graph_plot bars = dict() nbins = len(DECILE_ROW_NAMES) - for idx in range(0, nbins): + if hide_negative_incomes: + first_bin = 1 + else: + first_bin = 0 + for idx in range(first_bin, nbins): info = dict() info['label'] = DECILE_ROW_NAMES[idx] info['value'] = diff_table['pc_aftertaxinc'][idx] @@ -1456,6 +1478,10 @@ def dec_graph_data(diff_table, year): bars[idx] = info # construct dictionary containing bar data and auto-generated labels data = dict() + data['hide_neg'] = hide_negative_incomes + bottom_count = diff_table['count'][0] + diff_table['count'][1] + data['neg_bar_size'] = diff_table['count'][0] / bottom_count + data['pos_bar_size'] = diff_table['count'][1] / bottom_count data['bars'] = bars xlabel = 'Reform-Induced Percentage Change in After-Tax Expanded Income' data['xlabel'] = xlabel @@ -1558,6 +1584,14 @@ def dec_graph_plot(data, bval = data['bars'][idx]['value'] blabel = data['bars'][idx]['label'] bheight = barheight + if data['hide_neg']: + if yidx == 0: + bheight *= data['pos_bar_size'] + else: + if yidx == 0: + bheight *= data['neg_bar_size'] + elif yidx == 1: + bheight *= data['pos_bar_size'] if blabel == '90-95': bheight *= 0.5 bcolor = 'red' @@ -1574,168 +1608,6 @@ def dec_graph_plot(data, return fig -def qin_graph_data(diff_table, year): - """ - Prepare data needed by qin_graph_plot utility function. - - Parameters - ---------- - diff_table : a Pandas DataFrame object returned from the - Calculator class difference_table method - - year : integer - specifies calendar year of the data in the diff_table - - Returns - ------- - dictionary object suitable for passing to qin_graph_plot utility function - """ - # aggregate decile+details diff_table into quintile+details diff - qdiff = dict() - for qin in range(0, 5): - dec = 2 * qin - qdiff[qin] = 0.5 * (diff_table['pc_aftertaxinc'][dec] + - diff_table['pc_aftertaxinc'][dec + 1]) - qdiff[5] = diff_table['pc_aftertaxinc'][10] # all - qdiff[6] = diff_table['pc_aftertaxinc'][8] # 80-90 detail - qdiff[7] = diff_table['pc_aftertaxinc'][11] # 90-95 detail - qdiff[8] = diff_table['pc_aftertaxinc'][12] # 95-99 detail - qdiff[9] = diff_table['pc_aftertaxinc'][13] # Top 1% detail - assert len(qdiff) == len(QUINTILE_ROW_NAMES) - # construct dictionary containing the bar data required by qin_graph_plot - bars = dict() - nbins = len(qdiff) - for idx in range(0, nbins): - info = dict() - info['label'] = QUINTILE_ROW_NAMES[idx] - info['value'] = qdiff[idx] - if info['label'] == 'all': - info['label'] = '---------' - info['value'] = 0 - bars[idx] = info - # construct dictionary containing bar data and auto-generated labels - data = dict() - data['bars'] = bars - xlabel = 'Reform-Induced Percentage Change in After-Tax Expanded Income' - data['xlabel'] = xlabel - ylabel = 'Expanded Income Percentile Group' - data['ylabel'] = ylabel - title_str = 'Change in After-Tax Income by Income Percentile Group' - data['title'] = '{} for {}'.format(title_str, year) - return data - - -def qin_graph_plot(data, - width=850, - height=500, - xlabel='', - ylabel='', - title=''): - """ - Plot stacked quintile graph using data returned from the - qin_graph_data function. - - Parameters - ---------- - data : dictionary object returned from qin_graph_data() utility function - - width : integer - width of plot expressed in pixels - - height : integer - height of plot expressed in pixels - - xlabel : string - x-axis label; if '', then use label generated by dec_graph_data - - ylabel : string - y-axis label; if '', then use label generated by dec_graph_data - - title : string - graph title; if '', then use title generated by dec_graph_data - - Returns - ------- - bokeh.plotting figure object containing a raster graphics plot - - Notes - ----- - USAGE EXAMPLE:: - - gdata = dec_graph_data(...) - gplot = dec_graph_plot(gdata) - - THEN when working interactively in a Python notebook:: - - bp.show(gplot) - - OR when executing script using Python command-line interpreter:: - - bio.output_file('graph-name.html', title='Change in After-Tax Income') - bio.show(gplot) [OR bio.save(gplot) WILL JUST WRITE FILE TO DISK] - - WILL VISUALIZE GRAPH IN BROWSER AND WRITE GRAPH TO SPECIFIED HTML FILE - - To convert the visualized graph into a PNG-formatted file, click on - the "Save" icon on the Toolbar (located in the top-right corner of - the visualized graph) and a PNG-formatted file will written to your - Download directory. - - The ONLY output option the bokeh.plotting figure has is HTML format, - which (as described above) can be converted into a PNG-formatted - raster graphics file. There is no option to make the bokeh.plotting - figure generate a vector graphics file such as an EPS file. - """ - # pylint: disable=too-many-arguments,too-many-locals - if title == '': - title = data['title'] - bar_keys = sorted(data['bars'].keys()) - bar_labels = [data['bars'][key]['label'] for key in bar_keys] - fig = bp.figure(plot_width=width, plot_height=height, title=title, - y_range=bar_labels) - fig.title.text_font_size = '12pt' - fig.outline_line_color = None - fig.axis.axis_line_color = None - fig.axis.minor_tick_line_color = None - fig.axis.axis_label_text_font_size = '12pt' - fig.axis.axis_label_text_font_style = 'normal' - fig.axis.major_label_text_font_size = '12pt' - if xlabel == '': - xlabel = data['xlabel'] - fig.xaxis.axis_label = xlabel - fig.xaxis[0].formatter = PrintfTickFormatter(format='%+.1f%%') - if ylabel == '': - ylabel = data['ylabel'] - fig.yaxis.axis_label = ylabel - fig.ygrid.grid_line_color = None - # plot thick x-axis grid line at zero - fig.line(x=[0, 0], y=[0, 14], line_width=1, line_color='black') - # plot bars - barheight = 0.8 - bcolor = 'blue' - yidx = 0 - for idx in bar_keys: - bval = data['bars'][idx]['value'] - blabel = data['bars'][idx]['label'] - bheight = barheight - if blabel == '80-90': - bheight *= 0.50 - bcolor = 'red' - if blabel == '90-95': - bheight *= 0.25 - elif blabel == '95-99': - bheight *= 0.20 - elif blabel == 'Top 1%': - bheight *= 0.05 - fig.rect(x=(bval / 2.0), # x-coordinate of center of the rectangle - y=(yidx + 0.5), # y-coordinate of center of the rectangle - width=abs(bval), # width of the rectangle - height=bheight, # height of the rectangle - color=bcolor) - yidx += 1 - return fig - - def nonsmall_diffs(linelist1, linelist2, small=0.0): """ Return True if line lists differ significantly; otherwise return False.