Count every genre at once with a dictionary, then draw each count as a bar of
Before computers drew charts, people drew them with tally marks. A row of # characters is the same idea, and it is a real bar chart.
Last lesson counted one genre at a time. A dictionary can count every genre at once: one key per genre, and its count as the value. Then each count becomes a bar, because "#" * 5 is #####.
Make your prediction first. Help opens once you've locked it in.
counts = {"pop": 3, "rock": 2}
for genre in counts:
print(genre.ljust(6) + "#" * counts[genre])
"#" * 3 repeats text. ljust(6) pads a word with spaces until it is 6 characters long.
Run it: a bar for each genre, with its count. Which genre has the most songs? Add print(counts) after the first loop to see the whole dictionary.
import csv
with open("music.csv") as f:
songs = list(csv.DictReader(f))
counts = {}
for song in songs:
genre = song["genre"]
if genre in counts:
counts[genre] = counts[genre] + 1
else:
counts[genre] = 1
for genre in counts:
print(genre.ljust(12) + "#" * counts[genre] + " " + str(counts[genre]))
import csv
with open("music.csv") as f:
songs = list(csv.DictReader(f))
counts = {}
for song in songs:
genre = song["genre"]
if genre in counts:
counts[genre] = counts[genre] + 1
else:
counts[genre] = 1
for genre in counts:
print(genre.ljust(12) + "#" * counts[genre] + " " + str(counts[genre]))
What the dictionary holds.
A key that is not there yet.
A count that never starts.
This should count the genres, but it stops straight away with KeyError: 'country'. Click the line that is wrong.
Chart the songs by decade (1970, 1980, ...) instead of by genre.
Use the decade as the key instead of the genre: decade = int(song["year"]) // 10 * 10.
// divides and drops the remainder: 1987 // 10 is 198, and 198 * 10 is 1980. A number key needs str() before ljust.
Only draw a bar for genres with 3 or more songs.
Put the print inside if counts[genre] >= 3:.
Chart the songs by decade instead of genre.
Run your program. This ticks when your code does all of the above.
Only draw genres with 3 or more songs.
Run your program. This ticks when your code does all of the above.
Add up the minutes of each genre, then draw a bar for each genre with one # for every 5 minutes, and the total at the end of the bar. (int() drops the decimals from a number of #s.)
Total the minutes for each genre and draw a bar for each, one # for every 5 minutes.
Run your program. This ticks when your code does all of the above.
Real charting tools (spreadsheets, pandas, Gradio's BarPlot in Lesson 5) draw the same bars from the same counts. Next: data that is messy, and how to check your code with test cases.
Students count every genre at once with a dictionary and draw the counts as a text bar chart, then chart by decade, filter the bars, and total minutes per genre. About 50 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
Read the unit primer first. The counting pattern: counts = {}, then for each row, if the key is in counts add 1, otherwise start it at 1 (the bug task leaves out the start, giving a KeyError). Looping over a dictionary (for genre in counts:) gives its keys. "#" * n repeats text; ljust(12) pads text with spaces to 12 characters so the bars line up. The decade task uses // (divide and drop the remainder): 1987 // 10 * 10 is 1980. The Where this leads question is about where data comes from: this file is a hand-picked set of well-known songs, so it says nothing about music in general.
Counting with a dictionary: the new key that has no count yet. Ask what counts holds after the first song, on paper, before they change code.
Stretch: Print the bars in order, biggest first (sorted(counts, key=counts.get, reverse=True) is one way to look up).
Support: Give students the counting loop and ask them only to write the loop that draws the bars.
Next lesson cleans messy data and checks code with test cases. Lesson 5 draws the same chart with Gradio's BarPlot.