The request

From Megan Collins, Head of Sales
Your goal
Count orders (all statuses) per day from 2025-11-01 to 2025-12-31. Set result to a Series indexed by order_date (one row per day, 61 days, in date order) with values named n_orders, and draw it as a line chart.
- Use the
ordersDataFramenot done yet - Show exactly
order_daten_ordersnot done yet - 61 rows, sorted as askednot done yet
Your code
Loading the editor…
Reference solution
| order_id | customer_id | order_date | status | channel |
|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace |
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
What Megan gets, and why
DataFrames
Loaded for you as pandas DataFrames, plus pd and np.
orders12,000 rows · 7 columns
order_idintegercustomer_idintegerorder_datetimestampstatusvarcharchannelvarcharshipping_feedecimalcoupon_codevarchar
| order_id | customer_id | order_date | status | channel | shipping_fee | coupon_code |
|---|---|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web | 0.00 | NaN |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web | 0.00 | NaN |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace | 4.99 | WELCOME10 |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace | 4.99 | WELCOME10 |
| 1005 | 82 | 2023-01-02 11:43:36 | completed | web | 0.00 | WELCOME10 |
customers2,018 rows · 9 columns
customer_idintegerfirst_namevarcharlast_namevarcharemailvarcharcityvarcharstatevarcharsignup_datedatesegmentvarcharreferral_sourcevarchar
| customer_id | first_name | last_name | city | state | signup_date | segment | referral_source | |
|---|---|---|---|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco | CA | 2022-06-02 | consumer | search |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta | GA | 2022-06-02 | consumer | NaN |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles | CA | 2022-06-04 | business | NaN |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle | WA | 2022-06-06 | business | |
| 5 | Kyle | Jimenez | kjimenez27@yahoo.com | Indianapolis | IN | 2022-06-07 | consumer | NaN |
products120 rows · 8 columns
product_idintegernamevarcharcategoryvarcharsubcategoryvarcharunit_pricedecimalunit_costdecimallaunched_ondateis_activeboolean
| product_id | name | category | subcategory | unit_price | unit_cost | launched_on | is_active |
|---|---|---|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 | NaN | 2023-09-11 | true |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 | 503.50 | 2024-05-16 | true |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 | 429.87 | 2023-05-27 | true |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 | 214.70 | 2022-12-20 | true |
| 105 | Avery Leather Bed Frame | Furniture | Beds | 449.00 | 232.70 | 2021-08-31 | true |
order_items30,338 rows · 6 columns
order_item_idintegerorder_idintegerproduct_idintegerquantityintegerunit_pricedecimaldiscount_pctdecimal
| order_item_id | order_id | product_id | quantity | unit_price | discount_pct |
|---|---|---|---|---|---|
| 1 | 1001 | 121 | 9 | 31.99 | 0.00 |
| 2 | 1001 | 154 | 3 | 11.99 | 0.00 |
| 3 | 1002 | 154 | 4 | 11.99 | 0.00 |
| 4 | 1002 | 194 | 1 | 149.00 | 0.00 |
| 5 | 1002 | 193 | 2 | 19.99 | 0.00 |
returns1,673 rows · 5 columns
return_idintegerorder_item_idintegerreturned_ondatereasonvarcharrefund_amountdecimal
| return_id | order_item_id | returned_on | reason | refund_amount |
|---|---|---|---|---|
| 1 | 14 | 2023-01-10 | damaged | 83.69 |
| 2 | 42 | 2023-01-10 | wrong_item | 19.99 |
| 3 | 105 | 2023-01-14 | wrong_item | 10.99 |
| 4 | 24 | 2023-01-16 | changed_mind | 26.99 |
| 5 | 126 | 2023-01-16 | late | 20.99 |
employees60 rows · 8 columns
employee_idintegerfirst_namevarcharlast_namevarchardepartmentvarchartitlevarcharmanager_idintegerhire_datedatesalaryinteger
| employee_id | first_name | last_name | department | title | manager_id | hire_date | salary |
|---|---|---|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer | NaN | 2016-03-01 | 285000 |
| 2 | Robert | Kim | Executive | Chief Operating Officer | 1 | 2017-01-09 | 235000 |
| 3 | Megan | Collins | Sales | Head of Sales | 1 | 2018-04-16 | 172000 |
| 4 | Chloe | Gutierrez | Sales | Account Executive | 3 | 2020-01-21 | 72000 |
| 5 | Frank | Bell | Sales | Account Executive | 3 | 2023-05-21 | 73000 |
web_sessions40,000 rows · 7 columns
session_idintegercustomer_idintegerstarted_attimestampdevicevarcharsourcevarcharpages_viewedintegerconvertedboolean
| session_id | customer_id | started_at | device | source | pages_viewed | converted |
|---|---|---|---|---|---|---|
| 1 | NaN | 2023-01-01 23:02:24 | mobile | paid | 1 | false |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid | 1 | false |
| 3 | NaN | 2023-01-01 16:55:46 | desktop | direct | 7 | false |
| 4 | NaN | 2023-01-01 12:43:28 | mobile | organic | 3 | false |
| 5 | NaN | 2023-01-01 13:06:21 | mobile | social | 2 | false |
marketing_spend3,276 rows · 3 columns
spend_datedatechannelvarcharamountdecimal
| spend_date | channel | amount |
|---|---|---|
| 2023-01-01 | paid | 492.99 |
| 2023-01-01 | 37.38 | |
| 2023-01-01 | social | 200.53 |
| 2023-01-02 | paid | 709.13 |
| 2023-01-02 | 64.13 |
The lesson
Start from the question, then the data
A chart answers one question. Megan’s is “how did orders move day by day through the holidays, and how big was the peak?” Time on the x-axis, a count on the y-axis, points that belong in order: that is a line chart.
Before drawing anything, build the numbers. One row per day:
season = orders[(orders["order_date"] >= "2025-11-01") & (orders["order_date"] < "2026-01-01")]
daily = season.set_index("order_date").resample("D").size().rename("n_orders")
len(daily) # 61 days
daily.max() # 67, on 2025-12-01 (Cyber Monday)
daily.median() # 22
The chart is only as good as this Series, which is why the check looks at it.
Figure and Axes
matplotlib draws on two objects. The Figure is the whole image, the frame. The Axes is
the plotting area inside it, with its x and y axis and the data. plt.subplots() makes one of
each:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(9, 4)) # width, height in inches
ax.plot(daily.index, daily.values) # x first, then y
ax.set_title("Orders per day, Nov to Dec 2025")
ax.set_xlabel("Day")
ax.set_ylabel("Orders")
x and y must have the same length; here both come from the same Series, so they always do.
You’ll also see a shorter style that talks to “the current chart”: plt.plot(...),
plt.title(...), plt.xlabel(...). It’s fine for a quick look. The fig, ax style is the one to
learn, because it’s clearer and you need it as soon as a figure holds more than one chart. The
names map one to one: plt.title becomes ax.set_title, plt.xlabel becomes ax.set_xlabel,
plt.ylim becomes ax.set_ylim.
pandas has a shortcut too: daily.plot() draws the same line and returns the ax, so you can keep
going with ax.set_title(...).
Reference lines and markers
A line alone shows the shape. A reference line gives it a scale:
ax.plot(daily.index, daily.values, marker="o", markersize=3)
ax.axhline(daily.mean(), color="gray", linestyle="--", label="Average")
ax.legend()
axhline draws a horizontal line across the chart (axvline a vertical one, handy for marking a
launch date). marker="o" puts a dot on each day; linestyle takes "-", "--" or ":".
ax.legend() lists every line that was given a label=. Dates along the x-axis often run into
each other; fig.autofmt_xdate() tilts them so they fit.
Here the average is about 24 orders a day. The Black Friday weekend (November 28 to 30) brought 56, 51 and 58, and Cyber Monday, December 1, brought 67: almost three times a normal day. The quietest days were Christmas Eve and Christmas Day, with 11 and 9.
A title that says the finding
“Orders per day” describes the chart. “Cyber Monday was the busiest day of the season” tells the reader what to see. A good chart can be understood without you standing next to it, and the title is where that starts.
Common mistakes
- Calling
ax.title("...")instead ofax.set_title("..."). On an Axes the setters start withset_;ax.titleis a text object, and calling it raisesTypeError: 'Text' object is not callable. - Calling
ax.legend()when no line has alabel=. The legend comes out empty with a warning. - Removing the
import matplotlib.pyplot as pltline. Here that line is what loads the chart library, and pandas’.plot()needs it too.
Lantern lit!
Practised: matplotlibline chartfig axaxhlineresample
- Solved
- No hints
- First run
