Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
253 views
in Technique[技术] by (71.8m points)

python - Weird "demonic" xtick in matplotlib (jpeg artifacts? No way...)

So I'm comparing NBA betting lines between different sportsbooks over time

Procedure:

  1. Open pickle file of scraped data
  2. Plot the scraped data

The pickle file is a dictionary of NBA betting lines over time. Each of the two teams are their own nested dictionary. Each key in these team-specific dictionaries represents a different sportsbook. The values for these sportsbook keys are lists of tuples, representing timeseries data. It looks roughly like this:

dicto = {
'Time': <time that the game starts>,

'Team1': {

     Market1: [ (time1, value1), (time2, value2), etc...],

     Market2: [ (time1, value1), (time2, value2), etc...],
    
     etc...

          }

'Team2': {
     <SAME FORM AS TEAM1>
          }

}

There are no issues with scraping or manipulating this data. The issue comes when I plot it. Here is the code for the script that unpickles and plots these dictionaries:

import matplotlib.pyplot as plt
import pickle, datetime, os, time, re
IMAGEPATH = 'Images'
reg = re.compile(r'[A-Z]+@[A-Z]+[0-9|-]+')
noDate = re.compile(r'[A-Z]+@[A-Z]+')

# Turn 1 into '01'
def zeroPad(num):
    if num < 10:
        return '0' + str(num)
    else:
        return num

# Turn list of time-series tuples into an x list and y list
def unzip(lst):
    x = []
    y = []
    for i in lst:
        x.append(f'{i[0].hour}:{zeroPad(i[0].minute)}')
        y.append(i[1])
    return x, y

# Make exactly 5, evenly spaced xticks
def prune(xticks):
    last = len(xticks) 
    first = 0
    mid = int(len(xticks) / 2) - 1 
    upMid = int( mid + (last - mid) / 2) 
    downMid = int( (mid - first) / 2) 

    out = []
    count = 0
    for i in xticks:
        if count in [last, first, mid, upMid, downMid]:
            out.append(i)
        else:
            out.append('')
        count += 1
    return out

def plot(filename, choice):
    IMAGEPATH = 'Images'
    IMAGEPATH = os.path.join(IMAGEPATH, choice)
    with open(filename, 'rb') as pik:
        dicto = pickle.load(pik)

    fig, axs = plt.subplots(2)
    gameID = noDate.search(filename).group(0)
    tm = dicto['Time']
    fig.suptitle(gameID + '
' + str(tm))
    i = 0
    for team in dicto.keys():
        axs[i].set_title(team)
        if team == 'Time':
            continue
        for market in dicto[team].keys():
            lst = dicto[team][market]
            x, y = unzip(lst)
            axs[i].plot(x, y, label= market)
            
            axs[i].set_xticks(prune(x))
            axs[i].set_xticklabels(rotation=45, labels = x)
       
        i += 1  

    plt.tight_layout()

    #Finish
    outputFile = reg.search(filename).group(0)
    
    date = (datetime.datetime.today() - datetime.timedelta(hours = 6)).date()
    
    fig.savefig(os.path.join(IMAGEPATH, str(date), f'{outputFile}.png'))

    plt.close()

Here is the image that results from calling the plot function on one of the dictionaries that I described above. It is pretty much exactly as I intended it, except for one very strange and bothersome problem.

Here

You will notice that the bottom right tick looks haunted, demonic, jpeggy, whatever you want to call it. I am highly suspicious that this problem occurs in the prune function, which I use to set the xtick values of the plot.

The reason that I prune the values with a function like this is because these dictionaries are continuously updated, so setting a static number of xticks would not work. And if I don't prune the xticks, they end up becoming unreadable due to overlapping one another.

I am quite confused as to what could cause an xtick to look like this. It happens consistently, for every dictionary, every time. Before I added the prune function (when the xticks unbound, overlapping one another), this issue did not occur. So when I say I'm suspicious that the prune function is the cause, I am really quite certain.

I will be happy to share an instance of one of these dictionaries, but they are saved as .pickle files, and I'm pretty sure it's bad practice to share pickle files over the internet. I have been warned about potential malware, so I'll just stay away from that. But if you need to see the dictionary, I can take the time to prettily print one and share a screenshot. Any help is greatly appreciated!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Matplotlib does this when there are many xticks or yticks which are plotted on the same value. It is normal. If you can limit the number of times the specific value is plotted - you can make it appear indistinguishable from the rest of the xticks.

Plot a simple example to test this out and you will see for yourself.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...