<jupyter_start><jupyter_text>Plotting overviewPyEI has a number of plots available. Here is a list of available plots.Plotting methods for any fitted EI model where inference involves sampling -- i.e. all approaches excepts the (non-Bayesian) Goodman's ER- Summary plots for distributions of **polity-wide** voter preferences    - `plot`    - `plot_kde` (2 by 2)    - `plot_kdes` ($r$ by $c$)    - `plot_boxplot` (2 by 2)    - `plot_boxplots` ($r$ by $c$)    - `plot_intervals` (2 by 2)- Plots of polarization    - `plot_polarization_kde` (2 by 2)    - `plot_polarization_kdes` ($r$ by $c$)For all approaches except Goodman's ER and the Bayesian Goodman's ER (which do not generate samples for each precinct)- Plots of **precinct-level** voter preferences    - `precinct_level_plot`    - `plot_intervals_by_precinct`        `GoodmansER` objects also have a plot method- `plot`Additional plotting utilities: for tomography plotting and comparing precinct-level posterior means:- `plot_utils.tomography_plot`- `plot_precinct_scatterplot`We can also visualize the Bayesian models (see Visualizing Models, below).Below we show examples of these available plots (as well as loading example data and fitting example models).At the end of the notebook, we show how to save plots as files.  Load example data<jupyter_code># Example 2x2 data
santa_clara_data = Datasets.Santa_Clara.to_dataframe()

group_fraction_2by2 = np.array(santa_clara_data["pct_e_asian_vote"])
votes_fraction_2by2 = np.array(santa_clara_data["pct_for_hardy2"])

demographic_group_name_2by2 = "e_asian"
candidate_name_2by2 = "Hardy"

# Example rxc data (here r=c=3)
group_fractions_rbyc = np.array(santa_clara_data[['pct_ind_vote', 'pct_e_asian_vote', 'pct_non_asian_vote']]).T
votes_fractions_rbyc = np.array(santa_clara_data[['pct_for_hardy2', 'pct_for_kolstad2', 'pct_for_nadeem2']]).T

candidate_names_rbyc = ["Hardy", "Kolstad", "Nadeem"]
demographic_group_names_rbyc = ["ind", "e_asian", "non_asian"]

# Data we'll use in both 2x2 and rbyc
precinct_pops = np.array(santa_clara_data["total2"])
precinct_names = santa_clara_data['precinct']<jupyter_output><empty_output><jupyter_text>Tomography_plotFor the 2 by 2 case. If - $X^i$ is the fraction of voters in the demographic group of interest (in Precinct i) (from `group_fraction`)- $T^i$ is the fraction of votes for the candidate of group of interest (in Precinct i) (from `votes_fraction`)- $b_1^i$ is the fraction of voters in the demographic group of interest that vote for the candidate of interest (in Precinct i)- $b_2^i$ is the fraction of voters in the complement of the demographic group of interest that vote for the candidate of interest (in Precinct i)    then what is sometimes called the **accounting identity** tells us that:$$ T^i = b_1^i X^i + b_2^i (1-X^i)$$(that is, the total votes for a candidate come from summing their votes from each of the two groups).We can visualize this linear relationship between $b_1^i$ and $b_2^i$ by plotting them against each other. If we plot a line segment for each precinct, and display a line segment for each precinct, we get what has been called a **tomography_plot**. (Note that this plot does not depend on a fitted model.)<jupyter_code>tomography_plot(group_fraction_2by2, votes_fraction_2by2, demographic_group_name=demographic_group_name_2by2, candidate_name=candidate_name_2by2)<jupyter_output><empty_output><jupyter_text>Fit example modelsThe rest of the plots are applicable to fitted models.<jupyter_code># Create a TwobyTwoEI object
ei_2by2 = TwoByTwoEI(model_name="king99_pareto_modification", pareto_scale=8, pareto_shape=2)

# Fit the model
ei_2by2.fit(group_fraction_2by2, 
       votes_fraction_2by2, 
       precinct_pops, 
       demographic_group_name=demographic_group_name_2by2, 
       candidate_name=candidate_name_2by2, 
       precinct_names=precinct_names, 
)
# Create a RowByColumnEI object
ei_rbyc = RowByColumnEI(model_name='multinomial-dirichlet-modified', pareto_shape=100, pareto_scale=100)

# Fit the model
ei_rbyc.fit(group_fractions_rbyc, 
       votes_fractions_rbyc, 
       precinct_pops, 
       demographic_group_names=demographic_group_names_rbyc, 
       candidate_names=candidate_names_rbyc, 
       #precinct_names=precinct_names, 
)
# Create a GoodmansER object
goodmans_er = GoodmansER() 

# Fit the model
goodmans_er.fit(
    group_fraction_2by2, 
    votes_fraction_2by2,
    demographic_group_name=demographic_group_name_2by2, 
    candidate_name=candidate_name_2by2
)
# Create a GoodmansERBayes object
bayes_goodman_ei = GoodmansERBayes("goodman_er_bayes", weighted_by_pop=True, sigma=1)

