Browse Source

Merge pull request #167 from vmarkovtsev/master

Add "old-vs-new" plot
Vadim Markovtsev 6 years ago
parent
commit
1bf23cc88d
6 changed files with 54 additions and 3 deletions
  1. 13 0
      README.md
  2. BIN
      doc/add_vs_changed.png
  3. BIN
      doc/devs_tensorflow.png
  4. BIN
      doc/emberjs_people.png
  5. BIN
      doc/wireshark_churn_matrix.png
  6. 41 3
      labours.py

+ 13 - 0
README.md

@@ -300,6 +300,19 @@ insights from the `tensorflow/tensorflow` plot above:
 2. The "blue" group of developers covers the global maintainers and a few people who left (at the top).
 2. The "blue" group of developers covers the global maintainers and a few people who left (at the top).
 3. The "red" group shows how core developers join the project or become less active.
 3. The "red" group shows how core developers join the project or become less active.
 
 
+#### Added vs changed lines through time
+
+![tensorflow/tensorflow](doc/add_vs_changed.png)
+<p align="center">tensorflow/tensorflow added and changed lines through time.</p>
+
+```
+hercules --devs [-people-dict=/path/to/identities]
+python3 labours.py -m old-vs-new -o <name>
+```
+
+`--devs` from the previous section allows to plot how many lines were added and how many existing changed
+(deleted or replaced) through time. This plot is smoothed.
+
 #### Sentiment (positive and negative code)
 #### Sentiment (positive and negative code)
 
 
 ![Django sentiment](doc/sentiment.png)
 ![Django sentiment](doc/sentiment.png)

BIN
doc/add_vs_changed.png


BIN
doc/devs_tensorflow.png


BIN
doc/emberjs_people.png


BIN
doc/wireshark_churn_matrix.png


+ 41 - 3
labours.py

@@ -3,6 +3,7 @@ import argparse
 from collections import defaultdict, namedtuple
 from collections import defaultdict, namedtuple
 from datetime import datetime, timedelta
 from datetime import datetime, timedelta
 from importlib import import_module
 from importlib import import_module
+from itertools import chain
 import io
 import io
 import json
 import json
 import os
 import os
@@ -61,7 +62,7 @@ def parse_args():
     parser.add_argument("-m", "--mode",
     parser.add_argument("-m", "--mode",
                         choices=["burndown-project", "burndown-file", "burndown-person",
                         choices=["burndown-project", "burndown-file", "burndown-person",
                                  "churn-matrix", "ownership", "couples", "shotness", "sentiment",
                                  "churn-matrix", "ownership", "couples", "shotness", "sentiment",
-                                 "devs", "all", "run-times"],
+                                 "devs", "old-vs-new", "all", "run-times"],
                         help="What to plot.")
                         help="What to plot.")
     parser.add_argument(
     parser.add_argument(
         "--resample", default="year",
         "--resample", default="year",
@@ -1314,7 +1315,7 @@ def show_devs(args, name, start_date, end_date, data):
         else:
         else:
             # outlier
             # outlier
             color = "grey"
             color = "grey"
-        ax.plot(plot_x, series, color=color)
+        ax.fill_between(plot_x, series, color=color)
         ax.set_axis_off()
         ax.set_axis_off()
         author = people[dev_i]
         author = people[dev_i]
         ax.text(0.03, 0.5, author[:36] + (author[36:] and "..."),
         ax.text(0.03, 0.5, author[:36] + (author[36:] and "..."),
@@ -1344,7 +1345,7 @@ def show_devs(args, name, start_date, end_date, data):
         axes[-1].xaxis.set_major_locator(matplotlib.dates.MonthLocator(interval=interval))
         axes[-1].xaxis.set_major_locator(matplotlib.dates.MonthLocator(interval=interval))
         axes[-1].xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%Y-%m"))
         axes[-1].xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%Y-%m"))
     for tick in axes[-1].xaxis.get_major_ticks():
     for tick in axes[-1].xaxis.get_major_ticks():
-        tick.label.set_fontsize(16)
+        tick.label.set_fontsize(args.font_size)
     axes[-1].spines["left"].set_visible(False)
     axes[-1].spines["left"].set_visible(False)
     axes[-1].spines["right"].set_visible(False)
     axes[-1].spines["right"].set_visible(False)
     axes[-1].spines["top"].set_visible(False)
     axes[-1].spines["top"].set_visible(False)
@@ -1355,6 +1356,34 @@ def show_devs(args, name, start_date, end_date, data):
     deploy_plot(title, args.output, args.style)
     deploy_plot(title, args.output, args.style)
 
 
 
 
+def show_old_vs_new(args, name, start_date, end_date, data):
+    from scipy.signal import convolve, slepian
+
+    days, people = data
+    start_date = datetime.fromtimestamp(start_date)
+    start_date = datetime(start_date.year, start_date.month, start_date.day)
+    end_date = datetime.fromtimestamp(end_date)
+    end_date = datetime(end_date.year, end_date.month, end_date.day)
+    new_lines = numpy.zeros((end_date - start_date).days + 1)
+    old_lines = numpy.zeros_like(new_lines)
+    for day, devs in days.items():
+        for stats in devs.values():
+            new_lines[day] += stats.Added
+            old_lines[day] += stats.Removed + stats.Changed
+    resolution = 32
+    window = slepian(len(new_lines) // resolution, 0.5)
+    new_lines = convolve(new_lines, window, "same")
+    old_lines = convolve(old_lines, window, "same")
+    matplotlib, pyplot = import_pyplot(args.backend, args.style)
+    plot_x = [start_date + timedelta(days=i) for i in range(len(new_lines))]
+    pyplot.fill_between(plot_x, new_lines, color="#8DB843", label="Changed new lines")
+    pyplot.fill_between(plot_x, old_lines, color="#E14C35", label="Changed existing lines")
+    pyplot.legend(loc=2, fontsize=args.font_size)
+    for tick in chain(pyplot.gca().xaxis.get_major_ticks(), pyplot.gca().yaxis.get_major_ticks()):
+        tick.label.set_fontsize(args.font_size)
+    deploy_plot("Additions vs changes", args.output, args.style)
+
+
 def _format_number(n):
 def _format_number(n):
     if n == 0:
     if n == 0:
         return "0"
         return "0"
@@ -1502,6 +1531,14 @@ def main():
             return
             return
         show_devs(args, reader.get_name(), *reader.get_header(), data)
         show_devs(args, reader.get_name(), *reader.get_header(), data)
 
 
+    def old_vs_new():
+        try:
+            data = reader.get_devs()
+        except KeyError:
+            print(devs_warning)
+            return
+        show_old_vs_new(args, reader.get_name(), *reader.get_header(), data)
+
     modes = {
     modes = {
         "run-times": run_times,
         "run-times": run_times,
         "burndown-project": project_burndown,
         "burndown-project": project_burndown,
@@ -1513,6 +1550,7 @@ def main():
         "shotness": shotness,
         "shotness": shotness,
         "sentiment": sentiment,
         "sentiment": sentiment,
         "devs": devs,
         "devs": devs,
+        "old-vs-new": old_vs_new,
     }
     }
     try:
     try:
         modes[args.mode]()
         modes[args.mode]()