diff --git a/data-visualization.ipynb b/data-visualization.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..011953b28bad3c1a0891fcb245a405b598468784 --- /dev/null +++ b/data-visualization.ipynb @@ -0,0 +1,317 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "e60a9820-3375-4c4a-acc1-485be4be01e7", + "metadata": {}, + "source": [ + "# Data Visualization\n", + "\n", + "In this lesson, we'll learn two data visualization libraries `matplotlib` and `seaborn`. By the end of this lesson, students will be able to:\n", + "\n", + "- Skim library documentation to identify relevant examples and usage information.\n", + "- Apply `seaborn` and `matplotlib` to create and customize relational and regression plots.\n", + "- Describe data visualization principles as they relate the effectiveness of a plot.\n", + "\n", + "Just like how we like to import `pandas` as `pd`, we'll import `matplotlib.pyplot` as `plt` and `seaborn` as `sns`.\n", + "\n", + "**Seaborn** is a Python data visualization library based on matplotlib. Behind the scenes, seaborn uses matplotlib to draw its plots. When importing seaborn, it is recommended to call `sns.set_theme()` to apply the recommended seaborn visual style instead of the default matplotlib theme." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5872c8e4-b2e0-4237-b1f1-f64dbd05ef5a", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "\n", + "sns.set_theme()" + ] + }, + { + "cell_type": "markdown", + "id": "e748d5dd-da19-4d07-abda-e965f6a5979c", + "metadata": {}, + "source": [ + "Let's load this uniquely-formatted pokemon dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21541502-fd8f-45f7-85e2-b1f9e31af340", + "metadata": {}, + "outputs": [], + "source": [ + "pokemon = pd.read_csv(\"pokemon_viz.csv\", index_col=\"Num\")\n", + "pokemon" + ] + }, + { + "cell_type": "markdown", + "id": "95083b7c-e36c-4ad8-86e9-1f249d6a6113", + "metadata": {}, + "source": [ + "## Figure-level versus axes-level functions\n", + "\n", + "One way to draw a scatter plot comparing every pokemon's `Attack` and `Defense` stats is by calling `sns.scatterplot`. Because [this plotting function has so many parameters](https://seaborn.pydata.org/generated/seaborn.scatterplot.html), it's good practice to specify **keyword arguments** that tell Python which argument should go to which parameter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88545227-07e6-4dcc-8723-a2555ffc59fd", + "metadata": {}, + "outputs": [], + "source": [ + "sns.scatterplot(pokemon, x=\"Attack\", y=\"Defense\")" + ] + }, + { + "cell_type": "markdown", + "id": "a13251e4-c112-40ea-a593-87123fa78876", + "metadata": {}, + "source": [ + "The return type of `sns.scatterplot` is a matplotlib feature called **axes** that can be used to compose multiple plots into a single visualization. We can show two plots side-by-side by placing them on the same axes. For example, we could compare the attack and defense stats for two different groups of pokemon: not-`Legendary` and `Legendary`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f1247ae-736d-4aee-be81-caf26f993780", + "metadata": {}, + "outputs": [], + "source": [ + "# Nested tuple unpacking!\n", + "fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2)\n", + "ax1.set_title(\"Not Legendary\")\n", + "sns.scatterplot(pokemon[~pokemon[\"Legendary\"]], x=\"Attack\", y=\"Defense\", ax=ax1)\n", + "ax2.set_title(\"Legendary\")\n", + "sns.scatterplot(pokemon[pokemon[\"Legendary\"]], x=\"Attack\", y=\"Defense\", ax=ax2)\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "4506e513-7ec4-4ff2-a952-febac3526a98", + "metadata": {}, + "source": [ + "Each problem in the plot above can be fixed manually by repeatedly editing and running the code until you get a satisfactory result, but it's a tedious process. Seaborn was invented to make our data visualization experience less tedious. Methods like `sns.scatterplot` are considered **axes-level functions** designed for interoperability with the rest of `matplotlib`, but they come at the cost of forcing you to deal with the tediousness of tweaking matplotlib.\n", + "\n", + "Instead, the recommended way to create plots in seaborn is to use **figure-level functions** like `sns.relplot` as in *relational plot*. Figure-level functions return specialized seaborn objects (such as `FacetGrid`) that are intended to provide more usable results without tweaking." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee05b224-9192-4784-8a6b-c375c4572ddc", + "metadata": {}, + "outputs": [], + "source": [ + "sns.relplot(pokemon, x=\"Attack\", y=\"Defense\", col=\"Legendary\")" + ] + }, + { + "cell_type": "markdown", + "id": "76fe1021-f8cf-423d-b22b-d8bd4f1cfd94", + "metadata": {}, + "source": [ + "By default, relational plots produce scatter plots but they can also produce line plots by specifying the keyword argument `kind=\"line\"`.\n", + "\n", + "Alongside `relplot`, seaborn provides several other useful figure-level plotting functions:\n", + "\n", + "- [`relplot` for **relational plots**](https://seaborn.pydata.org/generated/seaborn.relplot.html), such as scatter plots and line plots.\n", + "- [`displot` for **distribution plots**](https://seaborn.pydata.org/generated/seaborn.displot.html), such as histograms and kernel density estimates.\n", + "- [`catplot` for **categorical plots**](https://seaborn.pydata.org/generated/seaborn.catplot.html), such as strip plots, box plots, violin plots, and bar plots.\n", + "- [`lmplot` for **relational plots with a regression fit**](https://seaborn.pydata.org/generated/seaborn.lmplot.html), such as the scatter plot with regression fit below.\n", + "\n", + "When reading documentation online, it is important to remember that we will only use figure-level plots in this course because they are the recommended approach. On the [relative merits of figure-level functions](https://seaborn.pydata.org/tutorial/function_overview.html#relative-merits-of-figure-level-functions) in the seaborn documentation:\n", + "\n", + "> On balance, the figure-level functions add some additional complexity that can make things more confusing for beginners, but their distinct features give them additional power. The tutorial documentation mostly uses the figure-level functions, because they produce slightly cleaner plots, and we generally recommend their use for most applications. The one situation where they are not a good choice is when you need to make a complex, standalone figure that composes multiple different plot kinds. At this point, it’s recommended to set up the figure using matplotlib directly and to fill in the individual components using axes-level functions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72c0d643-b70f-4b3e-b5c8-b3b9693b7cb5", + "metadata": {}, + "outputs": [], + "source": [ + "sns.lmplot(pokemon, x=\"Attack\", y=\"Defense\", col=\"Legendary\")" + ] + }, + { + "cell_type": "markdown", + "id": "555008e3-fe59-42f6-be38-4e1133022b1b", + "metadata": {}, + "source": [ + "## Customizing a `FacetGrid` plot\n", + "\n", + "`relplot`, `displot`, `catplot`, and `lmplot` all return a `FacetGrid`, a specialized seaborn object that represents a data visualization canvas. As we've seen above, a `FacetGrid` can put two plots side-by-side and manage their axes by removing the y-axis labels on the right plot because they are the same as the plot on the left.\n", + "\n", + "However, there are still many instances where we might want to customize a plot by changing labels or adding titles. We might want to create a bar plot to count the number of each type of pokemon." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24c31e9c-f790-4993-a6fb-5c190b008367", + "metadata": {}, + "outputs": [], + "source": [ + "sns.catplot(pokemon, x=\"Type 1\", kind=\"count\")" + ] + }, + { + "cell_type": "markdown", + "id": "1767fe40-b82d-490b-9e8b-06732c9fe1a1", + "metadata": {}, + "source": [ + "The pokemon types on the x-axis are hardly readable, the y-axis label \"count\" could use capitalization, and the plot could use a title. To modify the attributes of a plot, we can assign the returned `FacetGrid` to a variable like `grid` and then call [`tick_params`](https://seaborn.pydata.org/generated/seaborn.FacetGrid.tick_params.html) or [`set`](https://seaborn.pydata.org/generated/seaborn.FacetGrid.set.html#seaborn.FacetGrid.set)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50dc1652-2fc0-4517-b3d9-e6f3b75c4b9b", + "metadata": {}, + "outputs": [], + "source": [ + "grid = sns.catplot(pokemon, x=\"Type 1\", kind=\"count\")\n", + "grid.tick_params(axis=\"x\", rotation=60)\n", + "grid.set(title=\"Count of each primary pokemon type\", xlabel=\"Primary Type\", ylabel=\"Count\")" + ] + }, + { + "cell_type": "markdown", + "id": "dcf574f0-c9b0-4807-9e1e-27b3ca786cb8", + "metadata": {}, + "source": [ + "## Practice: Life expectancy versus health expenditure\n", + "\n", + "Seaborn includes a repository of [example datasets](https://github.com/mwaskom/seaborn-data) that we can load into a `DataFrame` by calling `sns.load_dataset`. Let's examine the [Life expectancy vs. health expenditure, 1970 to 2015](https://ourworldindata.org/grapher/life-expectancy-vs-health-expenditure?time=earliest..2015) dataset that combines two data sources:\n", + "\n", + "1. The Life expectancy at birth dataset from the [UN World Population Prospects](https://population.un.org/wpp/Download/) (2022): \"For a given year, it represents the average lifespan for a hypothetical group of people, if they experienced the same age-specific death rates throughout their lives as the age-specific death rates seen in that particular year.\"\n", + "1. The Health expenditure (2010 int.-$) dataset from [OECD.stat](https://stats.oecd.org/). \"Per capita health expenditure and financing in OECD countries, measured in 2010 international dollars.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "124d7c48-32e2-4758-9b26-abe3955dde8a", + "metadata": {}, + "outputs": [], + "source": [ + "life_expectancy = sns.load_dataset(\"healthexp\", index_col=[\"Year\", \"Country\"])\n", + "life_expectancy" + ] + }, + { + "cell_type": "markdown", + "id": "0410e17b-20a0-4d21-b187-a3597c89a642", + "metadata": {}, + "source": [ + "Write a `seaborn` expression to create a line plot comparing the `Year` (x-axis) to the `Life_Expectancy` (y-axis) colored with `hue=\"Country\"`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f160bc-6b1a-43e7-9bef-16f0d5af39da", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "7429bf64-f808-44f5-b7a5-fe05cd7efbb1", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "## What makes bad figures bad?\n", + "\n", + "In chapter 1 of *Data Visualization*, Kieran Hiely explains how data visualization is about communication and rhetoric.\n", + "\n", + "> While it is tempting to simply start laying down the law about what works and what doesn't, the process of making a really good or really useful graph cannot be boiled down to a list of simple rules to be followed without exception in all circumstances. The graphs you make are meant to be looked at by someone. The effectiveness of any particular graph is not just a matter of how it looks in the abstract, but also a question of who is looking at it, and why. An image intended for an audience of experts reading a professional journal may not be readily interpretable by the general public. A quick visualization of a dataset you are currently exploring might not be of much use to your peers or your students." + ] + }, + { + "cell_type": "markdown", + "id": "ea1add13-9f55-45fe-b2fb-c56ced8cb5bf", + "metadata": {}, + "source": [ + "### Bad taste\n", + "\n", + "Kieran identifies three problems, the first of which is **bad taste**.\n", + "\n", + "<img style=\"max-width: 100%; max-height: 480px\" alt=\"3-d horizontal bar chart comparing life expectancy across continents with Papyrus font and cute visual style\" src=\"https://socviz.co/assets/ch-01-chartjunk-life-expectancy.png\" />\n", + "\n", + "Kieran draws on Edward Tufte's principles (all quoted from Tufte 1983):\n", + "\n", + "- have a properly chosen format and design\n", + "- use words, numbers, and drawing together\n", + "- display an accessible complexity of detail\n", + "- avoid content-free decoration, including chartjunk\n", + "\n", + "In essence, these principles amount to \"an encouragement to maximize the 'data-to-ink' ratio.\" In practice, our plotting libraries like `seaborn` do a fairly good job of providing defaults that generally follow these principles." + ] + }, + { + "cell_type": "markdown", + "id": "94db5027-751d-4e63-8671-24cc6c047b0f", + "metadata": {}, + "source": [ + "### Bad data\n", + "\n", + "The second problem is **bad data**, which can involve either cherry-picking data or presenting information in a misleading way.\n", + "\n", + "> In November of 2016, *The New York Times* reported on some research on people's confidence in the institutions of democracy. It had been published in an academic journal by the political scientist Yascha Mounk. The headline in the *Times* ran, \"How Stable Are Democracies? ‘Warning Signs Are Flashing Red’†(Taub, 2016). The graph accompanying the article\n", + "\n", + "<img style=\"max-width: 100%; max-height: 480px\" alt=\"6-way line plot comparing Percentage of people who say it is 'essential' to live in a democracy (New York Times)\" src=\"https://socviz.co/assets/ch-01-democracy-nyt-version.png\" />\n", + "\n", + "This plot is one that is well-produced, and that we could reproduce by calling `sns.relplot` like we learned above. The x-axis shows the decade of birth for people all surveyed in the research study.\n", + "\n", + "> [But] scholars who knew the World Values Survey data underlying the graph noticed something else. The graph reads as though people were asked to say whether they thought it was essential to live in a democracy, and the results plotted show the percentage of respondents who said \"Yes\", presumably in contrast to those who said \"No\". But in fact the survey question asked respondents to rate the importance of living in a democracy on a ten point scale, with 1 being \"Not at all Important\" and 10 being \"Absolutely Important\". The graph showed the difference across ages of people who had given a score of \"10\" only, not changes in the average score on the question. As it turns out, while there is some variation by year of birth, most people in these countries tend to rate the importance of living in a democracy very highly, even if they do not all score it as \"Absolutely Important\". The political scientist Erik Voeten redrew the figure based using the average response.\n", + "\n", + "<img style=\"max-width: 100%; max-height: 480px\" alt=\"5-way line plot comparing by Erik Voeten showing Average importance of democracy for each Decade of birth\" src=\"https://socviz.co/assets/ch-01-democracy-voeten-version-2.png\" />" + ] + }, + { + "cell_type": "markdown", + "id": "12156797-f788-4f1d-9020-3a26f197d0fd", + "metadata": {}, + "source": [ + "### Bad perception\n", + "\n", + "The third problem is **bad perception**, which refers to how humans process the information contained in a visualization. Let's walk through section 1.3 on \"[Perception and data visualization](https://socviz.co/lookatdata.html#perception-and-data-visualization)\"." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/groupby-and-indexing.ipynb b/groupby-and-indexing.ipynb index 65df02f49de0988d9c9f92194591c031aa8bcdfb..ec9ed1567a5a2c2f443020522d366bae9c4b5131 100644 --- a/groupby-and-indexing.ipynb +++ b/groupby-and-indexing.ipynb @@ -252,14 +252,6 @@ "magnitudes_per_day.loc[[(2016, 8, 10), (2016, 8, 15)], \"count\"]" ] }, - { - "cell_type": "markdown", - "id": "51f2333a", - "metadata": {}, - "source": [ - "Poll question: what if we want to get all dates after 2016-08-10?" - ] - }, { "cell_type": "code", "execution_count": null, @@ -270,6 +262,14 @@ "magnitudes_per_day.loc[magnitudes_per_day[\"count\"] < 220, \"count\"]" ] }, + { + "cell_type": "markdown", + "id": "51f2333a", + "metadata": {}, + "source": [ + "Poll question: what if we want to get all dates after 2016-08-10?" + ] + }, { "cell_type": "markdown", "id": "cd028cbd-465e-4134-8647-4bed366f37ef", @@ -476,7 +476,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.undefined" } }, "nbformat": 4, diff --git a/pokemon_viz.csv b/pokemon_viz.csv new file mode 100644 index 0000000000000000000000000000000000000000..dba15ea906d26a505429041d30539f8c3f95c7cb --- /dev/null +++ b/pokemon_viz.csv @@ -0,0 +1,152 @@ +Num,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Stage,Legendary +1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,FALSE +2,Ivysaur,Grass,Poison,405,60,62,63,80,80,60,2,FALSE +3,Venusaur,Grass,Poison,525,80,82,83,100,100,80,3,FALSE +4,Charmander,Fire,,309,39,52,43,60,50,65,1,FALSE +5,Charmeleon,Fire,,405,58,64,58,80,65,80,2,FALSE +6,Charizard,Fire,Flying,534,78,84,78,109,85,100,3,FALSE +7,Squirtle,Water,,314,44,48,65,50,64,43,1,FALSE +8,Wartortle,Water,,405,59,63,80,65,80,58,2,FALSE +9,Blastoise,Water,,530,79,83,100,85,105,78,3,FALSE +10,Caterpie,Bug,,195,45,30,35,20,20,45,1,FALSE +11,Metapod,Bug,,205,50,20,55,25,25,30,2,FALSE +12,Butterfree,Bug,Flying,395,60,45,50,90,80,70,3,FALSE +13,Weedle,Bug,Poison,195,40,35,30,20,20,50,1,FALSE +14,Kakuna,Bug,Poison,205,45,25,50,25,25,35,2,FALSE +15,Beedrill,Bug,Poison,395,65,90,40,45,80,75,3,FALSE +16,Pidgey,Normal,Flying,251,40,45,40,35,35,56,1,FALSE +17,Pidgeotto,Normal,Flying,349,63,60,55,50,50,71,2,FALSE +18,Pidgeot,Normal,Flying,479,83,80,75,70,70,101,3,FALSE +19,Rattata,Normal,,253,30,56,35,25,35,72,1,FALSE +20,Raticate,Normal,,413,55,81,60,50,70,97,2,FALSE +21,Spearow,Normal,Flying,262,40,60,30,31,31,70,1,FALSE +22,Fearow,Normal,Flying,442,65,90,65,61,61,100,2,FALSE +23,Ekans,Poison,,288,35,60,44,40,54,55,1,FALSE +24,Arbok,Poison,,438,60,85,69,65,79,80,2,FALSE +25,Pikachu,Electric,,320,35,55,40,50,50,90,1,FALSE +26,Raichu,Electric,,485,60,90,55,90,80,110,2,FALSE +27,Sandshrew,Ground,,300,50,75,85,20,30,40,1,FALSE +28,Sandslash,Ground,,450,75,100,110,45,55,65,2,FALSE +29,NidoranF,Poison,,275,55,47,52,40,40,41,1,FALSE +30,Nidorina,Poison,,365,70,62,67,55,55,56,2,FALSE +31,Nidoqueen,Poison,Ground,505,90,92,87,75,85,76,3,FALSE +32,NidoranM,Poison,,273,46,57,40,40,40,50,1,FALSE +33,Nidorino,Poison,,365,61,72,57,55,55,65,2,FALSE +34,Nidoking,Poison,Ground,505,81,102,77,85,75,85,3,FALSE +35,Clefairy,Fairy,,323,70,45,48,60,65,35,1,FALSE +36,Clefable,Fairy,,483,95,70,73,95,90,60,2,FALSE +37,Vulpix,Fire,,299,38,41,40,50,65,65,1,FALSE +38,Ninetales,Fire,,505,73,76,75,81,100,100,2,FALSE +39,Jigglypuff,Normal,Fairy,270,115,45,20,45,25,20,1,FALSE +40,Wigglytuff,Normal,Fairy,435,140,70,45,85,50,45,2,FALSE +41,Zubat,Poison,Flying,245,40,45,35,30,40,55,1,FALSE +42,Golbat,Poison,Flying,455,75,80,70,65,75,90,2,FALSE +43,Oddish,Grass,Poison,320,45,50,55,75,65,30,1,FALSE +44,Gloom,Grass,Poison,395,60,65,70,85,75,40,2,FALSE +45,Vileplume,Grass,Poison,490,75,80,85,110,90,50,3,FALSE +46,Paras,Bug,Grass,285,35,70,55,45,55,25,1,FALSE +47,Parasect,Bug,Grass,405,60,95,80,60,80,30,2,FALSE +48,Venonat,Bug,Poison,305,60,55,50,40,55,45,1,FALSE +49,Venomoth,Bug,Poison,450,70,65,60,90,75,90,2,FALSE +50,Diglett,Ground,,265,10,55,25,35,45,95,1,FALSE +51,Dugtrio,Ground,,405,35,80,50,50,70,120,2,FALSE +52,Meowth,Normal,,290,40,45,35,40,40,90,1,FALSE +53,Persian,Normal,,440,65,70,60,65,65,115,2,FALSE +54,Psyduck,Water,,320,50,52,48,65,50,55,1,FALSE +55,Golduck,Water,,500,80,82,78,95,80,85,2,FALSE +56,Mankey,Fighting,,305,40,80,35,35,45,70,1,FALSE +57,Primeape,Fighting,,455,65,105,60,60,70,95,2,FALSE +58,Growlithe,Fire,,350,55,70,45,70,50,60,1,FALSE +59,Arcanine,Fire,,555,90,110,80,100,80,95,2,FALSE +60,Poliwag,Water,,300,40,50,40,40,40,90,1,FALSE +61,Poliwhirl,Water,,385,65,65,65,50,50,90,2,FALSE +62,Poliwrath,Water,Fighting,510,90,95,95,70,90,70,3,FALSE +63,Abra,Psychic,,310,25,20,15,105,55,90,1,FALSE +64,Kadabra,Psychic,,400,40,35,30,120,70,105,2,FALSE +65,Alakazam,Psychic,,500,55,50,45,135,95,120,3,FALSE +66,Machop,Fighting,,305,70,80,50,35,35,35,1,FALSE +67,Machoke,Fighting,,405,80,100,70,50,60,45,2,FALSE +68,Machamp,Fighting,,505,90,130,80,65,85,55,3,FALSE +69,Bellsprout,Grass,Poison,300,50,75,35,70,30,40,1,FALSE +70,Weepinbell,Grass,Poison,390,65,90,50,85,45,55,2,FALSE +71,Victreebel,Grass,Poison,490,80,105,65,100,70,70,3,FALSE +72,Tentacool,Water,Poison,335,40,40,35,50,100,70,1,FALSE +73,Tentacruel,Water,Poison,515,80,70,65,80,120,100,2,FALSE +74,Geodude,Rock,Ground,300,40,80,100,30,30,20,1,FALSE +75,Graveler,Rock,Ground,390,55,95,115,45,45,35,2,FALSE +76,Golem,Rock,Ground,495,80,120,130,55,65,45,3,FALSE +77,Ponyta,Fire,,410,50,85,55,65,65,90,1,FALSE +78,Rapidash,Fire,,500,65,100,70,80,80,105,2,FALSE +79,Slowpoke,Water,Psychic,315,90,65,65,40,40,15,1,FALSE +80,Slowbro,Water,Psychic,490,95,75,110,100,80,30,2,FALSE +81,Magnemite,Electric,Steel,325,25,35,70,95,55,45,1,FALSE +82,Magneton,Electric,Steel,465,50,60,95,120,70,70,2,FALSE +83,Farfetch'd,Normal,Flying,352,52,65,55,58,62,60,1,FALSE +84,Doduo,Normal,Flying,310,35,85,45,35,35,75,1,FALSE +85,Dodrio,Normal,Flying,460,60,110,70,60,60,100,2,FALSE +86,Seel,Water,,325,65,45,55,45,70,45,1,FALSE +87,Dewgong,Water,Ice,475,90,70,80,70,95,70,2,FALSE +88,Grimer,Poison,,325,80,80,50,40,50,25,1,FALSE +89,Muk,Poison,,500,105,105,75,65,100,50,2,FALSE +90,Shellder,Water,,305,30,65,100,45,25,40,1,FALSE +91,Cloyster,Water,Ice,525,50,95,180,85,45,70,2,FALSE +92,Gastly,Ghost,Poison,310,30,35,30,100,35,80,1,FALSE +93,Haunter,Ghost,Poison,405,45,50,45,115,55,95,2,FALSE +94,Gengar,Ghost,Poison,500,60,65,60,130,75,110,3,FALSE +95,Onix,Rock,Ground,385,35,45,160,30,45,70,1,FALSE +96,Drowzee,Psychic,,328,60,48,45,43,90,42,1,FALSE +97,Hypno,Psychic,,483,85,73,70,73,115,67,2,FALSE +98,Krabby,Water,,325,30,105,90,25,25,50,1,FALSE +99,Kingler,Water,,475,55,130,115,50,50,75,2,FALSE +100,Voltorb,Electric,,330,40,30,50,55,55,100,1,FALSE +101,Electrode,Electric,,480,60,50,70,80,80,140,2,FALSE +102,Exeggcute,Grass,Psychic,325,60,40,80,60,45,40,1,FALSE +103,Exeggutor,Grass,Psychic,520,95,95,85,125,65,55,2,FALSE +104,Cubone,Ground,,320,50,50,95,40,50,35,1,FALSE +105,Marowak,Ground,,425,60,80,110,50,80,45,2,FALSE +106,Hitmonlee,Fighting,,455,50,120,53,35,110,87,1,FALSE +107,Hitmonchan,Fighting,,455,50,105,79,35,110,76,1,FALSE +108,Lickitung,Normal,,385,90,55,75,60,75,30,1,FALSE +109,Koffing,Poison,,340,40,65,95,60,45,35,1,FALSE +110,Weezing,Poison,,490,65,90,120,85,70,60,2,FALSE +111,Rhyhorn,Ground,Rock,345,80,85,95,30,30,25,1,FALSE +112,Rhydon,Ground,Rock,485,105,130,120,45,45,40,2,FALSE +113,Chansey,Normal,,450,250,5,5,35,105,50,1,FALSE +114,Tangela,Grass,,435,65,55,115,100,40,60,1,FALSE +115,Kangaskhan,Normal,,490,105,95,80,40,80,90,1,FALSE +116,Horsea,Water,,295,30,40,70,70,25,60,1,FALSE +117,Seadra,Water,,440,55,65,95,95,45,85,2,FALSE +118,Goldeen,Water,,320,45,67,60,35,50,63,1,FALSE +119,Seaking,Water,,450,80,92,65,65,80,68,2,FALSE +120,Staryu,Water,,340,30,45,55,70,55,85,1,FALSE +121,Starmie,Water,Psychic,520,60,75,85,100,85,115,2,FALSE +122,Mr. Mime,Psychic,Fairy,460,40,45,65,100,120,90,1,FALSE +123,Scyther,Bug,Flying,500,70,110,80,55,80,105,1,FALSE +124,Jynx,Ice,Psychic,455,65,50,35,115,95,95,1,FALSE +125,Electabuzz,Electric,,490,65,83,57,95,85,105,1,FALSE +126,Magmar,Fire,,495,65,95,57,100,85,93,1,FALSE +127,Pinsir,Bug,,500,65,125,100,55,70,85,1,FALSE +128,Tauros,Normal,,490,75,100,95,40,70,110,1,FALSE +129,Magikarp,Water,,200,20,10,55,15,20,80,1,FALSE +130,Gyarados,Water,Flying,540,95,125,79,60,100,81,2,FALSE +131,Lapras,Water,Ice,535,130,85,80,85,95,60,1,FALSE +132,Ditto,Normal,,288,48,48,48,48,48,48,1,FALSE +133,Eevee,Normal,,325,55,55,50,45,65,55,1,FALSE +134,Vaporeon,Water,,525,130,65,60,110,95,65,2,FALSE +135,Jolteon,Electric,,525,65,65,60,110,95,130,2,FALSE +136,Flareon,Fire,,525,65,130,60,95,110,65,2,FALSE +137,Porygon,Normal,,395,65,60,70,85,75,40,1,FALSE +138,Omanyte,Rock,Water,355,35,40,100,90,55,35,1,FALSE +139,Omastar,Rock,Water,495,70,60,125,115,70,55,2,FALSE +140,Kabuto,Rock,Water,355,30,80,90,55,45,55,1,FALSE +141,Kabutops,Rock,Water,495,60,115,105,65,70,80,2,FALSE +142,Aerodactyl,Rock,Flying,515,80,105,65,60,75,130,1,FALSE +143,Snorlax,Normal,,540,160,110,65,65,110,30,1,FALSE +144,Articuno,Ice,Flying,580,90,85,100,95,125,85,1,TRUE +145,Zapdos,Electric,Flying,580,90,90,85,125,90,100,1,TRUE +146,Moltres,Fire,Flying,580,90,100,90,125,85,90,1,TRUE +147,Dratini,Dragon,,300,41,64,45,50,50,50,1,FALSE +148,Dragonair,Dragon,,420,61,84,65,70,70,70,2,FALSE +149,Dragonite,Dragon,Flying,600,91,134,95,100,100,80,3,FALSE +150,Mewtwo,Psychic,,680,106,110,90,154,90,130,1,TRUE +151,Mew,Psychic,,600,100,100,100,100,100,100,1,FALSE