diff --git a/README.rst b/README.rst index c03886b..a87601f 100644 --- a/README.rst +++ b/README.rst @@ -35,15 +35,15 @@ Sensitivity and Epsilon Analysis * Sensitivity : In a single time stamp, ``1`` merchant can come only once in a particular zip code but can appear in upto ``3`` zip codes. So, if we wanted to release measures about a single zip code sensitivity would be ``1`` but since we want to release data for all zip codes, the sensitivity used for each zip code is ``3``. * Scaling with Time: For multiple time stamps, sensitivity is ``3 * no_of_time_stamps``. * Epsilon Budget: The epsilon spent for each query is ``∈``. -* Scale Calculation: ``Scale = (sqrt(3) * no_of_time_stamps) / ∈``. +* Scale Calculation: ``Scale = (3 * no_of_time_stamps* upper_bound) / ∈``. -Mobility Detection (Airline Merch Category) -------------------------------------------- +Mobility Detection +------------------ Description -This analysis tracks mobility by monitoring differential private time series release of financial transactions in the "Airlines" category, which reflects the transportation sector. +This analysis tracks mobility by monitoring differential private time series release of financial transactions in the ``retail_and_recreation``, ``grocery_and_pharmacy`` and ``transit_stations`` super categories which matches with google mobility data for easy validation. Assumptions @@ -54,17 +54,18 @@ Assumptions Algorithm #. Add City Column: A new ``city`` column is added based on postal codes (``make_preprocess_location``). +#. Add Super Category Column : A new ``merch_super_category`` column is added for classifying transactions into retail_and_recreation, grocery_and_pharmacy and transit_stations categories (``make_preprocess_merchant_mobility``). #. Filter for City: Data for the selected city is filtered (``make_filter``). -#. Filter for Airline Category: Only transactions in the ``Airline`` category are considered (``make_filter``). +#. Filter for super category: data is filtered for retail_and_recreation, grocery_and_pharmacy and transit_stations categories (``make_filter``). #. Filter by Time Frame: Data is filtered for the selected time frame (``make_truncate_time``). #. Transaction Summing & Noise Addition: Sum the number of transactions by postal code for each timestep and add Gaussian noise (``make_private_sum_by``). Sensitivity and Epsilon Analysis -* Sensitivity per Merchant: Sensitivity is 3 for each merchant in the ``Airline`` category. +* Sensitivity per Merchant: Sensitivity is 3 for each merchant. * Scaling with Time: For multiple timesteps, sensitivity is ``3 * no_of_time_steps``. * Epsilon Budget: The epsilon spent per timestep is ∈ . -* Scale Calculation: ``Scale = (3 * no_of_time_steps) / ∈``. +* Scale Calculation: ``Scale = (3 * no_of_time_steps* upper_bound) / ∈``. Validation @@ -100,7 +101,7 @@ Sensitivity and Epsilon Analysis * Sensitivity per Category : Sensitivity is ``3`` for each category (essential or luxurious goods). * Scaling with Time : For multiple timesteps, sensitivity is ``3 * no_of_time_steps``. * Epsilon Budget : The epsilon spent per timestep is ∈. -* Scale Calculation : ``Scale = (3 * no_of_time_steps) / ∈``. +* Scale Calculation : ``Scale = (3 * no_of_time_steps* upper_bound) / ∈``. diff --git a/dist/dp_epidemiology-0.0.8-py3-none-any.whl b/dist/dp_epidemiology-0.0.8-py3-none-any.whl deleted file mode 100644 index 70fa40f..0000000 Binary files a/dist/dp_epidemiology-0.0.8-py3-none-any.whl and /dev/null differ diff --git a/dist/dp_epidemiology-0.0.8.tar.gz b/dist/dp_epidemiology-0.0.8.tar.gz deleted file mode 100644 index 11e66c3..0000000 Binary files a/dist/dp_epidemiology-0.0.8.tar.gz and /dev/null differ diff --git a/dist/dp_epidemiology-0.0.9-py3-none-any.whl b/dist/dp_epidemiology-0.0.9-py3-none-any.whl new file mode 100644 index 0000000..f58ac60 Binary files /dev/null and b/dist/dp_epidemiology-0.0.9-py3-none-any.whl differ diff --git a/dist/dp_epidemiology-0.0.9.tar.gz b/dist/dp_epidemiology-0.0.9.tar.gz new file mode 100644 index 0000000..03eb266 Binary files /dev/null and b/dist/dp_epidemiology-0.0.9.tar.gz differ diff --git a/docs/requirements.txt b/docs/requirements.txt index e69de29..ffba590 100644 Binary files a/docs/requirements.txt and b/docs/requirements.txt differ diff --git a/docs/usage.rst b/docs/usage.rst index d6cf342..46413c6 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -61,13 +61,14 @@ For example: To do mobility inference, -you can use the ``mobility_analyzer.mobility_analyzer()`` function to generate differential private time series of trnsactional data in the "Airlines" category: +you can use the ``mobility_analyzer.mobility_analyzer()`` function to generate differential private time series of trnsactional data in the ``retail_and_recreation``, ``grocery_and_pharmacy`` and ``transit_stations`` super categories: .. autofunction:: mobility_analyzer.mobility_analyzer The ``df`` parameter take pandas dataframe as input with columns ``[ "ID", "date", "merch_category", "merch_postal_code", "transaction_type", "spendamt", "nb_transactions"]``. The ``start_date`` and ``end_date`` parameters take the start and end date of the time frame for which the analysis is to be done. The ``city`` parameter takes the name of the city for which the analysis is to be done. +The ``category`` parameter takes the value of ``retail_and_recreation``, ``grocery_and_pharmacy`` or ``transit_stations`` for which the analysis is to be done. The ``epsilon`` parameter takes the value of epsilon for differential privacy. For example: @@ -75,7 +76,7 @@ For example: >>> from DP_epidemiology import mobility_analyzer >>> from datetime import datetime >>> df = pd.read_csv('data.csv') ->>> mobility_analyzer.mobility_analyzer(df,datetime(2020, 9, 1),datetime(2021, 3, 31),"Medellin",10) +>>> mobility_analyzer.mobility_analyzer(df,datetime(2020, 9, 1),datetime(2021, 3, 31),"Medellin","retail_and_recreation",10) nb_transactions date 0 1258 2020-09-01 1 1328 2020-09-08 diff --git a/pyproject.toml b/pyproject.toml index d052481..e100188 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "DP_epidemiology" -version = "0.0.8" +version = "0.0.9" dependencies = [ "pandas>=2.1.4", @@ -16,7 +16,8 @@ dependencies = [ "dash", "nbformat", "scipy", - "matplotlib" + "matplotlib", + "dtw", ] authors = [ diff --git a/src/DP_epidemiology/__pycache__/contact_matrix.cpython-310.pyc b/src/DP_epidemiology/__pycache__/contact_matrix.cpython-310.pyc index 2bf2272..5b18607 100644 Binary files a/src/DP_epidemiology/__pycache__/contact_matrix.cpython-310.pyc and b/src/DP_epidemiology/__pycache__/contact_matrix.cpython-310.pyc differ diff --git a/src/DP_epidemiology/__pycache__/hotspot_analyzer.cpython-310.pyc b/src/DP_epidemiology/__pycache__/hotspot_analyzer.cpython-310.pyc index e4e7260..1037b28 100644 Binary files a/src/DP_epidemiology/__pycache__/hotspot_analyzer.cpython-310.pyc and b/src/DP_epidemiology/__pycache__/hotspot_analyzer.cpython-310.pyc differ diff --git a/src/DP_epidemiology/__pycache__/mobility_analyzer.cpython-310.pyc b/src/DP_epidemiology/__pycache__/mobility_analyzer.cpython-310.pyc index cab8470..06fa566 100644 Binary files a/src/DP_epidemiology/__pycache__/mobility_analyzer.cpython-310.pyc and b/src/DP_epidemiology/__pycache__/mobility_analyzer.cpython-310.pyc differ diff --git a/src/DP_epidemiology/__pycache__/pandemic_adherence_analyzer.cpython-310.pyc b/src/DP_epidemiology/__pycache__/pandemic_adherence_analyzer.cpython-310.pyc index 7a71a7e..354cf23 100644 Binary files a/src/DP_epidemiology/__pycache__/pandemic_adherence_analyzer.cpython-310.pyc and b/src/DP_epidemiology/__pycache__/pandemic_adherence_analyzer.cpython-310.pyc differ diff --git a/src/DP_epidemiology/__pycache__/utilities.cpython-310.pyc b/src/DP_epidemiology/__pycache__/utilities.cpython-310.pyc index 651b5c4..182b321 100644 Binary files a/src/DP_epidemiology/__pycache__/utilities.cpython-310.pyc and b/src/DP_epidemiology/__pycache__/utilities.cpython-310.pyc differ diff --git a/src/DP_epidemiology/hotspot_analyzer.py b/src/DP_epidemiology/hotspot_analyzer.py index 45a702c..4804d76 100644 --- a/src/DP_epidemiology/hotspot_analyzer.py +++ b/src/DP_epidemiology/hotspot_analyzer.py @@ -25,7 +25,7 @@ def hotspot_analyzer(df:pd.DataFrame, start_date:datetime,end_date:datetime,city nb_timesteps = (end_date - start_date).days // 7 """scale calculation""" - scale=(np.sqrt(3.0)*nb_timesteps*upper_bound)/epsilon + scale=(3.0*nb_timesteps*upper_bound)/epsilon new_df=df.copy() diff --git a/src/DP_epidemiology/mobility_analyzer.py b/src/DP_epidemiology/mobility_analyzer.py index 7ca1cd2..e59144a 100644 --- a/src/DP_epidemiology/mobility_analyzer.py +++ b/src/DP_epidemiology/mobility_analyzer.py @@ -5,6 +5,8 @@ from datetime import datetime import scipy.stats as stats import opendp.prelude as dp +import matplotlib.pyplot as plt +from dtw import dtw,accelerated_dtw dp.enable_features("contrib", "floating-point", "honest-but-curious") @@ -28,7 +30,7 @@ def mobility_analyzer_airline(df:pd.DataFrame,start_date:datetime,end_date:datet nb_timesteps = (end_date - start_date).days // 7 """scale calculation""" - scale=(np.sqrt(3.0)*nb_timesteps*upper_bound)/epsilon + scale=(3.0*nb_timesteps*upper_bound)/epsilon new_df=df.copy() @@ -60,7 +62,7 @@ def mobility_analyzer(df:pd.DataFrame,start_date:datetime,end_date:datetime,city nb_timesteps = (end_date - start_date).days // 7 """scale calculation""" - scale=(np.sqrt(3.0)*nb_timesteps*upper_bound)/epsilon + scale=(3.0*nb_timesteps*upper_bound)/epsilon new_df=df.copy() @@ -85,4 +87,15 @@ def mobility_validation_with_google_mobility(df_transactional_data:pd.DataFrame, # print(df_transactional_mobility.head()) # print(df_google_mobility.head()) r, p = stats.pearsonr(df_transactional_mobility['nb_transactions'][:length], df_google_mobility[category][:length]) - print(f"Scipy computed Pearson r: {r} and p-value: {p}") \ No newline at end of file + print(f"Scipy computed Pearson r: {r} and p-value: {p}") + + d1 = df_transactional_mobility['nb_transactions'][:length].interpolate().values + d2 = df_google_mobility[category][:length].interpolate().values + d, cost_matrix, acc_cost_matrix, path = accelerated_dtw(d1,d2, dist='euclidean') + + plt.imshow(acc_cost_matrix.T, origin='lower', cmap='gray', interpolation='nearest') + plt.plot(path[0], path[1], 'w') + plt.xlabel('Subject1') + plt.ylabel('Subject2') + plt.title(f'DTW Minimum Path with minimum distance: {np.round(d,2)}') + plt.show() \ No newline at end of file diff --git a/src/DP_epidemiology/pandemic_adherence_analyzer.py b/src/DP_epidemiology/pandemic_adherence_analyzer.py index 75e966c..64507c0 100644 --- a/src/DP_epidemiology/pandemic_adherence_analyzer.py +++ b/src/DP_epidemiology/pandemic_adherence_analyzer.py @@ -26,7 +26,7 @@ def pandemic_adherence_analyzer(df:pd.DataFrame,start_date:datetime,end_date:dat nb_timesteps = (end_date - start_date).days // 7 """scale calculation""" - scale=(np.sqrt(3.0)*nb_timesteps*upper_bound)/epsilon + scale=(3.0*nb_timesteps*upper_bound)/epsilon new_df=df.copy() diff --git a/src/DP_epidemiology/utilities.py b/src/DP_epidemiology/utilities.py index 99555c4..3c663c7 100644 --- a/src/DP_epidemiology/utilities.py +++ b/src/DP_epidemiology/utilities.py @@ -118,15 +118,15 @@ def function(df): def make_private_sum_by(column, by, bounds, scale): """Create a measurement that computes the grouped bounded sum of `column`""" - space = dp.vector_domain(dp.atom_domain(T=int)), dp.l2_distance(T=float) - m_gauss = space >> dp.m.then_gaussian(scale) + space = dp.vector_domain(dp.atom_domain(T=int)), dp.l1_distance(T=int) + m_lap = space >> dp.m.then_laplace(scale) t_sum = make_sum_by(column, by, bounds) def function(df): exact = t_sum(df) # print(exact) noisy_sum = pd.Series( - np.maximum(m_gauss(exact.to_numpy().flatten()), 0), + np.maximum(m_lap(exact.to_numpy().flatten()), 0), ) # print(noisy_sum) noisy_sum=noisy_sum.to_frame(name=column) @@ -138,7 +138,7 @@ def function(df): input_metric=dp.symmetric_distance(), output_measure=dp.zero_concentrated_divergence(T=float), function=function, - privacy_map=lambda d_in: m_gauss.map(t_sum.map(d_in)), + privacy_map=lambda d_in: m_lap.map(t_sum.map(d_in)), ) def make_filter(column,entry): diff --git a/src/DP_epidemiology/viz.py b/src/DP_epidemiology/viz.py index 8369230..4e62d24 100644 --- a/src/DP_epidemiology/viz.py +++ b/src/DP_epidemiology/viz.py @@ -96,60 +96,62 @@ def update_graph(start_date, end_date, epsilon, city): return app -def create_mobility_dash_app(df:pd.DataFrame): +def create_mobility_dash_app(df: pd.DataFrame): cities = { "Medellin": (6.2476, -75.5658), "Bogota": (4.7110, -74.0721), "Brasilia": (-15.7975, -47.8919), "Santiago": (-33.4489, -70.6693) - } + } + app = dash.Dash(__name__) - category_list = ['grocery_and_pharmacy', 'transit_stations', 'retail_and_recreation',"other"] + category_list = ['grocery_and_pharmacy', 'transit_stations', 'retail_and_recreation', "other"] + app.layout = html.Div([ - dcc.DatePickerSingle( - id='start-date-picker', - date='2019-01-01' - ), - dcc.DatePickerSingle( - id='end-date-picker', - date='2019-12-31' - ), - dcc.Slider( - id='epsilon-slider', - min=0, - max=10, - step=0.1, - value=1, - marks={i: str(i) for i in range(11)} - ), - dcc.Dropdown( - id='city-dropdown', - options=[{'label': city, 'value': city} for city in cities.keys()], - value='Medellin' - ), - dcc.Dropdown( - id='category-list-dropdown', - options=[{'label': category, 'value': category} for category in category_list], - value='transit_stations' - ), - dcc.Graph(id='mobility-graph') - ]) + dcc.DatePickerSingle( + id='start-date-picker', + date='2019-01-01' + ), + dcc.DatePickerSingle( + id='end-date-picker', + date='2019-12-31' + ), + dcc.Slider( + id='epsilon-slider', + min=0, + max=10, + step=0.1, + value=1, + marks={i: str(i) for i in range(11)} + ), + dcc.Dropdown( + id='city-dropdown', + options=[{'label': city, 'value': city} for city in cities.keys()], + value='Medellin' + ), + dcc.Dropdown( + id='category-list-dropdown', + options=[{'label': category, 'value': category} for category in category_list], + value='transit_stations' + ), + dcc.Graph(id='mobility-graph') + ]) # Callback to update the graph based on input values @app.callback( Output('mobility-graph', 'figure'), [Input('start-date-picker', 'date'), - Input('end-date-picker', 'date'), - Input('city-dropdown', 'value'), - Input('category-list-dropdown', 'value'), - Input('epsilon-slider', 'value')] + Input('end-date-picker', 'date'), + Input('city-dropdown', 'value'), + Input('category-list-dropdown', 'value'), + Input('epsilon-slider', 'value')] ) - def update_graph(start_date, end_date, city_filter,category, epsilon): + def update_graph(start_date, end_date, city_filter, category, epsilon): # Convert date strings to datetime objects start_date = datetime.strptime(start_date, '%Y-%m-%d') end_date = datetime.strptime(end_date, '%Y-%m-%d') - # Call the mobility_analyser function + # Call the mobility_analyzer function filtered_df = mobility_analyzer(df, start_date, end_date, city_filter, category, epsilon) # Plot using Plotly Express @@ -161,76 +163,186 @@ def update_graph(start_date, end_date, city_filter,category, epsilon): labels={'nb_transactions': 'Number of Transactions', 'date': 'Date'} ) + # Add events for Bogotá + if city_filter == "Bogota": + events = [ + ("Isolation Start Drill", "2020-03-20"), + ("National Quarantine", "2020-03-26"), + ("Gender Restriction", "2020-04-16"), + ("Day Without VAT (IVA)", "2020-06-19"), + ("Lockdown 1", "2020-07-15"), + ("Lockdown 2", "2020-07-30"), + ("Lockdown 3", "2020-08-13"), + ("Lockdown 4", "2020-08-20"), + ("End of National Quarantine", "2020-09-04"), + ("Day Without VAT", "2020-11-19"), + ("Candle Day", "2020-12-07"), + ("Start of Novenas", "2020-12-16"), + ("Lockdown 1 (2021)", "2021-01-05"), + ("Lockdown 2 (2021)", "2021-01-12"), + ("Lockdown 3 (2021)", "2021-01-18"), + ("Lockdown 4 (2021)", "2021-01-28"), + ("Holy Week", "2021-03-28"), + ("Model 4x3", "2021-04-06"), + ("Model 4x3 (Extension)", "2021-04-06"), + ("Vaccination Stage 1", "2021-02-18"), + ("Vaccination Stage 2", "2021-03-08"), + ("Vaccination Stage 3", "2021-05-22"), + ("Vaccination Stage 4", "2021-06-17"), + ("Vaccination Stage 5", "2021-07-17"), + ("Riots and Social Unrest", "2021-05-01") + ] + + for event, date in events: + fig.add_shape( + type="line", + x0=date, + y0=0, + x1=date, + y1=1, + xref='x', + yref='paper', + line=dict(color="Red", width=2, dash="dash") + ) + fig.add_annotation( + x=date, + y=1, + xref='x', + yref='paper', + text=event, + showarrow=True, + arrowhead=1, + ax=-10, + ay=-40, + font=dict(color="Red") + ) + return fig + return app -def create_pandemic_adherence_dash_app(df:pd.DataFrame): +def create_pandemic_adherence_dash_app(df: pd.DataFrame): cities = { "Medellin": (6.2476, -75.5658), "Bogota": (4.7110, -74.0721), "Brasilia": (-15.7975, -47.8919), "Santiago": (-33.4489, -70.6693) - } - entry_types=["luxury","essential","other"] + } + entry_types = ["luxury", "essential", "other"] app = dash.Dash(__name__) - + app.layout = html.Div([ - dcc.DatePickerSingle( - id='start-date-picker', - date='2019-01-01' - ), - dcc.DatePickerSingle( - id='end-date-picker', - date='2019-12-31' - ), - dcc.Slider( - id='epsilon-slider', - min=0, - max=10, - step=0.1, - value=1, - marks={i: str(i) for i in range(11)} - ), - dcc.Dropdown( - id='city-dropdown', - options=[{'label': city, 'value': city} for city in cities.keys()], - value='Medellin' - ), - dcc.Dropdown( - id='entry-type-dropdown', - options=[{'label': entry_type, 'value': entry_type} for entry_type in entry_types], - value='luxury' - ), - dcc.Graph(id='pandemic-adherence-graph') - ]) + dcc.DatePickerSingle( + id='start-date-picker', + date='2019-01-01' + ), + dcc.DatePickerSingle( + id='end-date-picker', + date='2019-12-31' + ), + dcc.Slider( + id='epsilon-slider', + min=0, + max=10, + step=0.1, + value=1, + marks={i: str(i) for i in range(11)} + ), + dcc.Dropdown( + id='city-dropdown', + options=[{'label': city, 'value': city} for city in cities.keys()], + value='Medellin' + ), + dcc.Dropdown( + id='entry-type-dropdown', + options=[{'label': entry_type, 'value': entry_type} for entry_type in entry_types], + value='luxury' + ), + dcc.Graph(id='pandemic-adherence-graph') + ]) # Callback to update the graph based on input values @app.callback( Output('pandemic-adherence-graph', 'figure'), [Input('start-date-picker', 'date'), - Input('end-date-picker', 'date'), - Input('city-dropdown', 'value'), - Input('entry-type-dropdown', 'value'), - Input('epsilon-slider', 'value')] + Input('end-date-picker', 'date'), + Input('city-dropdown', 'value'), + Input('entry-type-dropdown', 'value'), + Input('epsilon-slider', 'value')] ) - def update_graph(start_date, end_date, city_filter,essential_or_luxury, epsilon): + def update_graph(start_date, end_date, city_filter, essential_or_luxury, epsilon): # Convert date strings to datetime objects start_date = datetime.strptime(start_date, '%Y-%m-%d') end_date = datetime.strptime(end_date, '%Y-%m-%d') - # Call the mobility_analyser function - filtered_df = pandemic_adherence_analyzer(df, start_date, end_date, city_filter,essential_or_luxury, epsilon) + # Call the pandemic_adherence_analyzer function + filtered_df = pandemic_adherence_analyzer(df, start_date, end_date, city_filter, essential_or_luxury, epsilon) # Plot using Plotly Express fig = px.line( filtered_df, x='date', y='nb_transactions', - title=f"Pandemic Stage Analysis for {city_filter} from {start_date.date()} to {end_date.date()} with epsilon={epsilon}", + title=f"Pandemic adherence Analysis for {city_filter} from {start_date.date()} to {end_date.date()} with epsilon={epsilon}", labels={'nb_transactions': 'Number of Transactions', 'date': 'Date'} ) + # Add events for Bogotá + if city_filter == "Bogota": + events = [ + ("Isolation Start Drill", "2020-03-20"), + ("National Quarantine", "2020-03-26"), + ("Gender Restriction", "2020-04-16"), + ("Day Without VAT (IVA)", "2020-06-19"), + ("Lockdown 1", "2020-07-15"), + ("Lockdown 2", "2020-07-30"), + ("Lockdown 3", "2020-08-13"), + ("Lockdown 4", "2020-08-20"), + ("End of National Quarantine", "2020-09-04"), + ("Day Without VAT", "2020-11-19"), + ("Candle Day", "2020-12-07"), + ("Start of Novenas", "2020-12-16"), + ("Lockdown 1 (2021)", "2021-01-05"), + ("Lockdown 2 (2021)", "2021-01-12"), + ("Lockdown 3 (2021)", "2021-01-18"), + ("Lockdown 4 (2021)", "2021-01-28"), + ("Holy Week", "2021-03-28"), + ("Model 4x3", "2021-04-06"), + ("Model 4x3 (Extension)", "2021-04-06"), + ("Vaccination Stage 1", "2021-02-18"), + ("Vaccination Stage 2", "2021-03-08"), + ("Vaccination Stage 3", "2021-05-22"), + ("Vaccination Stage 4", "2021-06-17"), + ("Vaccination Stage 5", "2021-07-17"), + ("Riots and Social Unrest", "2021-05-01") + ] + + for event, date in events: + fig.add_shape( + type="line", + x0=date, + y0=0, + x1=date, + y1=1, + xref='x', + yref='paper', + line=dict(color="Red", width=2, dash="dash") + ) + fig.add_annotation( + x=date, + y=1, + xref='x', + yref='paper', + text=event, + showarrow=True, + arrowhead=1, + ax=-10, + ay=-40, + font=dict(color="Red") + ) + return fig + return app def create_contact_matrix_dash_app(df:pd.DataFrame): @@ -375,7 +487,7 @@ def update_graph(start_date, end_date, city_filter, category, epsilon): offset = filtered_df_transactional["date"].iloc[0] filtered_df_google = preprocess_google_mobility(df_google_mobility_data, start_date, end_date, city_filter, category, offset) - # Create the plot + # Create the plot with two y-axes fig = go.Figure() # Add transactional mobility data @@ -383,7 +495,8 @@ def update_graph(start_date, end_date, city_filter, category, epsilon): x=filtered_df_transactional['date'], y=filtered_df_transactional['nb_transactions'], mode='lines', - name='Transactional Mobility' + name='Transactional Mobility', + yaxis='y1' )) # Add Google mobility data @@ -391,15 +504,14 @@ def update_graph(start_date, end_date, city_filter, category, epsilon): x=filtered_df_google['date'], y=filtered_df_google[category], mode='lines', - name='Google Mobility' + name='Google Mobility', + yaxis='y2' )) - # Update layout + # Update layout for two y-axes fig.update_layout( title=f"Mobility Analysis for {city_filter} and category {category} from {start_date.date()} to {end_date.date()} with epsilon={epsilon}", xaxis_title='Date', - # yaxis_title='Mobility Change', - # legend_title='Data Source' yaxis=dict( title='Transactional Mobility', titlefont=dict(color='blue'), diff --git a/tests/test_viz.ipynb b/tests/test_viz.ipynb index 3e3d84a..60fe32d 100644 --- a/tests/test_viz.ipynb +++ b/tests/test_viz.ipynb @@ -28,21 +28,261 @@ "outputs": [], "source": [ "path = \"C:\\\\Users\\kshub\\\\OneDrive\\\\Documents\\\\PET_phase_2\\\\Technical_Phase_Data\\\\technical_phase_data.csv\"\n", - "df_tran = pd.read_csv(path)\n", - "df_mobility = pd.read_csv(\"C:\\\\Users\\\\kshub\\\\OneDrive\\\\Documents\\\\PET_phase_2\\\\Global_Mobility_Report (1).csv\", low_memory=False)\n" + "df_tran = pd.read_csv(path)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
country_region_codecountry_regionsub_region_1sub_region_2metro_areaiso_3166_2_codecensus_fips_codeplace_iddateretail_and_recreation_percent_change_from_baselinegrocery_and_pharmacy_percent_change_from_baselineparks_percent_change_from_baselinetransit_stations_percent_change_from_baselineworkplaces_percent_change_from_baselineresidential_percent_change_from_baseline
0AEUnited Arab EmiratesNaNNaNNaNNaNNaNChIJvRKrsd9IXj4RpwoIwFYv0zM2020-02-150.04.05.00.02.01.0
1AEUnited Arab EmiratesNaNNaNNaNNaNNaNChIJvRKrsd9IXj4RpwoIwFYv0zM2020-02-161.04.04.01.02.01.0
2AEUnited Arab EmiratesNaNNaNNaNNaNNaNChIJvRKrsd9IXj4RpwoIwFYv0zM2020-02-17-1.01.05.01.02.01.0
3AEUnited Arab EmiratesNaNNaNNaNNaNNaNChIJvRKrsd9IXj4RpwoIwFYv0zM2020-02-18-2.01.05.00.02.01.0
4AEUnited Arab EmiratesNaNNaNNaNNaNNaNChIJvRKrsd9IXj4RpwoIwFYv0zM2020-02-19-2.00.04.0-1.02.01.0
\n", + "
" + ], + "text/plain": [ + " country_region_code country_region sub_region_1 sub_region_2 \\\n", + "0 AE United Arab Emirates NaN NaN \n", + "1 AE United Arab Emirates NaN NaN \n", + "2 AE United Arab Emirates NaN NaN \n", + "3 AE United Arab Emirates NaN NaN \n", + "4 AE United Arab Emirates NaN NaN \n", + "\n", + " metro_area iso_3166_2_code census_fips_code place_id \\\n", + "0 NaN NaN NaN ChIJvRKrsd9IXj4RpwoIwFYv0zM \n", + "1 NaN NaN NaN ChIJvRKrsd9IXj4RpwoIwFYv0zM \n", + "2 NaN NaN NaN ChIJvRKrsd9IXj4RpwoIwFYv0zM \n", + "3 NaN NaN NaN ChIJvRKrsd9IXj4RpwoIwFYv0zM \n", + "4 NaN NaN NaN ChIJvRKrsd9IXj4RpwoIwFYv0zM \n", + "\n", + " date retail_and_recreation_percent_change_from_baseline \\\n", + "0 2020-02-15 0.0 \n", + "1 2020-02-16 1.0 \n", + "2 2020-02-17 -1.0 \n", + "3 2020-02-18 -2.0 \n", + "4 2020-02-19 -2.0 \n", + "\n", + " grocery_and_pharmacy_percent_change_from_baseline \\\n", + "0 4.0 \n", + "1 4.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 0.0 \n", + "\n", + " parks_percent_change_from_baseline \\\n", + "0 5.0 \n", + "1 4.0 \n", + "2 5.0 \n", + "3 5.0 \n", + "4 4.0 \n", + "\n", + " transit_stations_percent_change_from_baseline \\\n", + "0 0.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 0.0 \n", + "4 -1.0 \n", + "\n", + " workplaces_percent_change_from_baseline \\\n", + "0 2.0 \n", + "1 2.0 \n", + "2 2.0 \n", + "3 2.0 \n", + "4 2.0 \n", + "\n", + " residential_percent_change_from_baseline \n", + "0 1.0 \n", + "1 1.0 \n", + "2 1.0 \n", + "3 1.0 \n", + "4 1.0 " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "# Define the path to the CSV file\n", + "file_path = \"C:\\\\Users\\\\kshub\\\\OneDrive\\\\Documents\\\\PET_phase_2\\\\Global_Mobility_Report (1).csv\"\n", + "\n", + "# Initialize an empty list to store the chunks\n", + "chunks = []\n", + "\n", + "# Read the CSV file in chunks\n", + "chunk_size = 10000 # Adjust the chunk size as needed\n", + "for chunk in pd.read_csv(file_path, chunksize=chunk_size, low_memory=False):\n", + " chunks.append(chunk)\n", + "\n", + "# Concatenate the chunks into a single DataFrame\n", + "df_mobility = pd.concat(chunks, ignore_index=True)\n", + "\n", + "# Display the first few rows of the DataFrame\n", + "df_mobility.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "df_mobility = pd.read_csv(\"C:\\\\Users\\\\kshub\\\\OneDrive\\\\Documents\\\\PET_phase_2\\\\Global_Mobility_Report (1).csv\", low_memory=False)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Scipy computed Pearson r: 0.3056463348470299 and p-value: 0.03886009367628722\n" + "Scipy computed Pearson r: 0.2726605353538447 and p-value: 0.06675963402694846\n" ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ @@ -51,7 +291,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -69,7 +309,7 @@ " " ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -83,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -101,21 +341,378 @@ " " ], "text/plain": [ - "" + "" ] }, "metadata": {}, "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---------------------------------------------------------------------------\n", + "ValueError Traceback (most recent call last)\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\PETs_for_Public_Health_Challenge\\src\\DP_epidemiology\\viz.py:76, in create_hotspot_dash_app..update_graph(\n", + " start_date=datetime.datetime(2019, 1, 1, 0, 0),\n", + " end_date=datetime.datetime(2019, 12, 31, 0, 0),\n", + " epsilon=1,\n", + " city='Medellin'\n", + ")\n", + " 73 filtered_df = get_coordinates(output)\n", + " 75 # Plot using Plotly Express\n", + "---> 76 fig = px.scatter_geo(\n", + " px = \n", + " filtered_df = nb_transactions merch_postal_code Latitude Longitude\n", + "0 306566 500001 6.389072 -74.596536\n", + "1 296614 500002 5.523995 -76.536749\n", + "2 342304 500003 5.982925 -75.812286\n", + "3 307235 500004 5.130301 -76.138346\n", + "4 237251 500005 5.605763 -74.716468\n", + "5 458127 500006 4.801478 -75.121902\n", + "6 554476 500007 7.180048 -76.071168\n", + "7 373792 500008 7.463546 -74.963595\n", + "8 324664 500009 7.743818 -76.738181\n", + "9 576898 500010 5.648854 -74.132482\n", + "10 273212 500011 6.727315 -76.635165\n", + "11 404836 500012 6.861639 -76.746068\n", + "12 498471 500013 7.362958 -74.297787\n", + "13 445097 500014 6.130727 -75.667267\n", + "14 397807 500015 5.825303 -76.559407\n", + "15 580316 500016 7.165207 -76.975321\n", + "16 421731 500017 6.236910 -74.487897\n", + "17 926698 500020 7.652337 -75.576271\n", + "18 370391 500021 7.236503 -75.530987\n", + "19 777796 500022 6.854339 -75.455203\n", + "20 394755 500023 7.241663 -76.453039\n", + "21 470054 500024 6.091720 -76.950376\n", + "22 438161 500025 7.261668 -77.019802\n", + "23 183703 500026 5.103643 -74.756495\n", + "24 447787 500027 4.874871 -74.121468\n", + "25 462685 500028 6.066869 -75.693614\n", + "26 384548 500030 5.627784 -76.472683\n", + "27 443880 500031 7.509737 -76.784860\n", + "28 350224 500032 6.206165 -74.107333\n", + "29 358644 500033 6.058493 -76.241435\n", + "30 406516 500034 7.417255 -75.579524\n", + "31 292610 500035 7.335878 -74.620644\n", + "32 339361 500036 5.158304 -74.901021\n", + "33 461339 500037 5.490366 -75.888601\n", + "34 334532 500040 7.124754 -75.053544\n", + "35 327973 500041 6.637287 -74.737167\n", + "36 332156 500042 7.137278 -75.044710\n", + "37 518508 500043 7.327858 -75.105685\n", + "38 353982 500044 4.986360 -75.365658\n", + "39 440938 500046 5.015590 -75.221307\n", + "40 497444 500047 5.814341 -75.149734\n", + "41 243727 55411 5.462628 -74.823107\n", + " start_date = datetime.datetime(2019, 1, 1, 0, 0)\n", + " end_date = datetime.datetime(2019, 12, 31, 0, 0)\n", + " city = 'Medellin'\n", + " epsilon = 1\n", + " px.colors.sequential.Plasma = ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921']\n", + " px.colors.sequential = \n", + " px.colors = \n", + " 77 filtered_df,\n", + " 78 lat='Latitude',\n", + " 79 lon='Longitude',\n", + " 80 color='nb_transactions',\n", + " 81 size='nb_transactions',\n", + " 82 hover_name='merch_postal_code',\n", + " 83 hover_data={'merch_postal_code': True, 'nb_transactions': True, 'Latitude': False, 'Longitude': False},\n", + " 84 projection='mercator',\n", + " 85 title=f\"Transaction Locations in {city} from {start_date.date()} to {end_date.date()} with epsilon={epsilon}\",\n", + " 86 color_continuous_scale=px.colors.sequential.Plasma\n", + " 87 )\n", + " 89 # Center the map around the selected city\n", + " 90 fig.update_geos(\n", + " 91 center=dict(lat=cities[city][0], lon=cities[city][1]),\n", + " 92 projection_scale=2.5 # Zoom level\n", + " 93 )\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\express\\_chart_types.py:1148, in scatter_geo(\n", + " data_frame= nb_transactions merch_postal_code Latitude ... 243727 55411 5.462628 -74.823107,\n", + " lat='Latitude',\n", + " lon='Longitude',\n", + " locations=None,\n", + " locationmode=None,\n", + " geojson=None,\n", + " featureidkey=None,\n", + " color='nb_transactions',\n", + " text=None,\n", + " symbol=None,\n", + " facet_row=None,\n", + " facet_col=None,\n", + " facet_col_wrap=0,\n", + " facet_row_spacing=None,\n", + " facet_col_spacing=None,\n", + " hover_name='merch_postal_code',\n", + " hover_data={'Latitude': False, 'Longitude': False, 'merch_postal_code': True, 'nb_transactions': True},\n", + " custom_data=None,\n", + " size='nb_transactions',\n", + " animation_frame=None,\n", + " animation_group=None,\n", + " category_orders=None,\n", + " labels=None,\n", + " color_discrete_sequence=None,\n", + " color_discrete_map=None,\n", + " color_continuous_scale=['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'],\n", + " range_color=None,\n", + " color_continuous_midpoint=None,\n", + " symbol_sequence=None,\n", + " symbol_map=None,\n", + " opacity=None,\n", + " size_max=None,\n", + " projection='mercator',\n", + " scope=None,\n", + " center=None,\n", + " fitbounds=None,\n", + " basemap_visible=None,\n", + " title='Transaction Locations in Medellin from 2019-01-01 to 2019-12-31 with epsilon=1',\n", + " template=None,\n", + " width=None,\n", + " height=None\n", + ")\n", + " 1101 def scatter_geo(\n", + " 1102 data_frame=None,\n", + " 1103 lat=None,\n", + " (...)\n", + " 1142 height=None,\n", + " 1143 ) -> go.Figure:\n", + " 1144 \"\"\"\n", + " 1145 In a geographic scatter plot, each row of `data_frame` is represented\n", + " 1146 by a symbol mark on a map.\n", + " 1147 \"\"\"\n", + "-> 1148 return make_figure(\n", + " go = \n", + " locationmode = None\n", + " 1149 args=locals(),\n", + " 1150 constructor=go.Scattergeo,\n", + " 1151 trace_patch=dict(locationmode=locationmode),\n", + " 1152 )\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\express\\_core.py:2115, in make_figure(\n", + " args={'animation_frame': None, 'animation_group': None, 'basemap_visible': None, 'category_orders': None, 'center': None, 'color': 'nb_transactions', 'color_continuous_midpoint': None, 'color_continuous_scale': ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'], 'color_discrete_map': None, 'color_discrete_sequence': None, ...},\n", + " constructor=,\n", + " trace_patch={'locationmode': None},\n", + " layout_patch={}\n", + ")\n", + " 2113 trace_patch = trace_patch or {}\n", + " 2114 layout_patch = layout_patch or {}\n", + "-> 2115 apply_default_cascade(args)\n", + " args = {'data_frame': nb_transactions merch_postal_code Latitude Longitude\n", + "0 306566 500001 6.389072 -74.596536\n", + "1 296614 500002 5.523995 -76.536749\n", + "2 342304 500003 5.982925 -75.812286\n", + "3 307235 500004 5.130301 -76.138346\n", + "4 237251 500005 5.605763 -74.716468\n", + "5 458127 500006 4.801478 -75.121902\n", + "6 554476 500007 7.180048 -76.071168\n", + "7 373792 500008 7.463546 -74.963595\n", + "8 324664 500009 7.743818 -76.738181\n", + "9 576898 500010 5.648854 -74.132482\n", + "10 273212 500011 6.727315 -76.635165\n", + "11 404836 500012 6.861639 -76.746068\n", + "12 498471 500013 7.362958 -74.297787\n", + "13 445097 500014 6.130727 -75.667267\n", + "14 397807 500015 5.825303 -76.559407\n", + "15 580316 500016 7.165207 -76.975321\n", + "16 421731 500017 6.236910 -74.487897\n", + "17 926698 500020 7.652337 -75.576271\n", + "18 370391 500021 7.236503 -75.530987\n", + "19 777796 500022 6.854339 -75.455203\n", + "20 394755 500023 7.241663 -76.453039\n", + "21 470054 500024 6.091720 -76.950376\n", + "22 438161 500025 7.261668 -77.019802\n", + "23 183703 500026 5.103643 -74.756495\n", + "24 447787 500027 4.874871 -74.121468\n", + "25 462685 500028 6.066869 -75.693614\n", + "26 384548 500030 5.627784 -76.472683\n", + "27 443880 500031 7.509737 -76.784860\n", + "28 350224 500032 6.206165 -74.107333\n", + "29 358644 500033 6.058493 -76.241435\n", + "30 406516 500034 7.417255 -75.579524\n", + "31 292610 500035 7.335878 -74.620644\n", + "32 339361 500036 5.158304 -74.901021\n", + "33 461339 500037 5.490366 -75.888601\n", + "34 334532 500040 7.124754 -75.053544\n", + "35 327973 500041 6.637287 -74.737167\n", + "36 332156 500042 7.137278 -75.044710\n", + "37 518508 500043 7.327858 -75.105685\n", + "38 353982 500044 4.986360 -75.365658\n", + "39 440938 500046 5.015590 -75.221307\n", + "40 497444 500047 5.814341 -75.149734\n", + "41 243727 55411 5.462628 -74.823107, 'lat': 'Latitude', 'lon': 'Longitude', 'locations': None, 'locationmode': None, 'geojson': None, 'featureidkey': None, 'color': 'nb_transactions', 'text': None, 'symbol': None, 'facet_row': None, 'facet_col': None, 'facet_col_wrap': 0, 'facet_row_spacing': None, 'facet_col_spacing': None, 'hover_name': 'merch_postal_code', 'hover_data': {'merch_postal_code': True, 'nb_transactions': True, 'Latitude': False, 'Longitude': False}, 'custom_data': None, 'size': 'nb_transactions', 'animation_frame': None, 'animation_group': None, 'category_orders': None, 'labels': None, 'color_discrete_sequence': None, 'color_discrete_map': None, 'color_continuous_scale': ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'], 'range_color': None, 'color_continuous_midpoint': None, 'symbol_sequence': None, 'symbol_map': None, 'opacity': None, 'size_max': None, 'projection': 'mercator', 'scope': None, 'center': None, 'fitbounds': None, 'basemap_visible': None, 'title': 'Transaction Locations in Medellin from 2019-01-01 to 2019-12-31 with epsilon=1', 'template': None, 'width': None, 'height': None}\n", + " 2117 args = build_dataframe(args, constructor)\n", + " 2118 if constructor in [go.Treemap, go.Sunburst, go.Icicle] and args[\"path\"] is not None:\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\express\\_core.py:970, in apply_default_cascade(\n", + " args={'animation_frame': None, 'animation_group': None, 'basemap_visible': None, 'category_orders': None, 'center': None, 'color': 'nb_transactions', 'color_continuous_midpoint': None, 'color_continuous_scale': ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'], 'color_discrete_map': None, 'color_discrete_sequence': None, ...}\n", + ")\n", + " 968 if \"symbol_sequence\" in args:\n", + " 969 if args[\"symbol_sequence\"] is None and args[\"template\"].data.scatter:\n", + "--> 970 args[\"symbol_sequence\"] = [\n", + " args = {'data_frame': nb_transactions merch_postal_code Latitude Longitude\n", + "0 306566 500001 6.389072 -74.596536\n", + "1 296614 500002 5.523995 -76.536749\n", + "2 342304 500003 5.982925 -75.812286\n", + "3 307235 500004 5.130301 -76.138346\n", + "4 237251 500005 5.605763 -74.716468\n", + "5 458127 500006 4.801478 -75.121902\n", + "6 554476 500007 7.180048 -76.071168\n", + "7 373792 500008 7.463546 -74.963595\n", + "8 324664 500009 7.743818 -76.738181\n", + "9 576898 500010 5.648854 -74.132482\n", + "10 273212 500011 6.727315 -76.635165\n", + "11 404836 500012 6.861639 -76.746068\n", + "12 498471 500013 7.362958 -74.297787\n", + "13 445097 500014 6.130727 -75.667267\n", + "14 397807 500015 5.825303 -76.559407\n", + "15 580316 500016 7.165207 -76.975321\n", + "16 421731 500017 6.236910 -74.487897\n", + "17 926698 500020 7.652337 -75.576271\n", + "18 370391 500021 7.236503 -75.530987\n", + "19 777796 500022 6.854339 -75.455203\n", + "20 394755 500023 7.241663 -76.453039\n", + "21 470054 500024 6.091720 -76.950376\n", + "22 438161 500025 7.261668 -77.019802\n", + "23 183703 500026 5.103643 -74.756495\n", + "24 447787 500027 4.874871 -74.121468\n", + "25 462685 500028 6.066869 -75.693614\n", + "26 384548 500030 5.627784 -76.472683\n", + "27 443880 500031 7.509737 -76.784860\n", + "28 350224 500032 6.206165 -74.107333\n", + "29 358644 500033 6.058493 -76.241435\n", + "30 406516 500034 7.417255 -75.579524\n", + "31 292610 500035 7.335878 -74.620644\n", + "32 339361 500036 5.158304 -74.901021\n", + "33 461339 500037 5.490366 -75.888601\n", + "34 334532 500040 7.124754 -75.053544\n", + "35 327973 500041 6.637287 -74.737167\n", + "36 332156 500042 7.137278 -75.044710\n", + "37 518508 500043 7.327858 -75.105685\n", + "38 353982 500044 4.986360 -75.365658\n", + "39 440938 500046 5.015590 -75.221307\n", + "40 497444 500047 5.814341 -75.149734\n", + "41 243727 55411 5.462628 -74.823107, 'lat': 'Latitude', 'lon': 'Longitude', 'locations': None, 'locationmode': None, 'geojson': None, 'featureidkey': None, 'color': 'nb_transactions', 'text': None, 'symbol': None, 'facet_row': None, 'facet_col': None, 'facet_col_wrap': 0, 'facet_row_spacing': None, 'facet_col_spacing': None, 'hover_name': 'merch_postal_code', 'hover_data': {'merch_postal_code': True, 'nb_transactions': True, 'Latitude': False, 'Longitude': False}, 'custom_data': None, 'size': 'nb_transactions', 'animation_frame': None, 'animation_group': None, 'category_orders': None, 'labels': None, 'color_discrete_sequence': None, 'color_discrete_map': None, 'color_continuous_scale': ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'], 'range_color': None, 'color_continuous_midpoint': None, 'symbol_sequence': None, 'symbol_map': None, 'opacity': None, 'size_max': None, 'projection': 'mercator', 'scope': None, 'center': None, 'fitbounds': None, 'basemap_visible': None, 'title': 'Transaction Locations in Medellin from 2019-01-01 to 2019-12-31 with epsilon=1', 'template': None, 'width': None, 'height': None}\n", + " args[\"symbol_sequence\"] = None\n", + " args[\"template\"] = None\n", + " 971 scatter.marker.symbol for scatter in args[\"template\"].data.scatter\n", + " 972 ]\n", + " 973 if not args[\"symbol_sequence\"] or not any(args[\"symbol_sequence\"]):\n", + " 974 args[\"symbol_sequence\"] = [\"circle\", \"diamond\", \"square\", \"x\", \"cross\"]\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\express\\_core.py:971, in (.0=)\n", + " 968 if \"symbol_sequence\" in args:\n", + " 969 if args[\"symbol_sequence\"] is None and args[\"template\"].data.scatter:\n", + " 970 args[\"symbol_sequence\"] = [\n", + "--> 971 scatter.marker.symbol for scatter in args[\"template\"].data.scatter\n", + " Exception trying to inspect frame. No more locals available.\n", + " 972 ]\n", + " 973 if not args[\"symbol_sequence\"] or not any(args[\"symbol_sequence\"]):\n", + " 974 args[\"symbol_sequence\"] = [\"circle\", \"diamond\", \"square\", \"x\", \"cross\"]\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\graph_objs\\scatter\\_marker.py:1214, in Marker.symbol(\n", + " self= instance\n", + ")\n", + " 1109 @property\n", + " 1110 def symbol(self):\n", + " 1111 \"\"\"\n", + " 1112 Sets the marker symbol type. Adding 100 is equivalent to\n", + " 1113 appending \"-open\" to a symbol name. Adding 200 is equivalent to\n", + " (...)\n", + " 1212 Any|numpy.ndarray\n", + " 1213 \"\"\"\n", + "-> 1214 return self[\"symbol\"]\n", + " Exception trying to inspect frame. No more locals available.\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\basedatatypes.py:4742, in BasePlotlyType.__getitem__(\n", + " self= instance,\n", + " prop='symbol'\n", + ")\n", + " 4739 self._compound_array_props[prop] = []\n", + " 4741 return validator.present(self._compound_array_props[prop])\n", + "-> 4742 elif self._props is not None and prop in self._props:\n", + " prop = 'symbol'\n", + " Exception trying to inspect frame. No more locals available.\n", + " 4743 return validator.present(self._props[prop])\n", + " 4744 elif self._prop_defaults is not None:\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\basedatatypes.py:4437, in BasePlotlyType._props(\n", + " self= instance\n", + ")\n", + " 4434 return self._orphan_props\n", + " 4435 else:\n", + " 4436 # Get data from parent's dict\n", + "-> 4437 return self.parent._get_child_props(self)\n", + " Exception trying to inspect frame. No more locals available.\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\basedatatypes.py:4451, in BasePlotlyType._get_child_props(\n", + " self= instance,\n", + " child= instance\n", + ")\n", + " 4439 def _get_child_props(self, child):\n", + " 4440 \"\"\"\n", + " 4441 Return properties dict for child\n", + " 4442 \n", + " (...)\n", + " 4449 dict\n", + " 4450 \"\"\"\n", + "-> 4451 if self._props is None:\n", + " Exception trying to inspect frame. No more locals available.\n", + " 4452 # If this node's properties are uninitialized then so are its\n", + " 4453 # child's\n", + " 4454 return None\n", + " 4455 else:\n", + " 4456 # ### Child a compound property ###\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\basedatatypes.py:4437, in BasePlotlyType._props(\n", + " self= instance\n", + ")\n", + " 4434 return self._orphan_props\n", + " 4435 else:\n", + " 4436 # Get data from parent's dict\n", + "-> 4437 return self.parent._get_child_props(self)\n", + " Exception trying to inspect frame. No more locals available.\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\basedatatypes.py:4471, in BasePlotlyType._get_child_props(\n", + " self=layout.template.Data({\n", + " 'bar': [{'error_x': {...': 'white'}},\n", + " 'type': 'table'}]\n", + "}),\n", + " child= instance\n", + ")\n", + " 4469 elif isinstance(validator, CompoundArrayValidator):\n", + " 4470 children = self[child.plotly_name]\n", + "-> 4471 child_ind = BaseFigure._index_is(children, child)\n", + " Exception trying to inspect frame. No more locals available.\n", + " 4472 assert child_ind is not None\n", + " 4474 children_props = self._props.get(child.plotly_name, None)\n", + "\n", + "File c:\\Users\\kshub\\OneDrive\\Documents\\PET_phase_2\\.venv\\lib\\site-packages\\plotly\\basedatatypes.py:3965, in BaseFigure._index_is(\n", + " iterable=(Scatter({\n", + " 'fillpattern': {'fillmode': 'overlay', 'size': 10, 'solidity': 0.2}\n", + "}),),\n", + " val= instance\n", + ")\n", + " 3963 index_list = [i for i, curr_val in enumerate(iterable) if curr_val is val]\n", + " 3964 if not index_list:\n", + "-> 3965 raise ValueError(\"Invalid value\")\n", + " 3967 return index_list[0]\n", + "\n", + "ValueError: Invalid value\n", + "\n" + ] } ], "source": [ - "app=create_hotspot_dash_app(df)\n", + "app=create_hotspot_dash_app(df_tran)\n", "app.run_server(debug=True)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -133,7 +730,7 @@ " " ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -141,13 +738,13 @@ } ], "source": [ - "app=create_mobility_dash_app(df)\n", + "app=create_mobility_dash_app(df_tran)\n", "app.run_server(debug=True)" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -165,7 +762,7 @@ " " ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -173,7 +770,7 @@ } ], "source": [ - "app=create_pandemic_adherence_dash_app(df)\n", + "app=create_pandemic_adherence_dash_app(df_tran)\n", "app.run_server(debug=True)" ] },