{"id":3520,"date":"2026-09-03T07:00:32","date_gmt":"2026-09-03T12:00:32","guid":{"rendered":"https:\/\/wollen.org\/blog\/?p=3520"},"modified":"2026-09-03T06:00:55","modified_gmt":"2026-09-03T11:00:55","slug":"the-golden-age-of-kicking","status":"publish","type":"post","link":"https:\/\/wollen.org\/blog\/2026\/09\/the-golden-age-of-kicking\/","title":{"rendered":"The golden age of kicking"},"content":{"rendered":"<p style=\"text-align: left;\">You might have seen Cam Little&#8217;s NFL-record 68-yard field goal last November. It seems like every few weeks there&#8217;s a new guy on the scene looking like the greatest kicker of all time.<\/p>\n<p><iframe loading=\"lazy\" title=\"Jaguars&amp;apos; Cam Little BREAKS NFL RECORD with 68-yard Field Goal vs. Raiders \ud83e\udd2f\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/5fRpwtdxH6k?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>My theory is that we&#8217;re currently in a fleeting <em>golden age<\/em> of NFL field goal kicking. And like an old-fashioned fable, kickers&#8217; success will beget their downfall. The league will soon rebalance their rules to limit kickers&#8217; effectiveness.<\/p>\n<p>Why would the NFL want to slow them down? It&#8217;s a fair question. They have made a <em>lot<\/em> of changes in recent years to encourage scoring. But with touchbacks now spotting the ball at the 35 yard line and midfield marking the edge of field goal range, it&#8217;s become a little <em>too<\/em> easy to put together a quick scoring drive. I think it&#8217;s embarrassing for the league when points come off 15 or 20 yards of offense and a kick\u2014especially because those drives tend to happen late in the 4th quarter in high-stakes moments which are then shared on social media with millions of additional eyeballs. I predict that ultimately the NFL will prefer slightly less scoring to being public embarrassed.<\/p>\n<p>How might they nerf field goals? A few ideas&#8230;<\/p>\n<ul>\n<li><strong>Easiest:<\/strong> Change kicking balls. Either force kickers to use the same ball as the offense or increase kicking balls&#8217; air pressure. This would have the advantage of hiding the rule change from casual viewers.<\/li>\n<li><strong>Maybe:<\/strong> On the other hand, narrowing field goal uprights or raising the crossbar would be visually obvious and draw a lot of attention.<\/li>\n<li><strong>Least likely:<\/strong> Give kickers fewer opportunities. Change kickoff\/touchback rules and move starting field position further back. I would be surprised if they went this route after putting so much effort into encouraging kick returns. That phase of special teams is genuinely more exciting than it was a few years ago.<\/li>\n<\/ul>\n<p>Admittedly, this is all idle speculation. Let&#8217;s go back to the beginning and verify that NFL kickers are, at least in terms of top-end range, getting significantly better.<\/p>\n<hr \/>\n<h4>1. Acquire the data.<\/h4>\n<p>We can start with the <a href=\"https:\/\/en.wikipedia.org\/wiki\/List_of_longest_NFL_field_goals\" target=\"_blank\" rel=\"noopener\">Wikipedia page<\/a> for longest NFL field goals. It lists all 60+ yard performances since the merger. On the blog I usually work with a clean dataset and gloss over the (often tedious) details of where the data came from. Since scraping Wikipedia is relatively easy, let&#8217;s step through it.<\/p>\n<p><strong>Disclaimer: the web page may change in the future and break this code!<\/strong><\/p>\n<p>The data is organized in tables, which is ideal because pandas&#8217; <code>read_html<\/code> method is very good at pulling HTML tables into a DataFrame.<\/p>\n<p>We catch another break as the tables are <em>not<\/em> loaded dynamically with Javascript. They render the old-fashioned way with HTML. Therefore we can use Python&#8217;s straightforward <a href=\"https:\/\/pypi.org\/project\/requests\/\" target=\"_blank\" rel=\"noopener\">requests library<\/a> to download the page.<\/p>\n<p>Wikipedia doesn&#8217;t mind scraping as long as we&#8217;re respectful and identify ourselves in headers. Today let&#8217;s be <em>KickerBot 1.0<\/em>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import requests\r\n\r\nurl = \"https:\/\/en.wikipedia.org\/wiki\/List_of_longest_NFL_field_goals\"\r\n\r\nheaders = {\"User-Agent\": \"KickerBot\/1.0\"}\r\n\r\ntext = requests.get(url, headers=headers).text\r\n\r\nwith open(\"response.txt\", \"w\") as f:\r\n    f.write(text)<\/pre>\n<p>It&#8217;s important to save the response locally and avoid sending repeated HTTP requests. If you were doing this for real you would need to run the script several times to get everything working correctly. Just comment out the request and file write once the page is saved to disk.<\/p>\n<p>Open the file and feed it into <code>pandas.read_html<\/code>. Pandas expects a StringIO type rather than a plain string. It then returns a list of DataFrames. Easy, right?<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import pandas as pd\r\n\r\nwith open(\"response.txt\", \"r\") as f:\r\n    text = f.read()\r\n\r\ndfs_found = pd.read_html(StringIO(text))<\/pre>\n<p>If you check <code>len(dfs_found)<\/code> you&#8217;ll see we extracted 13 DataFrames. The main table that we want is at the top of the web page so unsurprisingly it&#8217;s the first element of the list, i.e. <code>dfs_found[0]<\/code>.<\/p>\n<p><code>dfs_found[0].head()<\/code> is shown below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">   Distance            Kicker  ...            Elevation                  Weather\r\n0  68 yards        Cam Little  ...  2,184 ft (666 m)[7]                     Dome\r\n1  67 yards        Cam Little  ...         4 ft (1.2 m)            58 \u00b0F (14 \u00b0C)\r\n2  66 yards     Justin Tucker  ...    601 ft (183 m)[9]                     Dome\r\n3  65 yards    Brandon Aubrey  ...       584 ft (179 m)  Retractable roof closed\r\n4  65 yards  Chase McLaughlin  ...         35 ft (11 m)            93 \u00b0F (34 \u00b0C)<\/pre>\n<p>We still have a little work to do. Distance column values are string types. We need to strip out the &#8220;yards&#8221; text and convert to integers. We can drop most of the columns as their information is irrelevant.<\/p>\n<p>Assign this first-element DataFrame to its own variable, <code>df<\/code>, and limit it to the three relevant columns. It&#8217;s good practice to <code>copy<\/code> the sliced DataFrame before operating further. If you don&#8217;t, Pandas will let you know.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df = dfs_found[0][['Distance', 'Date', 'Kicker']].copy()\r\n\r\nprint(df.head())<\/pre>\n<p>The output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">   Distance                Date            Kicker\r\n0  68 yards    November 2, 2025        Cam Little\r\n1  67 yards     January 4, 2026        Cam Little\r\n2  66 yards  September 26, 2021     Justin Tucker\r\n3  65 yards  September 22, 2024    Brandon Aubrey\r\n4  65 yards  September 28, 2025  Chase McLaughlin<\/pre>\n<p>That&#8217;s a little better. Now we can see that Date is a string type as well. Let&#8217;s convert it to datetime while also parsing the Distance column.<\/p>\n<p>The pandas <code>str<\/code> accessor allows us to use most string methods from base Python.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df['Date'] = pd.to_datetime(df['Date'])\r\n\r\ndf['Distance'] = df['Distance'].str.strip(\" yards\").astype(int)\r\n\r\nprint(df.head())<\/pre>\n<p>The output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">   Distance       Date            Kicker\r\n0        68 2025-11-02        Cam Little\r\n1        67 2026-01-04        Cam Little\r\n2        66 2021-09-26     Justin Tucker\r\n3        65 2024-09-22    Brandon Aubrey\r\n4        65 2025-09-28  Chase McLaughlin<\/pre>\n<p>We&#8217;ve successfully scraped everything we need! Technically we don&#8217;t need kickers&#8217; names but it feels wrong to erase them.<\/p>\n<p>Save the DataFrame to a CSV file. Set <code>index=False<\/code> to exclude the useless index column.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df.to_csv(\"nfl_fgs_2026-09-03.csv\", index=False)<\/pre>\n<hr \/>\n<h4>2. Prepare the data.<\/h4>\n<p>Read the dataset into a pandas DataFrame. We&#8217;ll be using a datetime x-axis so make sure the Date column is the correct type.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df = pd.read_csv(\"nfl_fgs_2026-09-03.csv\", parse_dates=['Date'])<\/pre>\n<p>The plan is to create two vertically stacked subplots like below. On top will be a scatter plot of individual field goals. On bottom a histogram, which is essentially a bar plot displaying the total number of 60+ yard field goals per season.<\/p>\n<p><a href=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/subplot_diagram.png\">\u00a0<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3532\" src=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/subplot_diagram.png\" alt=\"\" width=\"650\" height=\"450\" srcset=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/subplot_diagram.png 650w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/subplot_diagram-300x208.png 300w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/a><\/p>\n<p>I always try to match x-axes between vertically stacked subplots. It&#8217;s important for readability at first glance. In this case it&#8217;s not really possible because the scatter plot will use datetimes while the histogram will use annual integers.<\/p>\n<p>To resolve this, let&#8217;s treat the histogram x-axis like a datetime axis but locate every bar on January 1st. That way we can easily align the two x-axes.<\/p>\n<p>NFL seasons extend into January and February so, for example, the 2010 season includes dates in January 2011. We can solve this by subtracting 90 days from every date and checking the resulting year. Do this operation and generate a Season column.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df['Season'] = (df['Date'] - pd.Timedelta(\"90 days\")).dt.strftime(\"%Y\").astype(int)<\/pre>\n<p>We have an integer Season column but we want bars on January 1st of each year. Use the Season column to create a datetime Season_x column. This is what we&#8217;ll use for plotting.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df['Season_x'] = df['Season'].apply(lambda x: pd.Timestamp(f\"January 1 {x}\"))<\/pre>\n<p><code>df.head()<\/code> looks like this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">   Distance       Date            Kicker  Season   Season_x\r\n0        68 2025-11-02        Cam Little    2025 2025-01-01\r\n1        67 2026-01-04        Cam Little    2025 2025-01-01\r\n2        66 2021-09-26     Justin Tucker    2021 2021-01-01\r\n3        65 2024-09-22    Brandon Aubrey    2024 2024-01-01\r\n4        65 2025-09-28  Chase McLaughlin    2025 2025-01-01<\/pre>\n<p>That looks great. Now we need to <code>groupby<\/code> season and <code>count<\/code> how many rows exist per year. The <code>reset_index()<\/code> addition isn&#8217;t required but it will make addressing columns a little more intuitive.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df2 = df.groupby(\"Season_x\")['Distance'].agg(\"count\").reset_index()\r\n\r\nprint(df2.tail())<\/pre>\n<p>The new DataFrame is below. You could rename &#8220;Distance&#8221; to &#8220;count&#8221; or similar but this will suffice.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">     Season_x  Distance\r\n16 2021-01-01         3\r\n17 2022-01-01         5\r\n18 2023-01-01         4\r\n19 2024-01-01         4\r\n20 2025-01-01        12<\/pre>\n<p>We&#8217;ll use <code>df2<\/code> to build our histogram. Bars will be located at January 1st of each year and the corresponding value will be their height.<\/p>\n<hr \/>\n<h4>3. Plot the data.<\/h4>\n<p>I&#8217;ll use a custom Matplotlib style that will be linked at the bottom of this post.<\/p>\n<p>Create a 2&#215;1 subplot grid and specify <code>height_ratios<\/code> so the lower histogram is smaller. We can refer to the Axes as <code>ax0<\/code> (upper) and <code>ax1<\/code> (lower).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import matplotlib.pyplot as plt\r\n\r\nplt.style.use(\"wollen_nfl.mplstyle\")\r\n\r\nfig, (ax0, ax1) = plt.subplots(nrows=2,\r\n                               ncols=1,\r\n                               height_ratios=(4, 1))<\/pre>\n<p>Use the main DataFrame <code>df<\/code> to construct the scatter plot. Each little dot will represent one 60+ yard field goal.<\/p>\n<p>I like to dial up the transparency (<code>alpha<\/code>) on plots like this where markers are likely to overlap.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">edge_color = \"#333\"\r\nedge_width = 0.8\r\nalpha = 0.8\r\n\r\nax0.scatter(df['Date'],\r\n            df['Distance'],\r\n            color=\"#D50A0A\",\r\n            edgecolor=edge_color,\r\n            linewidth=edge_width,\r\n            alpha=alpha)<\/pre>\n<p>Construct the histogram using <code>df2<\/code>. This is the DataFrame we created using <code>groupby<\/code> with each season located at January 1st. Scatter markers will be on top and these bars will represent how many markers fall into each year&#8217;s bucket.<\/p>\n<p>I&#8217;ve used an NFL red and blue color scheme.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ax1.bar(df2['Season_x'],\r\n        df2['Distance'],\r\n        width=250,\r\n        color=\"#013369\",\r\n        edgecolor=edge_color,\r\n        linewidth=edge_width,\r\n        alpha=alpha)<\/pre>\n<p>Tom Dempsey kicked the first 60+ field goal way back in 1970. That would be a lot of x-ticks so let&#8217;s mark every two years instead.<\/p>\n<p><code>pd.date_range<\/code> returns a list of regularly spaced datetimes. Yes, year values have to be passed as strings, not integers. It&#8217;s because you could also pass &#8220;July 15, 1970&#8221; or any arbitrary date.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">x_ticks = pd.date_range(start=\"1970\",\r\n                        end=\"2026\",\r\n                        freq=\"2YS\")\r\n\r\nx_tick_labels = [item.strftime(\"%Y\") for item in x_ticks]\r\n\r\nx_limits = (pd.Timestamp(\"Jan 1 1969\"), pd.Timestamp(\"Jan 1 2027\"))<\/pre>\n<p>Pass x- and y-tick values into <code>set()<\/code> methods for <code>ax0<\/code> and <code>ax1<\/code> respectively. Notice we&#8217;re using the same values for both x-axes. It&#8217;s important that dates line up to avoid confusing the viewer.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ax0.set(xticks=x_ticks,\r\n        xticklabels=x_tick_labels,\r\n        xlim=x_limits,\r\n        yticks=range(60, 69),\r\n        ylim=(59.7, 68.2),\r\n        ylabel=\"Yards\",\r\n        title=\"NFL  |  60+ Yard Field Goals\")\r\n\r\nax1.set(xticks=x_ticks,\r\n        xticklabels=x_tick_labels,\r\n        xlim=x_limits,\r\n        yticks=range(0, 20, 5),\r\n        ylim=(0, 15.5),\r\n        ylabel=\"Count\")<\/pre>\n<p>We have 29 x-tick labels so let&#8217;s help them fit by rotating them 60\u00b0.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">for ax in [ax0, ax1]:\r\n    plt.setp(ax.xaxis.get_majorticklabels(),\r\n             rotation=60,\r\n             horizontalalignment=\"right\",\r\n             rotation_mode=\"anchor\")<\/pre>\n<p>Use <code>text()<\/code> to cite Wikipedia in the upper-left corner of <code>ax1<\/code>. When drawing text on a plot I like to define a <code>bbox<\/code>, which functions like a solid or semi-transparent text background. It&#8217;s a subtle detail that greatly aids text readability.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ax1.text(x=pd.Timestamp(\"April 1 1970\"),\r\n         y=14.5,\r\n         s=\"Data: https:\/\/en.wikipedia.org\/wiki\/List_of_longest_NFL_field_goals\",\r\n         size=8,\r\n         horizontalalignment=\"left\",\r\n         verticalalignment=\"top\",\r\n         bbox={\"facecolor\": \"white\", \"edgecolor\": \"None\", \"pad\": 0})<\/pre>\n<p>Because 60+ field goals became more common in recent years, the left side of the scatter plot is mostly blank. Let&#8217;s fill the empty space with a large NFL logo. Give it low <code>alpha<\/code> so it will appear almost like a watermark.<\/p>\n<p>The <code>box_alignment<\/code> tuple defines (x, y) alignment. (0, 1) means the image&#8217;s top-left corner will fall at the specified coordinates.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from matplotlib.offsetbox import OffsetImage, AnnotationBbox\r\n\r\nab = AnnotationBbox(OffsetImage(plt.imread(\"nfl_logo.png\"),\r\n                                zoom=0.27,\r\n                                alpha=0.03),\r\n                    xy=(pd.Timestamp(\"July 1 1970\"), 67.9),\r\n                    box_alignment=(0, 1),\r\n                    frameon=False)\r\n\r\nax0.add_artist(ab)<\/pre>\n<p>Finally, save the figure with a bumped-up <code>dpi<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">plt.savefig(\"nfl_field_goals.png\", dpi=200)<\/pre>\n<hr \/>\n<h4>4. The output.<\/h4>\n<p><a href=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-scaled.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3537\" src=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-scaled.png\" alt=\"\" width=\"2560\" height=\"1772\" srcset=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-scaled.png 2560w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-300x208.png 300w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-1024x709.png 1024w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-768x532.png 768w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-1536x1063.png 1536w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/09\/nfl_field_goals-2048x1418.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<p>I like the dashed grid lines. They aren&#8217;t something I usually go for but they somehow remind me of football field markings.<\/p>\n<p>We can see that 60+ yard field goals started becoming more common in the late 2000s and took off beginning in 2021. Then 2025 was a total blowout, tripling the previous year.<\/p>\n<p>And it wasn&#8217;t just one guy making all these kicks. Cam Little set the NFL record of 68 yards but 9 different guys contributed to the total of 12 kicks last year.<\/p>\n<p>Maybe there will be some mean reversion this upcoming season and we&#8217;ll only see half as many bombs. Even then, no one could deny we&#8217;ve entered a <em>golden age<\/em> of field goal kicking. Enjoy it while it lasts.<!-- HFCM by 99 Robots - Snippet # 15: endmark-python -->\n<span class=\"endmark-python\"><\/span>\n<!-- \/end HFCM by 99 Robots -->\n<\/p>\n<hr \/>\n<p><a href=\"https:\/\/wollen.org\/misc\/nfl_kicking_2026.zip\"><strong>Download the data.<\/strong><\/a><\/p>\n<p><strong>Full code:<\/strong><\/p>\n<p style=\"text-align: center;\"><em>scrape_data.py<\/em><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import requests\r\nfrom io import StringIO\r\nimport pandas as pd\r\n\r\n\r\nurl = \"https:\/\/en.wikipedia.org\/wiki\/List_of_longest_NFL_field_goals\"\r\n\r\nheaders = {\"User-Agent\": \"KickerBot\/1.0\"}\r\n\r\ntext = requests.get(url, headers=headers).text\r\n\r\nwith open(\"response.txt\", \"w\") as f:\r\n    f.write(text)\r\n\r\nwith open(\"response.txt\", \"r\") as f:\r\n    text = f.read()\r\n\r\ndfs_found = pd.read_html(StringIO(text))\r\n\r\ndf = dfs_found[0][['Distance', 'Date', 'Kicker']].copy()\r\n\r\ndf['Date'] = pd.to_datetime(df['Date'])\r\n\r\ndf['Distance'] = df['Distance'].str.strip(\" yards\").astype(int)\r\n\r\ndf.to_csv(\"nfl_fgs_2026-09-03.csv\", index=False)<\/pre>\n<hr style=\"width: 50%;\" \/>\n<p style=\"text-align: center;\"><em>plot_data.py<\/em><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import pandas as pd\r\nimport matplotlib.pyplot as plt\r\nfrom matplotlib.offsetbox import OffsetImage, AnnotationBbox\r\n\r\n\r\ndf = pd.read_csv(\"nfl_fgs_2026-09-03.csv\", parse_dates=['Date'])\r\n\r\ndf['Season'] = (df['Date'] - pd.Timedelta(\"90 days\")).dt.strftime(\"%Y\").astype(int)\r\n\r\ndf['Season_x'] = df['Season'].apply(lambda x: pd.Timestamp(f\"January 1 {x}\"))\r\n\r\ndf2 = df.groupby(\"Season_x\")['Distance'].agg(\"count\").reset_index()\r\n\r\nplt.style.use(\"wollen_nfl.mplstyle\")\r\n\r\nfig, (ax0, ax1) = plt.subplots(nrows=2,\r\n                               ncols=1,\r\n                               height_ratios=(4, 1))\r\n\r\nedge_color = \"#333\"\r\nedge_width = 0.8\r\nalpha = 0.8\r\n\r\nax0.scatter(df['Date'],\r\n            df['Distance'],\r\n            color=\"#D50A0A\",\r\n            edgecolor=edge_color,\r\n            linewidth=edge_width,\r\n            alpha=alpha)\r\n\r\nax1.bar(df2['Season_x'],\r\n        df2['Distance'],\r\n        width=250,\r\n        color=\"#013369\",\r\n        edgecolor=edge_color,\r\n        linewidth=edge_width,\r\n        alpha=alpha)\r\n\r\nx_ticks = pd.date_range(start=\"1970\",\r\n                        end=\"2026\",\r\n                        freq=\"2YS\")\r\n\r\nx_tick_labels = [item.strftime(\"%Y\") for item in x_ticks]\r\n\r\nx_limits = (pd.Timestamp(\"Jan 1 1969\"), pd.Timestamp(\"Jan 1 2027\"))\r\n\r\nax0.set(xticks=x_ticks,\r\n        xticklabels=x_tick_labels,\r\n        xlim=x_limits,\r\n        yticks=range(60, 69),\r\n        ylim=(59.7, 68.2),\r\n        ylabel=\"Yards\",\r\n        title=\"NFL  |  60+ Yard Field Goals\")\r\n\r\nax1.set(xticks=x_ticks,\r\n        xticklabels=x_tick_labels,\r\n        xlim=x_limits,\r\n        yticks=range(0, 20, 5),\r\n        ylim=(0, 15.5),\r\n        ylabel=\"Count\")\r\n\r\nfor ax in [ax0, ax1]:\r\n    plt.setp(ax.xaxis.get_majorticklabels(),\r\n             rotation=60,\r\n             horizontalalignment=\"right\",\r\n             rotation_mode=\"anchor\")\r\n\r\nax1.text(x=pd.Timestamp(\"April 1 1970\"),\r\n         y=14.5,\r\n         s=\"Data: https:\/\/en.wikipedia.org\/wiki\/List_of_longest_NFL_field_goals\",\r\n         size=8,\r\n         horizontalalignment=\"left\",\r\n         verticalalignment=\"top\",\r\n         bbox={\"facecolor\": \"white\", \"edgecolor\": \"None\", \"pad\": 0})\r\n\r\nab = AnnotationBbox(OffsetImage(plt.imread(\"nfl_logo.png\"),\r\n                                zoom=0.27,\r\n                                alpha=0.03),\r\n                    xy=(pd.Timestamp(\"July 1 1970\"), 67.9),\r\n                    box_alignment=(0, 1),\r\n                    frameon=False)\r\n\r\nax0.add_artist(ab)\r\n\r\nplt.savefig(\"nfl_field_goals.png\", dpi=200)<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You might have seen Cam Little&#8217;s NFL-record 68-yard field goal last November. It seems like every few weeks there&#8217;s a new guy on the scene looking like the greatest kicker of all time. My theory is that we&#8217;re currently in<\/p>\n","protected":false},"author":1,"featured_media":3524,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[59],"tags":[705,704,702,22,122,120,56,38,700,701,24,126,119,30,161,698,326,201,703,699],"class_list":["post-3520","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sports","tag-68-yards","tag-brandon-aubrey","tag-cam-little","tag-data","tag-dataset","tag-football","tag-groupby","tag-histogram","tag-kickers","tag-kicking","tag-matplotlib","tag-mplstyle","tag-nfl","tag-pandas","tag-record","tag-requests","tag-rules","tag-scatter","tag-tom-dempsey","tag-wikipedia"],"_links":{"self":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts\/3520","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/comments?post=3520"}],"version-history":[{"count":27,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts\/3520\/revisions"}],"predecessor-version":[{"id":3552,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts\/3520\/revisions\/3552"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/media\/3524"}],"wp:attachment":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/media?parent=3520"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/categories?post=3520"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/tags?post=3520"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}