This week I learnt — how to add “$” to ticks on matplotlib graphs
Please examine Kaggle’s Python exercise 7 to try this yourself.
This week I completed Kaggle’s python exercise 7. In that exercise, there was a simple but interesting challenge of adding “$” to the y-axis ticks on a matplotlib graph. And this post is my documentation of my process.
Setup
Here’s the question from Kaggle:
After completing the exercises on lists and tuples, Jimmy noticed that, according to his
estimate_average_slot_payout
function, the slot machines at the Learn Python Casino are actually rigged against the house, and are profitable to play in the long run.Starting with $200 in his pocket, Jimmy has played the slots 500 times, recording his new balance in a list after each spin. He used Python’s
matplotlib
library to make a graph of his balance over time:
# Import the jimmy_slots submodule
from learntools.python import jimmy_slots
# Call the get_graph() function to get Jimmy's graph
graph = jimmy_slots.get_graph()
graph
Tasks
The tasks were to start the y-axis from 0, label the y-axis and add a title to the graph.
def prettify_graph(graph):
"""Modify the given graph according to Jimmy's requests:
add a title, make the y-axis
start at 0, label the y-axis.
(And, if you're feeling ambitious, format the tick marks as
dollar amounts using the "$" symbol.)
""" # Complete steps 2 and 3 heregraph = jimmy_slots.get_graph()
prettify_graph(graph)
graph
All three were easily done by adding three functions found in the directory:
def prettify_graph(graph):
"""Modify the given graph according to Jimmy's requests:
add a title, make the y-axis
start at 0, label the y-axis.
(And, if you're feeling ambitious, format the tick marks as
dollar amounts using the "$" symbol.)
""" # Complete steps 2 and 3 here graph.set_title("Results of 500 slot machine pulls")
graph.set_ylim(bottom=0)
graph.set_ylabel("Balance")graph = jimmy_slots.get_graph()
prettify_graph(graph)
graph
Challenge
The question had a challenge: to add “$” to the y-axis ticks.
Seems simple enough. Or so I thought as I looked through the directory of the graph function. I identified one useful method— set_yticks.
Experimenting with it gave me error after error. Frustrated at my lack of knowledge, I turned to the internet and found matplotlib documentation for dollar ticks. Here’s the code:
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))
# Use automatic StrMethodFormatter
ax.yaxis.set_major_formatter('${x:1.2f}')
ax.yaxis.set_tick_params(which='major', labelcolor='green',
labelleft=False, labelright=True)
plt.show()
Looks like it has what I need. I isolated the line of code responsible for the dollar ticks with cents:
ax.yaxis.set_major_formatter('${x:1.2f}')
Add that to the code in Kaggle:
def prettify_graph(graph):
"""Modify the given graph according to Jimmy's requests:
add a title, make the y-axis
start at 0, label the y-axis.
(And, if you're feeling ambitious, format the tick marks as
dollar amounts using the "$" symbol.)
""" # Complete steps 2 and 3 here
graph.set_title("Results of 500 slot machine pulls")
graph.set_ylim(bottom=0)
graph.set_ylabel("Balance") #alternative solution from the internet:
graph.yaxis.set_major_formatter('${x:1.2f}')graph = jimmy_slots.get_graph()
prettify_graph(graph)
graph
Success! But that’s not the end. I need to compare it with Kaggle’s solution.
Kaggle’s solution
Being through, I deactivated my solution and ran Kaggle’s solution.
def prettify_graph(graph):
"""Modify the given graph according to Jimmy's requests:
add a title, make the y-axis
start at 0, label the y-axis.
(And, if you're feeling ambitious, format the tick marks as
dollar amounts using the "$" symbol.)
""" # Complete steps 2 and 3 here
graph.set_title("Results of 500 slot machine pulls")
graph.set_ylim(bottom=0)
graph.set_ylabel("Balance") #alternative solution from the internet:
#graph.yaxis.set_major_formatter('${x:1.2f}') # Bonus: format the numbers on the y-axis as dollar amounts
# An array of the values displayed on the y-axis (150, 175, 200,
etc.)
ticks = graph.get_yticks()
# Format those values into strings beginning with dollar sign
new_labels = ['${}'.format(int(amt)) for amt in ticks]
# Set the new labels
graph.set_yticklabels(new_labels)graph = jimmy_slots.get_graph()
prettify_graph(graph)
graph
Looks like there are two issues with Kaggle’s solution. Firstly, the y-axis has lost the two decimal places. Secondly, what is the implication of the user warning and should I be concerned?
Troubleshooting
The first issue was not really an issue for this problem, but I wanted to know what caused the decimal points to disappear. The steps to solve it was simple — isolate the lines of code from both solutions and compare them. The difference was the formatting argument:
#alternative solution I found on matplotlib documentation
graph.yaxis.set_major_formatter('${x:1.2f}')#kaggle's solution
new_labels = ['${}'.format(int(amt)) for amt in ticks]#formatting argument:
#('${x:1.2f}') vs ['${}'~]
#where '~' indicates continuing codes not shown
Scanning from left to right. The dollar sign is needed for “$” in the tick. The text in {} formats the ticker value. x is the ticker value (in our case is 50, 100, 150, 200, 250, 300). So the code for the two decimal position is — :1.2f. Kaggle’s solution did not have x as the argument is passed into each value of the ticker later in the code.
Hence the modified Kaggle solution would be:
#kaggle's solution
new_labels = ['${:1.2f}'.format(int(amt)) for amt in ticks]
And the complete solution is:
def prettify_graph(graph):
"""Modify the given graph according to Jimmy's requests:
add a title, make the y-axis
start at 0, label the y-axis.
(And, if you're feeling ambitious, format the tick marks as
dollar amounts using the "$" symbol.)
""" # Complete steps 2 and 3 here
graph.set_title("Results of 500 slot machine pulls")
graph.set_ylim(bottom=0)
graph.set_ylabel("Balance") #alternative solution from the internet:
#graph.yaxis.set_major_formatter('${x:1.2f}') # Bonus: format the numbers on the y-axis as dollar amounts
# An array of the values displayed on the y-axis (150, 175, 200,
etc.)
ticks = graph.get_yticks()
# Format those values into strings beginning with dollar sign
new_labels = ['${:1.2f}'.format(int(amt)) for amt in ticks]
# Set the new labels
graph.set_yticklabels(new_labels)graph = jimmy_slots.get_graph()
prettify_graph(graph)
graph
Onwards to solve the second issue: the user warning — FixedFormatter should only be used together with FixedLocator
I did a little digging on the internet and found another useful tutorial on matplotlib.org. Link here
This tutorial is lengthy as it covers many types of tick formatting. I highly recommend reading it. Isolating the section related to the user warning (Setup code not shown here, but can be found in the source link):
# Fixed formatter
setup(axs1[3], title="FixedFormatter(['A', 'B', 'C', ...])")# FixedFormatter should only be used together with FixedLocator.
# Otherwise, one cannot be sure where the labels will end up.positions = [0, 1, 2, 3, 4, 5]
labels = ['A', 'B', 'C', 'D', 'E', 'F']
axs1[3].xaxis.set_major_locator(ticker.FixedLocator(positions))
axs1[3].xaxis.set_major_formatter(ticker.FixedFormatter(labels))
The tutorial indicates both FixedFormatter and FixedLocator should be used together, but not a must. So it is not an issue to fix now. Rather, I noted down the potential implication in the code so I know to use FixedLocator should the y-axis label appear at non-standard locations.
Conclusion
This was a fun and simple exercise. I spent more time documenting than solving it as I had to backtrack and take screenshots and copy codes when writing this. Aiming to improve my documentation process.