How much does a Nintendo console cost?
It’s been nearly eight years since Nintendo launched their wildly successful Switch console. By most standards, its successor is overdue. While it hasn’t arrived yet, the company has promised to reveal it by the end of their fiscal year (March 31, 2025). An announcement of an announcement, if you will.
Of course people have speculated about the new console’s price. We’ve seen around 30% cumulative inflation since the Switch launched in March 2017, so it’s a safe bet that we’ll see a higher price tag when it arrives (most likely) later this calendar year.
I stumbled onto a Twitter/X post from 2021 that edited inflation-adjusted prices onto a sales flyer from 1995.
It’s remarkable when you stop and think about it—video game MSRPs have hardly budged in 30 years despite all the inflation since then. But that’s true of a lot of consumer electronics. 60-inch TVs, for example, are much more affordable than they were in the 1990s. Development and manufacturing advancements have largely canceled out the dollar’s rising tide.
At least that’s true of video game software (cartridges or discs). Hardware (console) prices have varied a bit more. I think it would be interesting to see how Nintendo consoles prices, from NES to Switch, compare when adjusted for inflation. It’s possible they can help us predict the price of the Switch’s successor.
1. Prepare the data.
I tracked down launch dates and prices from Wikipedia and dropped them into a CSV file. Let’s load it into a pandas DataFrame and take a look.
import pandas as pd df = pd.read_csv("nintendo_consoles_prices.csv", parse_dates=["release_date"]) print(df.head(50))
The output:
console release_date nominal_price 0 NES 1985-10-18 179.00 1 Game Boy 1989-07-31 89.99 2 SNES 1991-08-23 199.00 3 N64 1996-09-29 199.99 4 GBC 1998-11-18 79.95 5 GBA 2001-06-11 99.99 6 Gamecube 2001-11-18 199.00 7 DS 2004-11-21 149.99 8 Wii 2006-11-19 249.99 9 3DS 2011-03-27 249.99 10 Wii U 2012-11-18 299.00 11 Switch 2017-03-03 299.99
The Nintendo Entertainment System might sound like a bargain at $179 but that was a lot of money in 1985! We’ll see later that Nintendo hasn’t charged that much again.
Let’s create a new column with inflation-adjusted modern prices. I like to use Ben Welsh’s cpi library.
The whole process can be done by applying cpi.inflate
. Pass the nominal price, original date, and final date. At the time of this post, November 2024 is the most recent available month, so we’ll use that.
from cpi import inflate from datetime import date df.loc[:, 'nov_2024_price'] = df.apply(lambda row: inflate(row['nominal_price'], row['release_date'], date(2024, 11, 1) ), axis=1)
This new column will be the only variable represented on our plot. My plan is to do a scatter plot with dots stacked vertically. That way we can easily label each console’s dot with horizontal text.
That means every data point will have the same x-coordinate. We’ve already created our y-axis data, so let’s make an x column as well.
df.loc[:, 'x'] = 0
We should also sort the DataFrame by price. Later it will be easier to iterate through rows and label the data.
df = df.sort_values("nov_2024_price", ascending=False)
At this point, df.head(50)
looks like this:
console release_date nominal_price nov_2024_price x 0 NES 1985-10-18 179.00 519.533091 0 2 SNES 1991-08-23 199.00 459.612789 0 10 Wii U 2012-11-18 299.00 409.747186 0 3 N64 1996-09-29 199.99 399.844392 0 8 Wii 2006-11-19 249.99 391.414864 0 11 Switch 2017-03-03 299.99 388.204909 0 6 Gamecube 2001-11-18 199.00 353.907029 0 9 3DS 2011-03-27 249.99 352.938443 0 7 DS 2004-11-21 149.99 247.752854 0 1 Game Boy 1989-07-31 89.99 228.225202 0 5 GBA 2001-06-11 99.99 177.225534 0 4 GBC 1998-11-18 79.95 153.802838 0
Now we can see every console’s price in November 2024 dollars. These prices will define the y-axis and every point will be located at x=0, creating a vertical stack.
We have everything we need. Let’s plot the data.
2. Plot the data.
I’ll use a custom mplstyle meant to emulate Nintendo’s Investor Relations web site. It’s about as interesting as it sounds: a white background, lots of gray, and a few splashes of red.
I usually name my Axes instances ax
, but this plot will have two Axes, so let’s call the first one ax0
.
plt.style.use("wollen_nintendo.mplstyle") fig, ax0 = plt.subplots()
Create the scatter plot on ax0
. Remember our x and y arguments are the columns we created before. Adjust dot size and border.
ax0.scatter(df['x'], df['nov_2024_price'], s=80, edgecolor="#333", linewidth=0.5)
I want a vertical grid line behind the dots but no x-axis labels. It may seem unnecessary but we should set x-limits so that text is spaced correctly within the window.
ax0.set_xticks([0], labels=[]) ax0.set_xlim(-100, 100)
The y-axis is a little more interesting. Each integer value of y_ticks
is replaced by a dollar string in y_tick_labels
. Save the lists as variables because we’ll also place them on the right-hand side of the plot.
y_ticks = range(150, 600, 50) ax0.set_yticks(y_ticks) y_tick_labels = [f"${n}" for n in y_ticks] ax0.set_yticklabels(y_tick_labels) y_tick_range = y_ticks[-1] - y_ticks[0] y_bottom, y_top = y_ticks[0] - y_tick_range * 0.02, y_ticks[-1] + y_tick_range * 0.01 ax0.set_ylim(y_bottom, y_top)
This is where we create a second Axes instance, ax1
, to occupy the right-hand side of the plot. In general it’s a good idea to avoid dual y-axis graphs because they can be confusing, but in this case there is only one data series present. The second axis exists only for symmetry.
Pass the previously defined y_ticks
and y_tick_labels
to the appropriate methods. Hide ax1
grid lines by setting their linewidth
to 0. They’re identical to ax0
grid lines so they can only get in the way.
ax1 = ax0.twinx() ax1.set_yticks(y_ticks) ax1.set_yticklabels(y_tick_labels) ax1.set_ylim(y_bottom, y_top) ax1.grid(which="both", linewidth=0)
Next we want to label each data point. Because the points tend to crowd each other, we can space things out by alternating labels on left and right. I use a bool named align_toggle
to accomplish this. When it’s True, text is placed on the right side. When it’s False, text goes on the left. And the bool switches as we step through each row of the DataFrame. This is why we sorted prices from highest to lowest. If we hadn’t, the alignments would be all over the place.
align_toggle = True for r, row in df.iterrows(): ax0.text(x={True: 5, False: -5}[align_toggle], y=row['nov_2024_price'], s=f"{row['console']} (${row['nominal_price']:.0f}, {row['release_date'].strftime('%b %Y')})", ha={True: "left", False: "right"}[align_toggle], va="center") align_toggle = not align_toggle
Call text
one more time to create a source message at the bottom of the plot.
ax0.text(x=-100, y=y_bottom - y_tick_range * 0.008, s="Console data: Wikipedia\nAdjusted using CPI Inflation Calculator", size=8, ha="left", va="top")
Finally, set a title and save the figure.
ax0.set_title("Nintendo Consoles\nUSA Inflation-Adjusted Launch Price\nNovember 2024 Prices") plt.savefig("nintendo_console_prices.png", dpi=150)
3. The output.
As I mentioned above, Nintendo’s first console, the NES, was its most expensive when adjusted for inflation. Their cheapest was the Game Boy Color, which isn’t surprising because it was a handheld device and an iteration on the original 1989 Game Boy.
So how much will Nintendo’s next console cost? When I look at this plot I notice handheld devices have generally occupied the lower-end $150 to $250 range. And home consoles, while originally priced above $500, have since settled around $400. That includes the Nintendo Switch, which when adjusted for inflation launched at just under $400.
With rumors that the new console will position itself as a more capable piece of hardware than its predecessor, it’s difficult to imagine a less-expensive $300 or $350 price tag. I would expect Nintendo’s next console to be priced at $400. That makes the most sense to me given how they’ve priced consoles in the past.
That is, of course, pure speculation. Its possible that Nintendo will change course and target a lower- or higher-end customer in the next generation.
Full code:
import pandas as pd from cpi import inflate from datetime import date import matplotlib.pyplot as plt df = pd.read_csv("nintendo_consoles_prices.csv", parse_dates=["release_date"]) df.loc[:, 'nov_2024_price'] = df.apply(lambda row: inflate(row['nominal_price'], row['release_date'], date(2024, 11, 1) ), axis=1) df.loc[:, 'x'] = 0 df = df.sort_values("nov_2024_price", ascending=False) print(df.head(50)) plt.style.use("wollen_nintendo.mplstyle") fig, ax0 = plt.subplots() ax0.scatter(df['x'], df['nov_2024_price'], s=80, edgecolor="#333", linewidth=0.5) ax0.set_xticks([0], labels=[]) ax0.set_xlim(-100, 100) y_ticks = range(150, 600, 50) ax0.set_yticks(y_ticks) y_tick_labels = [f"${n}" for n in y_ticks] ax0.set_yticklabels(y_tick_labels) y_tick_range = y_ticks[-1] - y_ticks[0] y_bottom, y_top = y_ticks[0] - y_tick_range * 0.02, y_ticks[-1] + y_tick_range * 0.01 ax0.set_ylim(y_bottom, y_top) ax1 = ax0.twinx() ax1.set_yticks(y_ticks) ax1.set_yticklabels(y_tick_labels) ax1.set_ylim(y_bottom, y_top) ax1.grid(which="both", linewidth=0) align_toggle = True for r, row in df.iterrows(): ax0.text(x={True: 5, False: -5}[align_toggle], y=row['nov_2024_price'], s=f"{row['console']} (${row['nominal_price']:.0f}, {row['release_date'].strftime('%b %Y')})", ha={True: "left", False: "right"}[align_toggle], va="center") align_toggle = not align_toggle ax0.text(x=-100, y=y_bottom - y_tick_range * 0.008, s="Console data: Wikipedia\nAdjusted using CPI Inflation Calculator", size=8, ha="left", va="top") ax0.set_title("Nintendo Consoles\nUSA Inflation-Adjusted Launch Price\nNovember 2024 Prices") plt.savefig("nintendo_console_prices.png", dpi=150)