From 80cbefdfe1e3b2d2863b6b22b7e92e1b7ba83415 Mon Sep 17 00:00:00 2001 From: Alyssa Dai Date: Fri, 20 Sep 2024 16:51:57 -0400 Subject: [PATCH] [MNT] Switch to 1 decimal place for all plots (#94) * set global # decimal places * add param for # decimals in all plotting funcs * specify global # decimals when calling plotting funcs * update type hint --- climate_emotions_map/app.py | 5 +++ climate_emotions_map/layout.py | 5 +++ .../make_descriptive_plots.py | 36 ++++++++++++------- climate_emotions_map/make_map.py | 4 +-- .../make_stacked_bar_plots.py | 12 +++---- climate_emotions_map/utility.py | 2 ++ 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/climate_emotions_map/app.py b/climate_emotions_map/app.py index dc8b651..b7aedbb 100644 --- a/climate_emotions_map/app.py +++ b/climate_emotions_map/app.py @@ -23,6 +23,7 @@ from .utility import ( # IMPACT_COLORMAP,; OPINION_COLORMAP, ALL_STATES_LABEL, DEFAULT_QUESTION, + NUM_DECIMALS, SECTION_TITLES, ) @@ -141,6 +142,7 @@ def update_sample_descriptive_plot(state): """Update the sample descriptive plot based on the selected state.""" return make_descriptive_plots( state=state, + decimals=NUM_DECIMALS, ) @@ -212,6 +214,7 @@ def update_map(question_value, state, impact): impact=impact, colormap_range_padding=MAP_LAYOUT["colormap_range_padding"], margins=MAP_LAYOUT["margin"], + decimals=NUM_DECIMALS, # opinion_colormap=OPINION_COLORMAP, # impact_colormap=IMPACT_COLORMAP, ) @@ -247,6 +250,7 @@ def update_selected_question_bar_plot( state=state, stratify=is_party_stratify_checked, threshold=threshold, + decimals=NUM_DECIMALS, fig_kw=SINGLE_SUBQUESTION_FIG_KW, ) return figure @@ -319,6 +323,7 @@ def update_stacked_bar_plots( state=state, stratify=is_party_stratify_checked, threshold=threshold, + decimals=NUM_DECIMALS, ) figures.append(figure) diff --git a/climate_emotions_map/layout.py b/climate_emotions_map/layout.py index 5c939ef..435534f 100644 --- a/climate_emotions_map/layout.py +++ b/climate_emotions_map/layout.py @@ -12,6 +12,7 @@ from .utility import ( # IMPACT_COLORMAP,; OPINION_COLORMAP, ALL_STATES_LABEL, DEFAULT_QUESTION, + NUM_DECIMALS, SECTION_TITLES, ) @@ -140,6 +141,7 @@ def create_sample_descriptive_plot(): id="sample-descriptive-plot", figure=make_descriptive_plots( state=None, + decimals=NUM_DECIMALS, ), config=DCC_GRAPH_CONFIG, # TODO: Revisit @@ -368,6 +370,7 @@ def create_map_plot(): outcome=DEFAULT_QUESTION["outcome"], colormap_range_padding=MAP_LAYOUT["colormap_range_padding"], margins=MAP_LAYOUT["margin"], + decimals=NUM_DECIMALS, # opinion_colormap=OPINION_COLORMAP, ), # vh = % of viewport height @@ -443,6 +446,7 @@ def create_bar_plots_for_question(question_id: str, subquestion_id: str): state=None, stratify=False, threshold=DEFAULT_QUESTION["outcome"], + decimals=NUM_DECIMALS, ), config=DCC_GRAPH_CONFIG, ), @@ -470,6 +474,7 @@ def create_selected_question_bar_plot(): state=None, stratify=False, threshold=DEFAULT_QUESTION["outcome"], + decimals=NUM_DECIMALS, fig_kw=SINGLE_SUBQUESTION_FIG_KW, ), config=DCC_GRAPH_CONFIG, diff --git a/climate_emotions_map/make_descriptive_plots.py b/climate_emotions_map/make_descriptive_plots.py index e05b080..f455e41 100755 --- a/climate_emotions_map/make_descriptive_plots.py +++ b/climate_emotions_map/make_descriptive_plots.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from functools import partial from textwrap import wrap -from typing import Optional import numpy as np import pandas as pd @@ -138,8 +137,6 @@ Q2_LABEL: (11, 1), } -DECIMALS = 0 - def get_categories_dict(df: pd.DataFrame) -> dict: """ @@ -179,8 +176,9 @@ def get_category_to_display(category: str, demographic_variable: str): def make_descriptive_plot_traces( df: pd.DataFrame, demographic_variable: str, - marker_color=None, - reverse=True, + marker_color: str | None = None, + reverse: bool = True, + decimals: int = 1, ) -> go.Bar: """ Make a single plot for a descriptive demographic variable. @@ -192,6 +190,8 @@ def make_descriptive_plot_traces( and "percentage". demographic_variable : str Demographic variable to plot. + decimals : int, optional + Number of decimal places to display, by default 1 """ # subset the data df: pd.DataFrame = df.loc[ @@ -233,7 +233,7 @@ def make_descriptive_plot_traces( # for n, percentage in zip(df[COL_N], df[COL_PERCENTAGE]) # ], hovertemplate=( - f"%{{customdata[1]}}: %{{x:.{DECIMALS}f}}% (%{{customdata[0]}})" + f"%{{customdata[1]}}: %{{x:.{decimals}f}}% (%{{customdata[0]}})" "" ), marker_color=marker_color, @@ -259,7 +259,7 @@ def wrap_text_label(text: str, width: int) -> pd.DataFrame: def make_impact_plot_traces( - df: pd.DataFrame, marker_color=None, text_wrap_width=10 + df: pd.DataFrame, marker_color=None, text_wrap_width=10, decimals=1 ): data_impact = df.loc[ df[COL_DEMOGRAPHIC_VARIABLE].isin(IMPACT_VARIABLES) @@ -290,7 +290,7 @@ def make_impact_plot_traces( customdata=list(zip(x, data_category[COL_N])), hovertemplate=( "%{customdata[0]}" - f": %{{y:.{DECIMALS}f}}% (%{{customdata[1]}})" + f": %{{y:.{decimals}f}}% (%{{customdata[1]}})" "" ), marker_color=marker_color, @@ -303,9 +303,10 @@ def make_impact_plot_traces( def make_descriptive_plots( state: str | None = None, - margins: Optional[dict] = None, - text_wrap_width=14, - colors: list[str] = None, + margins: dict | None = None, + text_wrap_width: int = 14, + colors: list[str] | None = None, + decimals: int = 1, ) -> go.Figure: """Make the sample descriptive plots @@ -319,6 +320,8 @@ def make_descriptive_plots( Maximum width for wrapping some text labels, by default 14 colors : list[str], optional List of colors for the bar plots, by default None (uses the turbo colorscale) + decimals : int, optional + Number of decimal places to display, by default 1 Returns ------- @@ -363,11 +366,18 @@ def make_descriptive_plots( if demographic_variable == IMPACTS_LABEL: traces = make_impact_plot_traces( - data, text_wrap_width=text_wrap_width, marker_color=color + data, + text_wrap_width=text_wrap_width, + marker_color=color, + decimals=decimals, ) else: traces = make_descriptive_plot_traces( - data, demographic_variable, reverse=True, marker_color=color + data, + demographic_variable, + reverse=True, + marker_color=color, + decimals=decimals, ) for trace in traces: diff --git a/climate_emotions_map/make_map.py b/climate_emotions_map/make_map.py index dcbbfc7..1d6d3f0 100644 --- a/climate_emotions_map/make_map.py +++ b/climate_emotions_map/make_map.py @@ -64,7 +64,7 @@ def make_map( impact_marker_size_scale: float = 1.0, colormap_range_padding: int = 10, margins: dict = None, - decimals: int = 0, + decimals: int = 1, ) -> go.Figure: """Generate choropleth map showing opinion and/or impact data. @@ -97,7 +97,7 @@ def make_map( margins : dict | None, optional Margins for the Plotly figure, by default 30 everywhere decimals : int, optional - Number of decimals to show in the hoverbox, by default 0 + Number of decimals to show in the hoverbox, by default 1 Returns ------- diff --git a/climate_emotions_map/make_stacked_bar_plots.py b/climate_emotions_map/make_stacked_bar_plots.py index 00aee62..9794a54 100644 --- a/climate_emotions_map/make_stacked_bar_plots.py +++ b/climate_emotions_map/make_stacked_bar_plots.py @@ -135,7 +135,7 @@ def plot_bars( y="question", color="outcome", title=None, # TODO: remove this argument? - round_to=2, # NOTE: This is the number of decimal places to round the data to, BEFORE multiplying by 100. + decimals=1, sort_order="descending", facet_order=None, palette=None, @@ -145,11 +145,7 @@ def plot_bars( """Make a stacked bar plot of the opinions of the whole sample, split by state and party.""" facet_var = "sub_question" - # Determine the appropriate number of decimal places to use after converting data - # to percentages based on the applied rounding, to use in hover text - decimals = max(0, round_to - 2) - - plot_df[x] = plot_df[x].round(round_to) * 100 + plot_df[x] = plot_df[x] * 100 # sort by subquestion @@ -331,6 +327,7 @@ def make_stacked_bar( state: str | None = None, stratify: bool = False, threshold: str | None = None, + decimals: int = 1, palettes: dict = None, fig_kw: dict = None, ) -> px.bar: @@ -350,6 +347,8 @@ def make_stacked_bar( Whether to stratify the data by party. The default is False. threshold : str, optional The outcome ID for the Likert endorsement level to threshold at (e.g. "3+"). The default is None. + decimals : int, optional + The number of decimal places to display for the percentage values. The default is 1. palettes : dict, optional A dictionary of color palettes for different numbers of outcomes. The default is None. fig_kw : dict, optional @@ -449,6 +448,7 @@ def make_stacked_bar( y=y, facet_order=facet_order, sort_order=sort_order, + decimals=decimals, palette=palette, fig_kw=fig_kw, ) diff --git a/climate_emotions_map/utility.py b/climate_emotions_map/utility.py index df2f236..2a0c482 100644 --- a/climate_emotions_map/utility.py +++ b/climate_emotions_map/utility.py @@ -17,6 +17,8 @@ "all_questions": "Select a survey domain to view responses for", "demographics": "Sample Characteristics", } +# Number of decimal places to round to in all plots +NUM_DECIMALS = 1 # We have not yet decided on the best colormaps to use # OPINION_COLORMAP = "OrRd"