使用字典中的数据创建 3D 曲面图

Creating 3D surface plot using data from dictionaries

我无法弄清楚如何使用 python 中的 matplotlib 将我的数据转换为曲面图的 X、Y 和 Z 轴。数据来自一个包含 5 个字母单词列表的文件,我的程序运行该文件并计算每个字母在单词的每个位置出现的次数。它存储在 5 个不同的字典中,每个字典对应一个位置。我在想我将不得不使用 .keys() 和 .values() 方法,但我并不肯定。

我进入 excel 并制作图表以显示我正在尝试做的事情的示例。

这是我目前的代码:

import string
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
import numpy as np


#Creates a list of the alphabet in uppercase
alphabet = string.ascii_uppercase
letter_list = list(alphabet)

#Creates dictionary for lettercount. Keys = A-Z, Values = 0 
lettercount = {i: 0 for i in letter_list}

#Creates dictonaries for position frequency. Keys = A-Z, Values = 0 
position1_freq = {i: 0 for i in letter_list}
position2_freq = {i: 0 for i in letter_list}
position3_freq = {i: 0 for i in letter_list}
position4_freq = {i: 0 for i in letter_list}
position5_freq = {i: 0 for i in letter_list}


with open("answers.txt") as f:
    for i in f:
        i = i.rstrip()
        for word in i.split(" "):
            for letter in range(len(word)):
                #Iterates through alphabet
                for j in letter_list:
                    #If the letter in the word = j it will add 1 to lettercount and depending on what value the indicie letter is, 1 will be added to the proper position frequency
                    if word[letter] == j:
                        lettercount[j] += 1
                        if letter == 0:
                            position1_freq[j] += 1

                        if letter == 1:
                            position2_freq[j] += 1

                        if letter == 2:
                            position3_freq[j] += 1

                        if letter == 3:
                            position4_freq[j] += 1

                        if letter == 4:
                            position5_freq[j] += 1

#Sorts the lettercount dictionary to be high to low
sort_lettercount = sorted(lettercount.items(), key = lambda x: x[1], reverse= True)

fig = plt.figure()
ax = plt.axes(projection = '3d')



plt.show()

这是一个完整的例子。我使用了列表和字典理解,因为它们在 python 中很常见(很好习惯!)和标准库中的 Counter class。因此,如果您不习惯,代码可能会有点难以阅读,但这种风格在 python 中很常见,所以我建议学习它而不是使用明确的 for-loops。 Counter 对象是一种字典,因此可以将其视为字典。 :)

我再用.values()。 Counter 上的函数来提取结果。我将它放入一个 numpy 数组中,因为这是 matplotlib 所需要的。

最后,在 matplotlib 中创建 3d 图有点做作。 Matplotlib 不太适合分类数据(例如在 X 轴上有字母),也不太适合带有水平色带的 3d 图(如您的 excel 示例)。

总之,就在这里:

from string import ascii_uppercase
from collections import Counter


# a dictionary with all ascii lettters as keys, and only zeros as values
zero_counts = {c:0 for c in ascii_uppercase}

with open('answers.txt') as f:
    # read the file into a list, remove trailing newlines and make sure all is uppercase
    lines = [line.strip().upper() for line in f.readlines()]

    # transpose the list, so that instead of having N 5-letter words, we now have 5 N-letter words
    list_of_chars_per_pos = zip(*lines)

    # for each of these 5 "words", count the number of occurrances of each letter
    # then add these occurences into a copy of the "zero" dictionary from before
    # so now we have 5 dictionaries holding the count for letter 0,1,2,3 and 4
    char_counts_per_pos = [zero_counts | Counter(chars)  for chars in list_of_chars_per_pos]


# matplotlib only works with numpy data structures, so lets change into that!
import numpy as np
x = np.arange(len(ascii_uppercase)) # the x axis will correspond to the letters
y = np.arange(5)                    # the y axis will be the positions
X,Y = np.meshgrid(x,y)              # create 2D arrays with the X and Y coordinates

# here we extract the  data from the dictionaries using the .values() method
Z = np.array([list(dictionary.values()) for dictionary in char_counts_per_pos])

# now create the plot! create 3d axes on a new figure and draw the plot
# there is quite a bit of customization that can be done to the plot to make it look
# in whatever way you like.
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator, FixedLocator
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
surf= ax.plot_surface(X=X,Y=Y,Z=Z)
ax.xaxis.set_major_locator(FixedLocator(x))
ax.set_xticklabels(ascii_uppercase)
ax.set_box_aspect((26,5,5))
ax.zaxis.set_major_locator(MaxNLocator(integer=True))
ax.set_zlabel("Counts")
ax.set_ylabel("Position")

# finally, show the plot. :)
plt.show()

通过运行把它放在下面的文本文件中answers.txt

abbot
mince
grate
dodos
piggy
baron
party

我明白了