Top 10 4K Ultra GPUs for Zwift

Nvidia dominates the top 10 in the GPU performance charts at 4K Ultra for Zwift. Using the Zwiftalizer data, Jupyer notebook, Pandas and Matplotlib, this post shows how to get the top 10 GPUs from the 4K Ultra category that have a minimum frame rate of 60 FPS, then rank them to get the top performers. Nvidia takes the lead. AMD Vega 64 and RX 580 can do 4K Ultra but did not make the top 10 because they did not meet the high bar of a 60 FPS minimum. Feel free to follow along - the data set is publicly accessible. Suggestions and improvements from Python and Pandas experts are very welcome.

Nvidia dominates the top 10

Top 10 4K Ultra 60 FPS GPUs for Zwift - 2019

Import python modules

%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import requests
import json

Load the Zwiftalizer benchmarks raw data

url = ""
data = requests.get(url).json()

Use the 4K Ultra results subset data

# Filter python objects with list comprehensions
dict_4k = [x for x in data['resolutions'] if x['resolution'] == 2160][0]
dict_4k_ultra = [x for x in dict_4k['profiles'] if x['profileId'] == 3][0]

Create a dataframe of the results using systemId as the index

df = pd.DataFrame(dict_4k_ultra['results'], columns=['systemId','minFps','avgFps','samples'])

Get the GPU model by splitting the systemId on / and take the 3rd token (index 2)

df[['gpu']] = df.systemId.str.split(' / ', expand=True)[[2]]

Use this new GPU column as the new index (for x axis) and delete the systemId column

df.index = df['gpu']
df = df.drop(['systemId', 'gpu'], axis=1)
# check how it looks so far by printing the head of the dataframe
# df.head()

Filter where min FPS >= 60 and number of logs collected >= 4

Filter out all the entries where the minimum FPS is less than sixty. This is a high bar. Often a high end GPU will be paired with an old CPU which can be a bottleneck and misrepresent the GPU performance. Also filter out all the systems with fewer than 4 log samples. Delete minFps and samples columns after filtering because we don’t want them in the plot.

min_fps_filter = df['minFps'] >= 60
min_samples_filter = df['samples'] >= 4
df_filtered = df[min_fps_filter & min_samples_filter]
df_filtered = df_filtered.drop(['minFps','samples'], axis=1)

Group by gpu name, get mean FPS, print the top 10

gpu_leaders = df_filtered.groupby('gpu').agg({'avgFps':'mean'}).reset_index()
gpu_leaders.index = gpu_leaders['gpu']
gpu_leaders_sorted = gpu_leaders.sort_values(by='avgFps', ascending=False)

Plot the top 10

gpu_leaders.sort_values(by='avgFps', ascending=True).plot(kind='barh', figsize=(14, 10))
plt.xlabel('Average FPS', size = 30)
plt.xticks(size = 30)
plt.ylabel('', size = 1)
plt.yticks(size = 20)
plt.title('Top 10 4K Ultra GPUs for Zwift', size = 30)



For Zwifting with a 4K Ultra large screen TV it is not really necessary to have an FPS higher than 60, but it is good to have extra headroom for situations like large group rides. The Turing generation Nvidia GPUs (20xx) are top of the pile, as expected. The previous generation top model 1080 Ti is neck and neck with the new generation lowest model RTX 2060. The best performance for price is the GTX 1660 sitting close to the previous generation 1070, and only slightly behind the two generations older top of the line 980 Ti. GTX 1660 is Turing without the real time ray tracing.

For reference, the Nvidia model numbers are now screwed up. It used to be this - first number represents the generation - 4xx, 5xx, 6xx, 7xx, (8xx mobile), 9xx, 10xx, 20xx. Last two numbers represent the spec level x60, x70, x80. The new Turing 16xx code is higher than 10xx but lower than 20xx.

Watch out for a follow up post where I’ll get the top GPUs for 1080 Ultra and find some gems in the 1080 High and Medium profile categories with budget performance that might surprise you.

Search Amazon for NVidia GPUs

Mike Hanney