You can do this more succinctly by first grouping by the User and the Post Type to get a set of every first question and answer. Then group that set by the type of post and the week it occurred in. Finally use the PIVOT operator to pivot the rows into two columns so you can display it on the chart.
DECLARE @FirstDate DATE = '2011-01-01'; --There was very little activity prior to this date. Including it skews the graph. SELECT WeekOf, Questions, Answers FROM ( SELECT WeekOf, CASE PostTypeId WHEN 1 THEN 'Questions' WHEN 2 THEN 'Answers' END AS PostType, COUNT(*) AS PostCount FROM ( SELECT PostTypeId, DATEADD(week, DATEDIFF(week, 0, MIN(CreationDate)),0) AS WeekOf FROM Posts WHERE PostTypeId IN (1,2) AND CreationDate >= @FirstDate GROUP BY OwnerUserId, PostTypeId ) AS FirstPosts GROUP BY WeekOf, PostTypeId ) AS WeeklyCounts PIVOT ( MAX(PostCount) FOR PostType IN ([Questions],[Answers]) ) AS p ORDER BY WeekOf;
There isn't any need to join the Posts table to the Users table because we don't need any columns from there. Grouping by the OwnerUserId column is sufficient, it doesn't even need to be in the SELECT clause.
A variable to hold the starting week so it can be easily updated in the future can be useful.
I noticed that you've split all of your sub-queries out into CTEs. If I'm not using it in multiple places or doing recursion I don't use a CTE. Personally, I find it easier to read the sub-queries in-line rather than have to scroll up to see what they are doing.
One problem this doesn't solve is that if no new questions and answers are made in a week then that week won't appear in the result set. A recursive CTE can be used to generate a set of all of the dates in the period.
My date ranges aren't normally so large so I don't usually need to change the MAXRECURSION option but in this case there are more than 100 weeks in the set and 100 is the default maximum recursion limit. 300 will be sufficient.
A second variable is used to store the maximum post date for limiting the recursive CTE. If a variable wasn't used the query to determine the maximum post creation date would be run every time the CTE executed.
DECLARE @FirstWeek DATE = '2011-01-01'; --There was very little activity prior to this date. Including it skews the graph. DECLARE @FinalWeek DATE = ( SELECT MAX(CreationDate) FROM Posts WHERE PostTypeId IN (1,2) ); WITH AllWeeks AS ( SELECT DATEADD(week, DATEDIFF(week, 0, @FirstWeek), 0) AS WeekOf UNION ALL SELECT DATEADD(week, 1, WeekOf) AS WeekOf FROM AllWeeks WHERE WeekOf < @FinalWeek ) SELECT AllWeeks.WeekOf, Questions, Answers FROM AllWeeks LEFT JOIN ( SELECT WeekOf, CASE PostTypeId WHEN 1 THEN 'Questions' WHEN 2 THEN 'Answers' END AS PostType, COUNT(*) AS PostCount FROM ( SELECT PostTypeId, DATEADD(week, DATEDIFF(week, 0, MIN(CreationDate)),0) AS WeekOf FROM Posts WHERE PostTypeId IN (1,2) AND CreationDate >= @FirstWeek GROUP BY OwnerUserId, PostTypeId ) AS FirstPosts GROUP BY WeekOf, PostTypeId ) AS WeeklyCounts PIVOT ( MAX(PostCount) FOR PostType IN ([Questions],[Answers]) ) AS p ON p.WeekOf=AllWeeks.WeekOf ORDER BY WeekOf OPTION (MAXRECURSION 300);
Doing this will slow down your query of course.
Number of first posts and new users per week