import%20marimo%0A%0A__generated_with%20%3D%20%220.23.11%22%0Aapp%20%3D%20marimo.App(%0A%20%20%20%20width%3D%22medium%22%2C%0A%20%20%20%20app_title%3D%22Hawk%2FDove%20with%20Multiple%20Risk-Attitudes%20-%20Payoff%20Analysis%22%2C%0A%20%20%20%20html_head_file%3D%22..%2Fdocs_head.html%22%2C%0A)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20import%20altair%20as%20alt%0A%0A%20%20%20%20from%20simulatingrisk.hawkdovemulti.batch_run%20import%20params%0A%0A%20%20%20%20data_dir%20%3D%20Path(%22data%2Fno_adjustment%2F%22)%0A%20%20%20%20return%20alt%2C%20data_dir%2C%20mo%2C%20params%2C%20pl%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20simulatingrisk.doc_utils%20import%20docs_header%0A%0A%20%20%20%20docs_header()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Hawk%2FDove%20with%20Multiple%20Risk-Attitudes%20%3A%20Payoff%20Analysis%0A%0A%20%20%20%20-%20mean%20and%20quartiles%20for%20payoff%20by%20risk%20attitude%0A%20%20%20%20-%20does%20mean%20vary%20between%20different%20risk%20attitudes%20or%20is%20it%20roughly%20the%20same%3F%0A%20%20%20%20%20-%20quartiles%20look%20different%2C%20but%20need%20a%20statistic%3B%20esp.%20compare%20lower-R%20quartile%20to%20higher-R%20quartile%0A%20%20%20%20%20%20-%20expect%2Fhope%20that%20lower%20quartile%20is%20higher%20for%20R1%20than%20R8%2C%20higher%20quartile%20is%20higher%20for%20R8%20than%20R1%0A%20%20%20%20%20%20-%20what's%20going%20on%20in%20the%20middle%3F%0A%0A%0A%20%20%20%20Simulations%20run%20for%20different%20lengths%20before%20converging%2C%20simulations%20include%20a%20range%20of%20different%20play%20neighborhood%20sizes%20(which%20affects%20total%20payoff%2C%20since%20each%20agent%20plays%20all%20neighbors%20in%20their%20play%20neighborhood.%20Therefore%2C%20we%20scale%20payoff%20by%20play%20neighborhood%20size%20and%20simulation%20run%20length%20so%20that%20payoffs%20can%20be%20compared%20across%20simulations.%20%20The%20scaled%20points%20is%20multipled%20by%20100%20to%20make%20the%20point%20ranges%20more%20intelligible%20and%20comparable%20to%20a%20simulation%20run.%0A%0A%20%20%20%20%5C%5B%0A%20%20%20%20%20scaled%5C_points%20%3D%20((points%20%2F%20play%5C_neighborhood)%20%2F%20simulation%5C_runlength)%20*%20100%0A%20%20%20%20%5C%5D%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data_dir%2C%20params%2C%20pl)%3A%0A%20%20%20%20%23%20agent%20data%20accompanies%20model%20data%20with%20same%20filename%3B%20run%20ids%20are%20only%20unique%20within%20a%20filename%2C%20and%20model%0A%20%20%20%20%23%20data%20includes%20all%20the%20parameters%20for%20that%20run%0A%0A%20%20%20%20def%20load_agent_data()%20-%3E%20list%5Bpl.LazyFrame%5D%3A%0A%20%20%20%20%20%20%20%20%23%20load%20agent%20data%20and%20model%20data%20in%20pairs%20by%20filename%2C%20joining%20on%20RunId%0A%20%20%20%20%20%20%20%20data_lf%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20model_file%20in%20data_dir.glob(%22*_model.csv%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20batch%20run%20filename%20shared%20by%20model%2Fagent%20data%3B%20runid%20is%20unique%20within%20a%20batch%0A%20%20%20%20%20%20%20%20%20%20%20%20batchrun_base_name%20%3D%20model_file.stem.replace(%22_model%22%2C%20%22%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20agent_file%20%3D%20model_file.with_name(f%22%7Bbatchrun_base_name%7D_agent.csv%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20agent_file.exists()%20or%20agent_file.stat().st_size%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(f%22Missing%20or%20empty%20agent%20file%20at%20%7Bagent_file%7D%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20load%20model%20data%20and%20join%20with%20agent%20data%2C%20then%20subset%20to%20the%20columns%20needed%20for%20analysis%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20-%20limit%20to%20initial%20parameters%20and%20RunId%20for%20joining%20with%20model%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20model_df%20%3D%20pl.scan_csv(str(model_file)).select(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22RunId%22%2C%20*params%5B%22no_adjustment%22%5D.keys()%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20drop%20risk_level_changed%3B%20not%20relevant%20here%20(no%20adjustment%20%3D%20no%20changes)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20rename%20internal%20risk_level%20field%20to%20risk_attitude%0A%20%20%20%20%20%20%20%20%20%20%20%20agent_df%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.scan_csv(str(agent_file))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.drop(%22risk_level_changed%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.rename(%7B%22risk_level%22%3A%20%22risk_attitude%22%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20join%20agent%20data%20with%20model%20data%20and%20add%20to%20list%20of%20lazy%20frames%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20make%20runid%20unique%20by%20adding%20base%20filename%0A%20%20%20%20%20%20%20%20%20%20%20%20agent_df%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20agent_df.join(model_df%2C%20on%3D%5B%22RunId%22%5D%2C%20how%3D%22left%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20run_id%3Dpl.concat_str(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Bpl.col.RunId%2C%20pl.lit(model_file.stem.replace(%22_model%22%2C%20%22%22))%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20separator%3D%22%7C%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.drop(%22RunId%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20data_lf.append(agent_df)%0A%0A%20%20%20%20%20%20%20%20return%20data_lf%0A%0A%20%20%20%20model_agent_df%20%3D%20(%0A%20%20%20%20%20%20%20%20pl.concat(load_agent_data())%0A%20%20%20%20%20%20%20%20.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20calculate%20a%20scaled%20points%20value%20so%20we%20can%20compare%20across%20runs%20with%20different%20length%20and%20play%20neighborhood%0A%20%20%20%20%20%20%20%20%20%20%20%20scaled_points%3Dpl.col(%22points%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.truediv(pl.col(%22play_neighborhood%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20.truediv(pl.col(%22Step%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20.mul(100)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.collect()%0A%20%20%20%20)%0A%20%20%20%20model_agent_df%0A%20%20%20%20return%20(model_agent_df%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20%23%20sns.boxenplot(data%3Dmodel_agent_df%2C%20y%3D%22points%22%2C%20x%3D%22risk_level%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Mean%2C%20median%2C%20and%20quartiles%20for%20payoff%20by%20risk-attitude%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model_agent_df%2C%20pl)%3A%0A%20%20%20%20%23%20Calculate%20quartiles%20with%20polars%0A%20%20%20%20payoff_by_risk_attitude%20%3D%20(%0A%20%20%20%20%20%20%20%20model_agent_df.group_by(%22risk_attitude%22)%0A%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20min%3Dpl.col(%22scaled_points%22).min()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20max%3Dpl.col(%22scaled_points%22).max()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20median%3Dpl.col(%22scaled_points%22).median()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mean%3Dpl.col(%22scaled_points%22).mean()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q1%3Dpl.col(%22scaled_points%22).quantile(0.25)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q2%3Dpl.col(%22scaled_points%22).quantile(0.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q3%3Dpl.col(%22scaled_points%22).quantile(0.75)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.sort(%22risk_attitude%22)%0A%20%20%20%20)%0A%0A%20%20%20%20payoff_by_risk_attitude%0A%20%20%20%20return%20(payoff_by_risk_attitude%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20custom_boxplot%2C%20payoff_by_risk_attitude)%3A%0A%20%20%20%20payoffchart_title%20%3D%20alt.TitleParams(%0A%20%20%20%20%20%20%20%20%22Cumulative%20Payoff%20Distribution%20by%20Risk%20Attitude%22%2C%0A%20%20%20%20%20%20%20%20subtitle%3D%22Payoff%20scaled%20by%20simulation%20length%20and%20play%20neighborhood%20across%20all%20simulations%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20custom_boxplot(payoff_by_risk_attitude).properties(title%3Dpayoffchart_title)%0A%20%20%20%20return%20(payoffchart_title%2C)%0A%0A%0A%40app.cell%0Adef%20_(payoff_by_risk_attitude)%3A%0A%20%20%20%20%23%20output%20payoff%20by%20risk%20attitude%20as%20nicely%20styled%20table%0A%20%20%20%20(%0A%20%20%20%20%20%20%20%20payoff_by_risk_attitude.rename(%7B%22risk_attitude%22%3A%20%22Risk%20Attitude%22%7D)%0A%20%20%20%20%20%20%20%20.style.tab_header(%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Cumulative%20Payoff%20by%20Risk%20Attitude%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20subtitle%3D%22Payoff%20scaled%20by%20simulation%20length%20and%20play%20neighborhood%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.fmt_number(decimals%3D1)%0A%20%20%20%20%20%20%20%20.fmt_number(%22Risk%20Attitude%22%2C%20decimals%3D0)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Payoff%20and%20simulation%20parameters%0A%0A%20%20%20%20How%20is%20agent%20payoff%20affected%20by%20simulation%20parameters%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model_agent_df%2C%20params%2C%20pl)%3A%0A%20%20%20%20%23%20one%20row%20per%20run_id%20%E2%80%94%20mean%20scaled_points%20across%20all%20agents%20in%20that%20run%0A%0A%20%20%20%20%23%20parameters%20to%20test%20correlation%0A%20%20%20%20corr_variables%20%3D%20%5B%22q1_payoff%22%2C%20%22mean_payoff%22%2C%20%22q3_payoff%22%5D%0A%0A%20%20%20%20param_variables%20%3D%20%5B%0A%20%20%20%20%20%20%20%20p%0A%20%20%20%20%20%20%20%20for%20p%20in%20params%5B%22no_adjustment%22%5D.keys()%0A%20%20%20%20%20%20%20%20if%20p%20not%20in%20%5B%22risk_distribution%22%2C%20%22risk_adjustment%22%5D%0A%20%20%20%20%5D%0A%0A%20%20%20%20%23%20risk%20distribution%20is%20categorical%3B%20treat%20to%20one-hot%200%2F1%20for%20each%0A%20%20%20%20_model_agent_riskdist_df%20%3D%20model_agent_df.to_dummies(%22risk_distribution%22)%0A%20%20%20%20%23%20print(_model_agent_riskdist_df.columns)%0A%20%20%20%20param_variables.extend(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20c%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20c%20in%20_model_agent_riskdist_df.columns%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20c.startswith(%22risk_distribution_%22)%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20%23%20print(corr_variables)%0A%0A%20%20%20%20%23%20corr_sample_size%20%3D%20100_000%20%20%20%23%20completes%20in%2017.20s%0A%20%20%20%20corr_sample_size%20%3D%201_000_000%20%20%23%20completes%20in%2032.69s%0A%0A%20%20%20%20param_level%20%3D%20(%0A%20%20%20%20%20%20%20%20_model_agent_riskdist_df.sample(corr_sample_size)%0A%20%20%20%20%20%20%20%20.group_by(%22run_id%22%2C%20*param_variables)%0A%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20mean_payoff%3Dpl.col.scaled_points.mean()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20q1_payoff%3Dpl.col.scaled_points.quantile(0.25)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20q3_payoff%3Dpl.col.scaled_points.quantile(0.75)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20param_level%0A%20%20%20%20param_level%0A%20%20%20%20%23%20corr%20%3D%20param_level.corr()%0A%20%20%20%20return%20corr_sample_size%2C%20corr_variables%2C%20param_level%2C%20param_variables%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(corr_variables%2C%20param_level%2C%20param_variables%2C%20pl)%3A%0A%20%20%20%20_corr_cols%20%3D%20corr_variables%20%2B%20param_variables%0A%0A%20%20%20%20run_corr_matrix_df%20%3D%20(%0A%20%20%20%20%20%20%20%20param_level.select(_corr_cols)%0A%20%20%20%20%20%20%20%20%23%20add%20labels%0A%20%20%20%20%20%20%20%20.corr()%0A%20%20%20%20%20%20%20%20.with_columns(pl.Series(%22var_x%22%2C%20_corr_cols))%0A%20%20%20%20%20%20%20%20.select(%22var_x%22%2C%20*_corr_cols)%0A%20%20%20%20)%0A%20%20%20%20run_corr_matrix_df%0A%20%20%20%20return%20(run_corr_matrix_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(pl%2C%20run_corr_matrix_df)%3A%0A%0A%20%20%20%20%23%20add%20columns%20as%20label%2C%20then%20unpivot%20to%20long%20form%20for%20charting%0A%20%20%20%20run_corr_matrix_long_df%20%3D%20(%0A%20%20%20%20%20%20%20%20run_corr_matrix_df.unpivot(%0A%20%20%20%20%20%20%20%20%20%20%20%20on%3Drun_corr_matrix_df.columns%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20index%3D%22var_x%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20variable_name%3D%22var_y%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20value_name%3D%22correlation%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.filter(pl.col.var_y.is_in(%5B%22mean_payoff%22%2C%20%22q1_payoff%22%2C%20%22q3_payoff%22%5D))%0A%20%20%20%20%20%20%20%20.filter(~pl.col.var_x.is_in(%5B%22mean_payoff%22%2C%20%22q1_payoff%22%2C%20%22q3_payoff%22%5D))%0A%20%20%20%20%20%20%20%20.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20correlation%3Dpl.col.correlation.cast(pl.Float32)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20correlation_str%3Dpl.col.correlation.map_elements(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lambda%20x%3A%20f%22%7Bfloat(x)%3A%2C.2f%7D%22%2C%20return_dtype%3Dpl.String%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20run_corr_matrix_long_df%0A%20%20%20%20return%20(run_corr_matrix_long_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20corr_sample_size%2C%20run_corr_matrix_long_df)%3A%0A%0A%20%20%20%20_heatmap_corr_chart%20%3D%20(%0A%20%20%20%20%20%20%20%20alt.Chart(run_corr_matrix_long_df)%0A%20%20%20%20%20%20%20%20.mark_rect()%0A%20%20%20%20%20%20%20%20.encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22var_x%3AO%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20axis%3Dalt.Axis(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20orient%3D%22top%22%2C%20%20%23%20move%20axis%20to%20top%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20labelAngle%3D-45%2C%20%20%23%20angle%20the%20labels%20(negative%20%3D%20counterclockwise)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22var_y%3AO%22%2C%20title%3D%22%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20use%20spectral%20theme%20since%20we%20have%20both%20negative%20and%20positive%20correlations%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(%22correlation%22).scale(scheme%3D%22spectral%22)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.properties(width%3D450%2C%20height%3D300)%0A%20%20%20%20)%0A%0A%20%20%20%20_text_corr_chart%20%3D%20_heatmap_corr_chart.mark_text().encode(%0A%20%20%20%20%20%20%20%20x%3D%22var_x%3AO%22%2C%0A%20%20%20%20%20%20%20%20y%3D%22var_y%3AO%22%2C%0A%20%20%20%20%20%20%20%20text%3D%22correlation_str%22%2C%0A%20%20%20%20%20%20%20%20%23%20for%20contrast%2C%20vary%20the%20color%20based%20on%20the%20intensity%20of%20the%20correlation%2C%20negative%20or%20positive%0A%20%20%20%20%20%20%20%20color%3Dalt.condition(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22abs(datum.correlation)%20%3E%200.3%22%2C%20alt.value(%22white%22)%2C%20alt.value(%22black%22)%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20(_heatmap_corr_chart%20%2B%20_text_corr_chart).properties(%0A%20%20%20%20%20%20%20%20width%3D600%2C%0A%20%20%20%20%20%20%20%20title%3Df%22Payoff%20%2F%20parameter%20correlation%20(based%20on%20sample%20of%20%7Bcorr_sample_size%3A%2C%7D%20agents)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Grid%20Size%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model_agent_df%2C%20pl)%3A%0A%20%20%20%20%23%20calculate%20mean%20%26%20quartiles%20for%20risk%20attitude%20by%20grid%20size%0A%20%20%20%20payoff_by_risk_grid%20%3D%20(%0A%20%20%20%20%20%20%20%20model_agent_df.group_by(%22risk_attitude%22%2C%20%22grid_size%22)%0A%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20min%3Dpl.col(%22scaled_points%22).min()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20max%3Dpl.col(%22scaled_points%22).max()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20median%3Dpl.col(%22scaled_points%22).median()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mean%3Dpl.col(%22scaled_points%22).mean()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q1%3Dpl.col(%22scaled_points%22).quantile(0.25)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q2%3Dpl.col(%22scaled_points%22).quantile(0.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q3%3Dpl.col(%22scaled_points%22).quantile(0.75)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.sort(%22grid_size%22%2C%20%22risk_attitude%22)%0A%20%20%20%20)%0A%20%20%20%20return%20(payoff_by_risk_grid%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20custom_boxplot%2C%20payoff_by_risk_grid%2C%20payoffchart_title)%3A%0A%20%20%20%20custom_boxplot(payoff_by_risk_grid).facet(%0A%20%20%20%20%20%20%20%20column%3Dalt.Column(%22grid_size%22%2C%20title%3D%22Grid%20Size%22)%0A%20%20%20%20).properties(title%3Dpayoffchart_title)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(payoff_by_risk_grid%2C%20plot_mean_quartiles)%3A%0A%20%20%20%20plot_mean_quartiles(payoff_by_risk_grid%2C%20%22grid_size%22%2C%20%22Grid%20Size%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Play%20Neighborhood%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20custom_boxplot%2C%20model_agent_df%2C%20payoffchart_title%2C%20pl)%3A%0A%20%20%20%20%23%20calculate%20mean%20%26%20quartiles%20for%20risk%20attitude%20by%20play%20neighborhood%0A%20%20%20%20payoff_by_risk_playnhood%20%3D%20(%0A%20%20%20%20%20%20%20%20model_agent_df.group_by(%22risk_attitude%22%2C%20%22play_neighborhood%22)%0A%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20min%3Dpl.col(%22scaled_points%22).min()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20max%3Dpl.col(%22scaled_points%22).max()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20median%3Dpl.col(%22scaled_points%22).median()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mean%3Dpl.col(%22scaled_points%22).mean()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q1%3Dpl.col(%22scaled_points%22).quantile(0.25)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q2%3Dpl.col(%22scaled_points%22).quantile(0.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q3%3Dpl.col(%22scaled_points%22).quantile(0.75)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.sort(%22play_neighborhood%22%2C%20%22risk_attitude%22)%0A%20%20%20%20)%0A%0A%20%20%20%20custom_boxplot(payoff_by_risk_playnhood).facet(%0A%20%20%20%20%20%20%20%20column%3Dalt.Column(%22play_neighborhood%22%2C%20title%3D%22Play%20Neighborhood%22)%0A%20%20%20%20).properties(title%3Dpayoffchart_title)%0A%20%20%20%20return%20(payoff_by_risk_playnhood%2C)%0A%0A%0A%40app.cell%0Adef%20_(payoff_by_risk_playnhood%2C%20plot_mean_quartiles)%3A%0A%20%20%20%20plot_mean_quartiles(%0A%20%20%20%20%20%20%20%20payoff_by_risk_playnhood%2C%20%22play_neighborhood%22%2C%20%22Play%20Neighborhood%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Observed%20Neighborhood%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model_agent_df%2C%20pl)%3A%0A%0A%20%20%20%20%23%20calculate%20mean%20%26%20quartiles%20for%20risk%20attitude%20by%20observed%20neighborhood%0A%20%20%20%20payoff_by_risk_obsvnhood%20%3D%20(%0A%20%20%20%20%20%20%20%20model_agent_df.group_by(%22risk_attitude%22%2C%20%22observed_neighborhood%22)%0A%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20min%3Dpl.col(%22scaled_points%22).min()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20max%3Dpl.col(%22scaled_points%22).max()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20median%3Dpl.col(%22scaled_points%22).median()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mean%3Dpl.col(%22scaled_points%22).mean()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q1%3Dpl.col(%22scaled_points%22).quantile(0.25)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q2%3Dpl.col(%22scaled_points%22).quantile(0.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Q3%3Dpl.col(%22scaled_points%22).quantile(0.75)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.sort(%22observed_neighborhood%22%2C%20%22risk_attitude%22)%0A%20%20%20%20)%0A%20%20%20%20return%20(payoff_by_risk_obsvnhood%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20custom_boxplot%2C%20payoff_by_risk_obsvnhood%2C%20payoffchart_title)%3A%0A%20%20%20%20custom_boxplot(payoff_by_risk_obsvnhood).facet(%0A%20%20%20%20%20%20%20%20column%3Dalt.Column(%22observed_neighborhood%22%2C%20title%3D%22Observed%20Neighborhood%22)%0A%20%20%20%20).properties(title%3Dpayoffchart_title)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(payoff_by_risk_obsvnhood%2C%20plot_mean_quartiles)%3A%0A%20%20%20%20plot_mean_quartiles(%0A%20%20%20%20%20%20%20%20payoff_by_risk_obsvnhood%2C%20%22observed_neighborhood%22%2C%20%22Observed%20Neighborhood%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%0A%20%20%20%20Utility%20methods%20used%20to%20graph%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20mo%2C%20pl)%3A%0A%20%20%20%20%23%20define%20a%20custom%20box%20plot%20method%20using%20layered%20plots%2C%0A%20%20%20%20%23%20so%20that%20we%20can%20quickly%20generate%20plots%20from%20statistics%20generated%20by%20polars%0A%0A%20%20%20%20def%20custom_boxplot(df)%3A%0A%20%20%20%20%20%20%20%20%23%20calculate%20risk%20group%20labels%2C%20for%20color%0A%20%20%20%20%20%20%20%20plot_df%20%3D%20df.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20risk_type%3Dpl.when(pl.col.risk_attitude%20%3C%203)%0A%20%20%20%20%20%20%20%20%20%20%20%20.then(pl.lit(%22Risk-Seeking%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20.when(pl.col.risk_attitude%20%3C%207)%0A%20%20%20%20%20%20%20%20%20%20%20%20.then(pl.lit(%22Risk-Moderate%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20.otherwise(pl.lit(%22Risk-Averse%22))%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%20create%20base%20chart%20to%20use%20across%20layers%0A%20%20%20%20%20%20%20%20base_chart%20%3D%20alt.Chart(plot_df)%0A%0A%20%20%20%20%20%20%20%20%23%20area%20chart%20for%20Q1%20to%20Q3%0A%20%20%20%20%20%20%20%20area_chart%20%3D%20base_chart.mark_rect(width%3D15).encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22Q1%22).axis(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20offset%3D12%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%20%20%23%20add%20offset%20so%20axis%20does%20not%20crowd%20rectangle%0A%20%20%20%20%20%20%20%20%20%20%20%20y2%3D%22Q3%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22risk_attitude%3AQ%22%2C%20title%3D%22Risk%20Attitude%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tooltip%3D%5B%22min%22%2C%20%22max%22%2C%20%22mean%22%2C%20%22Q1%22%2C%20%22median%22%2C%20%22Q3%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20colors%20from%20tableau%2010%20https%3A%2F%2Fvega.github.io%2Fvega%2Fdocs%2Fschemes%2F%23tableau10%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20but%20specify%20order%20to%20make%20more%20logical%2Fsemantic%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22risk_type%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Risk%20Attitude%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sort%3D%5B%22Risk%20Inclined%22%2C%20%22Risk%20Moderate%22%2C%20%22Risk%20Avoidant%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20).scale(range%3D%5B%22%23e45756%22%2C%20%22%23f58518%22%2C%20%22%234c78a8%22%5D)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%20line%20chart%20for%20min-max%20spread%0A%20%20%20%20%20%20%20%20%23%20specifying%20a%20stroke%20for%20point%20on%20the%20line%20only%20adds%20the%20min%20point%0A%0A%20%20%20%20%20%20%20%20%23%20set%20light%2Fdark%20color%20depending%20on%20notebook%20theme%0A%20%20%20%20%20%20%20%20line_stroke_color%20%3D%20%22%20%2352514e%22%20if%20mo.app_meta().theme%20%3D%3D%20%22light%22%20else%20%22%23c3c2b7%22%0A%0A%20%20%20%20%20%20%20%20minmax_line_chart%20%3D%20base_chart.mark_line(%0A%20%20%20%20%20%20%20%20%20%20%20%20point%3Dalt.OverlayMarkDef(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20filled%3DFalse%2C%20shape%3D%22stroke%22%2C%20color%3Dline_stroke_color%2C%20strokeWidth%3D2%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20).encode(alt.Y(%22min%22)%2C%20alt.Y2(%22max%22)%2C%20x%3D%22risk_attitude%3AQ%22)%0A%20%20%20%20%20%20%20%20%23%20add%20a%20black%20stroke%20for%20the%20max%0A%20%20%20%20%20%20%20%20max_marks%20%3D%20base_chart.mark_point(%0A%20%20%20%20%20%20%20%20%20%20%20%20shape%3D%22stroke%22%2C%20size%3D55%2C%20color%3Dline_stroke_color%0A%20%20%20%20%20%20%20%20).encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D%22max%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22risk_attitude%3AQ%22)%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20median_marks%20%3D%20base_chart.mark_point(%0A%20%20%20%20%20%20%20%20%20%20%20%20shape%3D%22stroke%22%2C%20size%3D100%2C%20strokeWidth%3D1%2C%20color%3Dline_stroke_color%0A%20%20%20%20%20%20%20%20).encode(y%3D%22median%22%2C%20x%3D%22risk_attitude%3AQ%22)%0A%0A%20%20%20%20%20%20%20%20%23%20mean%20line%20%3F%0A%20%20%20%20%20%20%20%20mean_line_chart%20%3D%20base_chart.mark_line(%0A%20%20%20%20%20%20%20%20%20%20%20%20interpolate%3D%22monotone%22%2C%20color%3Dline_stroke_color%2C%20opacity%3D0.5%0A%20%20%20%20%20%20%20%20).encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22risk_attitude%3AQ%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22mean%22%2C%20title%3D%22Cumulative%20Payoff%22).scale(zero%3DFalse)%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20mean_line_chart%20%2B%20minmax_line_chart%20%2B%20area_chart%20%2B%20median_marks%20%2B%20max_marks%0A%20%20%20%20%20%20%20%20).resolve_axis(%22shared%22)%0A%0A%20%20%20%20return%20(custom_boxplot%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20payoffchart_title)%3A%0A%20%20%20%20%23%20define%20a%20custom%20method%20to%20plot%20mean%20and%20quartiles%20for%20a%20specified%20simulation%20parameter%0A%0A%20%20%20%20def%20plot_mean_quartiles(df%2C%20field%2C%20field_label)%3A%0A%20%20%20%20%20%20%20%20%23%20takes%20a%20dataframe%2C%20the%20field%20in%20the%20dataframe%20for%20the%20simulation%20parameter%2C%20and%20displayable%20label%20for%20the%20field%0A%0A%20%20%20%20%20%20%20%20%23%20create%20a%20selection%20filter%20bound%20to%20the%20legend%0A%20%20%20%20%20%20%20%20selection%20%3D%20alt.selection_point(fields%3D%5Bfield%5D%2C%20bind%3D%22legend%22)%0A%20%20%20%20%20%20%20%20base_chart%20%3D%20alt.Chart(df)%0A%20%20%20%20%20%20%20%20%23%20curved%20line%20for%20the%20mean%20pyoff%20by%20risk%20attitude%0A%20%20%20%20%20%20%20%20payoff_mean_chart%20%3D%20base_chart.mark_line(interpolate%3D%22monotone%22).encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22risk_attitude%22%2C%20title%3D%22Risk%20Attitude%22).scale(domain%3D%5B0%2C%209%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22mean%22%2C%20title%3D%22Cumulative%20Payoff%20(mean)%22).scale(zero%3DFalse)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(f%22%7Bfield%7D%3AN%22%2C%20title%3Dfield_label)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20opacity%3Dalt.when(selection).then(alt.value(1.0)).otherwise(alt.value(0.4))%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%20curved%20area%20chart%20for%20payoff%20quartile%20spread%0A%20%20%20%20%20%20%20%20payoff_spread%20%3D%20base_chart.mark_area(interpolate%3D%22monotone%22).encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22risk_attitude%22%2C%20title%3D%22Risk%20Attitude%22).scale(domain%3D%5B0%2C%209%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22Q3%22).scale(zero%3DFalse)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y2%3D%22Q1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(f%22%7Bfield%7D%3AN%22%2C%20title%3Dfield_label)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20opacity%3Dalt.when(selection).then(alt.value(0.3)).otherwise(alt.value(0.1))%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%23%20combine%20the%20charts%20for%20multiple%20ways%20to%20view%0A%20%20%20%20%20%20%20%20chart_payoff_title%20%3D%20payoffchart_title.copy()%0A%20%20%20%20%20%20%20%20chart_payoff_title%5B%22text%22%5D%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22%7Bpayoffchart_title%5B'text'%5D%7D%20and%20%7Bfield_label%7D%20%E2%80%94%20Mean%20and%20Quartiles%22%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%23%20display%20mean%20curve%20chart%2C%20payoff%20area%20chart%2C%20and%20mean%20layered%20with%20the%20payoff%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20(payoff_mean_chart%20%7C%20payoff_spread%20%7C%20(payoff_mean_chart%20%2B%20payoff_spread))%0A%20%20%20%20%20%20%20%20%20%20%20%20.add_params(selection)%0A%20%20%20%20%20%20%20%20%20%20%20%20.resolve_legend(color%3D%22shared%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.properties(title%3Dchart_payoff_title)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20return%20(plot_mean_quartiles%2C)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
bc111da8a8030ddb0494170e4e14b3d4