# Fit the model
bayes_goodman_ei.fit(
    group_fraction_2by2, 
    votes_fraction_2by2,
    precinct_pops,
    demographic_group_name=demographic_group_name_2by2, 
    candidate_name=candidate_name_2by2
)<jupyter_output>Auto-assigning NUTS sampler...
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [eps, b_2, b_1]<jupyter_text>Summary plots for distributions of polity-wide voter preferencesAvailable plotting methods for fitted `TwoByTwoEI`, `RowByColumEI`, `GoodmansERBayes` objects- `plot`- `plot_kde` (2 by 2)- `plot_kdes` ($r$ by $c$)- `plot_boxplot` (2 by 2)- `plot_boxplots` ($r$ by $c$)- `plot_intervals` (2 by 2)<jupyter_code>ei_2by2.plot() # Summary plot 
ei_2by2.plot_kde()
ei_2by2.plot_boxplot()
ei_2by2.plot_intervals()
ei_rbyc.plot()<jupyter_output><empty_output><jupyter_text>**For r by c kde and boxplots, specify whether you'd like to organize the plots by group or by candidate**<jupyter_code>ei_rbyc.plot_kdes(plot_by="group")
ei_rbyc.plot_kdes(plot_by="candidate")
ei_rbyc.plot_boxplots(plot_by="group")
ei_rbyc.plot_boxplots(plot_by="candidate")<jupyter_output><empty_output><jupyter_text>Plots of polarizationAvailable for fitted `TwoByTwoEI`, `RowByColumEI`, `GoodmansERBayes` objects.These plots visualize the estimated difference in the levels of support for a candidate between two demographic groups. Thus, they give insight into the polarization of those two groups with respect to a particular candidate.We can specify a threshold and show the probability that the difference in support is at least as large as that threshold.Alternatively, we can specify a percentile, and show the associated credible interval of the difference in voter support levels.For example, we might specify the percentile of 95, and be returned something like: **there is a 95% probability that the difference in support for the candidate is in [.34, .73].** The fact that the interval is far from 0 (where 0 represents no difference in support for the candidate between the two groups), suggests that the two groups have very different levels of support for the candidate.<jupyter_code>ei_2by2.plot_polarization_kde(threshold=0.4, show_threshold=True) #set show_threshold to false to just view the kde
ei_2by2.plot_polarization_kde(percentile=95, show_threshold=True) #set show_threshold to false to just view the kde
# For the r by c case, we need to specify the two groups we'd like to compare, and the candidate of interest
ei_rbyc.plot_polarization_kde(percentile=95, groups=['ind', 'e_asian'], candidate='Kolstad', show_threshold=True) #set show_threshold to false to just view the kde<jupyter_output><empty_output><jupyter_text>Plots of precinct-level voter preferencesAvailable for `TwoByTwoEI`, `RowByColumEI` objects.*(Note that neither GoodmansER approach produce precinct-level estimates)*- `precinct_level_plot`- `plot_intervals_by_precinct`<jupyter_code>ei_2by2.precinct_level_plot()
#ei_rbyc.precinct_level_plot()<jupyter_output><empty_output><jupyter_text>GoodmansER plotsLike `TwoByTwoEI`, `RowByColumEI` objects, `GoodmansER` and `GoodmansERBayes` objects have a plot function to show a summary plot; however, since Goodman models rest on a linear regresion, their summary plots visualize that regression, and so look different from the other summary plots.Note that the y-coordinate of the point of intersection of the line with $x=1$ gives the estimated support of the demographic group of interest for the candidate of interest. Note that the y-coordinate of the point of intersection of the line with $x=0$ gives the estimated support of the complement of the demographic group of interest for the candidate of interest.<jupyter_code>goodmans_er.plot()
bayes_goodman_ei.plot()<jupyter_output><empty_output><jupyter_text>plot_precinct_scatterplotThis is a method for comparing the outputs of two different ei methods by comparing the point estimates that the two methods give for each precinct.<jupyter_code>ei_2by2_alternative = TwoByTwoEI(model_name='truncated_normal')
ei_2by2_alternative.fit(group_fraction_2by2, 
       votes_fraction_2by2, 
       precinct_pops, 
       demographic_group_name=demographic_group_name_2by2, 
       candidate_name=candidate_name_2by2, 
       precinct_names=precinct_names, 
)
plot_precinct_scatterplot([ei_2by2, ei_2by2_alternative], run_names=['king-pareto', 'truncated normal'], candidate='Hardy')<jupyter_output><empty_output><jupyter_text>Visualizing modelsWe can use pymc3's `model_to_graphviz` function to visualize the models themselves, by showing the associated graphical model.Available for `TwoByTwoEI`, `RowByColumnEI`, and `BayesGoodmansER` objects<jupyter_code>model = ei_2by2.sim_model
pm.model_to_graphviz(model)
model = bayes_goodman_ei.sim_model
pm.model_to_graphviz(model)<jupyter_output><empty_output><jupyter_text>Saving plotsPyEI's plotting functions return matplotlib Axes objects. One simple way to save a figure that you've generated in a notebook is to use matplotlib.pyplot's `savefig` method. We provide an example here, in case you are new to matplotlib.<jupyter_code>import matplotlib.pyplot as plt

goodmans_er.plot()
plt.savefig('goodman_er_testfig.png', dpi=300) # Creates a file named `goodman_er_testfig.png`<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0793698879127537, 'fraction_numerical': 0.014743007169544582, 'mean_word_length': 6.239766081871345, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '495262', 'license': 'MIT', 'n_tokens_mistral': 3364, 'n_tokens_neox': 3191, 'n_words': 981, 'path': 'pyei/intro_notebooks/Plotting_with_PyEI.ipynb', 'repo_name': 'tahentx/ecological-inference', 'size': '9903'}