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 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 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
Initial 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
Graph after completing the three tasks

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.

Directory of graph

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()
Graph from matplotlib documentation

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
Graph with dollar ticks (set_major_formatter method)

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
User warning and graph with dollar ticks (Kaggle’s solution)

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
Graph with dollar ticks (modified Kaggle’s solution)

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))
Output of fixed formatted code

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.

I'm starting out in the world of Data Science. Working to be a qualified and employed Data Analyst. Follow me on my journey!