@@ -119,9 +119,7 @@ p.yaxis.axis_label = TeX(r"\frac{issues}{day}")
119119show(p)
120120```
121121
122- % TODO: add distribution of labels
123-
124- ### First responders
122+ #### Time to response
125123
126124``` {code-cell} ipython3
127125---
@@ -135,8 +133,14 @@ newly_created_day_old = [
135133]
136134
137135# TODO: really need pandas here
138- first_commenters = []
139- for iss in newly_created_day_old:
136+ commented_issues = [
137+ iss for iss in newly_created_day_old
138+ if any(
139+ e["node"]["__typename"] == "IssueComment" for e in iss["timelineItems"]["edges"]
140+ )
141+ ]
142+ first_commenters, time_to_first_comment = [], []
143+ for iss in commented_issues:
140144 for e in iss["timelineItems"]["edges"]:
141145 if e["node"]["__typename"] == "IssueComment":
142146 try:
@@ -145,7 +149,26 @@ for iss in newly_created_day_old:
145149 # This can happen e.g. when a user deletes their GH acct
146150 user = "UNKNOWN"
147151 first_commenters.append(user)
152+ dt = np.datetime64(e["node"]["createdAt"]) - np.datetime64(iss["createdAt"])
153+ time_to_first_comment.append(dt.astype("m8[m]"))
148154 break # Only want the first commenter
155+ time_to_first_comment = np.array(time_to_first_comment) # in minutes
156+
157+ median_time_til_first_response = np.median(time_to_first_comment.astype(int) / 60)
158+
159+ cutoffs = [
160+ np.timedelta64(1, "h"),
161+ np.timedelta64(12, "h"),
162+ np.timedelta64(24, "h"),
163+ np.timedelta64(3, "D"),
164+ np.timedelta64(7, "D"),
165+ np.timedelta64(14, "D"),
166+ ]
167+ num_issues_commented_by_cutoff = np.array(
168+ [
169+ np.sum(time_to_first_comment < cutoff) for cutoff in cutoffs
170+ ]
171+ )
149172
150173# TODO: Update IssueComment query to include:
151174# - whether the commenter is a maintainer
@@ -154,16 +177,53 @@ for iss in newly_created_day_old:
154177# maintainers vs. non-maintainer, and the distribution of how long an issue
155178# usually sits before it's at least commented on
156179
157- glue("new_issues_at_least_1_day_old", len(newly_created_day_old))
158180glue(
159181 "num_new_issues_responded",
160- percent_val(len(first_commenters ), len(newly_created_day_old))
182+ percent_val(len(commented_issues ), len(newly_created_day_old))
161183)
184+
185+ glue("new_issues_at_least_1_day_old", len(newly_created_day_old))
186+ glue("median_response_time", f"{median_time_til_first_response:1.0f}")
162187```
163188
164189Of the {glue: text }` new_issues_at_least_1_day_old ` issues that are at least 24
165190hours old, {glue: text }` num_new_issues_responded ` of them have been commented
166191on.
192+ The median time until an issue is first responded to is
193+ {glue: text }` median_response_time ` hours.
194+
195+ ``` {code-cell} ipython3
196+ ---
197+ tags: [hide-input]
198+ ---
199+ from bokeh.transform import dodge
200+
201+ title = f"Percentage of issues opened since {query_date} that are commented on within..."
202+
203+ x = [str(c) for c in cutoffs]
204+ y = 100 * num_issues_commented_by_cutoff / len(newly_created_day_old)
205+
206+ p = figure(
207+ x_range=x,
208+ y_range=(0, 100),
209+ width=670,
210+ height=400,
211+ title=title,
212+ tooltips=[(r"%", "@top")],
213+ )
214+ p.vbar(x=x, top=y, width=0.8)
215+ p.xaxis.axis_label = "Time interval"
216+ p.yaxis.axis_label = "Percentage of issues commented on within interval"
217+ show(p)
218+ ```
219+
220+ #### First responders
221+
222+ ``` {code-cell} ipython3
223+ ---
224+ tags: [hide-input]
225+ ---
226+ ```
167227
168228``` {code-cell} ipython3
169229---
0 commit comments