Monday, 24 June 2024

Web Tutorial: Python Matplotlib Line Chart (Part 2/2)

It's time to render the line chart!

Begin by using the figure() method to determine how large you want the chart to be. I'm going to recommend these proportions.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))


Now, we use the plot() method for line charts. We are going to first plot goals. Remember vals carries information for both goals and appearances. We want only goals right now.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"])


The marker argument defines what the points will look like. We want a circle, so I've input "o".
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o")


Finally, for goals, I want a nice solid scarlet, and that's what we'll have for the color attribute.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))


Finally, we use the show() method to render the chart.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))

  plt.show()


I chose to show the stats for Roberto Firminho, one of the longest-serving players in the menu. Notice that the data is rendered in circular dots and it's a bright red.


Now, we do the same for appearances! Only this time, we'll use a deeper shade of red.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  plt.show()


As you can see here, the scale has changed because the maximum number of appearances is vastly greater than the number of goals. (Still a great goalscorer though!)


Let's add these values to the plot. First, for goals, we want to iterate through the values using a For loop. Since we want to use the index value as well, we will need to use enumerate() on the values.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
  
  plt.show()


Then we use the text() method within the For loop. index determines the horizontal positioning, while value determines the vertical positioning. We'll add 1 to value so that the text won't overlap the dots. The next argument is the value itself, and we need to use str() on it so convert it to a string. Finally, we use the same color we did for plotting the values of the goals.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))
  
  plt.show()


Looks good.


Now we do the same thing for appearances!
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))

  
  plt.show()


I like the look of how things are shaping up!


Next, let's add lines to show average values. Since we have two sets of values, we want them in different colors too. Let's start with the average line for goals. We use the axhline() method for this. We begin by specifying that the y argument is the average of the goals properties in vals, using the namnean() method from numpy.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]))

  plt.show()


And then we make the line a dashed line by passing in "-." as the linestyle argument.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]), linestyle="-.")

  plt.show()


The color argument is obvious - it's the same as the plot color for goals.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]), linestyle="-.", color=(1, 0, 0))

  plt.show()


Nice!


We want to label it, so let's use the text() method. It starts at 0 for the horizontal position. For the vertical position, we want it just about the dashed line, so we use the same value as the dashed line, plus 5. The text will be "GOALS", and of course, we use the same color.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]), linestyle="-.", color=(1, 0, 0))
  plt.text(0, np.nanmean(vals["goals"]) + 5, "GOALS", color=(1, 0, 0))
  
  plt.show()


There it is.


Now, if you need me to elaborate on what you should do for appearances, I'll be terribly disappointed.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]), linestyle="-.", color=(1, 0, 0))
  plt.text(0, np.nanmean(vals["goals"]) + 5, "GOALS", color=(1, 0, 0))
  
  plt.axhline(y=np.nanmean(vals["appearances"]), linestyle="-.", color=(0.5, 0, 0))
  plt.text(0, np.nanmean(vals["appearances"]) + 5, "APPEARANCES", color=(0.5, 0, 0))

  
  plt.show()


We'll be done soon. The hard parts are over.


Now all that's left to do is use xlabel() and title() methods for your chart!
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]), linestyle="-.", color=(1, 0, 0))
  plt.text(0, np.nanmean(vals["goals"]) + 5, "GOALS", color=(1, 0, 0))
  
  plt.axhline(y=np.nanmean(vals["appearances"]), linestyle="-.", color=(0.5, 0, 0))
  plt.text(0, np.nanmean(vals["appearances"]) + 5, "APPEARANCES", color=(0.5, 0, 0))
  
  plt.xlabel("Seasons")
  plt.title("Liverpool FC Player Stats for " + player)

  plt.show()


Let's try it with Salah this time! Uh-oh, looks like the top label overlaps! This can happen if the stats for appearances are fairly consistent, putting the average value near the maximum.


So what we need to do is add this line, to set the highest limit to the max value for appearances, plus a few. This ought to be safe, because, barring some freak statistic, the number of appearances for any player over the course of a season should be significantly higher than the number of goals. Unless it's the kind of player who makes maybe five appearances in one season but scores a hat-trick each time. But this is too much of an anomaly for me to bother with right now.
def lineChart(labels, vals, player):
  plt.figure(figsize = (10, 5))

  plt.ylim(0, max(vals["appearances"]) + 10)
  plt.plot(labels, vals["goals"], marker="o", color=(1, 0, 0))
  plt.plot(labels, vals["appearances"], marker="o", color=(0.5, 0, 0))
  
  for index, value in enumerate(vals["goals"]):
    plt.text(index, value + 1, str(value), color=(1, 0, 0))

  for index, value in enumerate(vals["appearances"]):
    plt.text(index, value + 1, str(value), color=(0.5, 0, 0))
    
  plt.axhline(y=np.nanmean(vals["goals"]), linestyle="-.", color=(1, 0, 0))
  plt.text(0, np.nanmean(vals["goals"]) + 5, "GOALS", color=(1, 0, 0))
  
  plt.axhline(y=np.nanmean(vals["appearances"]), linestyle="-.", color=(0.5, 0, 0))
  plt.text(0, np.nanmean(vals["appearances"]) + 5, "APPEARANCES", color=(0.5, 0, 0))
  
  plt.xlabel("Seasons")
  plt.title("Liverpool FC Player Stats for " + player)
  plt.show()


Here we go.


Well, that was fun...

It's not all that often I do a web tutorial that doesn't involve coding for the web. But when I do, it's really rewarding. The matplotlib library seems pretty basic so far, but it has tons of features I'm itching to explore.

And that's the bottom line!
T___T

No comments:

Post a Comment