ownership.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from datetime import datetime, timedelta
  2. import json
  3. from typing import Any, Dict, List, Tuple
  4. import numpy
  5. from labours.burndown import import_pandas
  6. from labours.plotting import apply_plot_style, deploy_plot, get_plot_path, import_pyplot
  7. from labours.utils import default_json, floor_datetime, parse_date
  8. def load_ownership(
  9. header: Tuple[int, int, int, int, float],
  10. sequence: List[Any],
  11. contents: Dict[Any, Any],
  12. max_people: int,
  13. order_by_time: bool,
  14. ):
  15. pandas = import_pandas()
  16. start, last, sampling, _, tick = header
  17. start = datetime.fromtimestamp(start)
  18. start = floor_datetime(start, tick)
  19. last = datetime.fromtimestamp(last)
  20. people = []
  21. for name in sequence:
  22. people.append(contents[name].sum(axis=1))
  23. people = numpy.array(people)
  24. date_range_sampling = pandas.date_range(
  25. start + timedelta(seconds=sampling * tick),
  26. periods=people[0].shape[0],
  27. freq="%dD" % sampling,
  28. )
  29. if people.shape[0] > max_people:
  30. chosen = numpy.argpartition(-numpy.sum(people, axis=1), max_people)
  31. others = people[chosen[max_people:]].sum(axis=0)
  32. people = people[chosen[: max_people + 1]]
  33. people[max_people] = others
  34. sequence = [sequence[i] for i in chosen[:max_people]] + ["others"]
  35. print("Warning: truncated people to the most owning %d" % max_people)
  36. if order_by_time:
  37. appearances = numpy.argmax(people > 0, axis=1)
  38. if people.shape[0] > max_people:
  39. appearances[-1] = people.shape[1]
  40. else:
  41. appearances = -people.sum(axis=1)
  42. if people.shape[0] > max_people:
  43. appearances[-1] = 0
  44. order = numpy.argsort(appearances)
  45. people = people[order]
  46. sequence = [sequence[i] for i in order]
  47. for i, name in enumerate(sequence):
  48. if len(name) > 40:
  49. sequence[i] = name[:37] + "..."
  50. return sequence, people, date_range_sampling, last
  51. def plot_ownership(args, repo, names, people, date_range, last):
  52. if args.output and args.output.endswith(".json"):
  53. data = locals().copy()
  54. del data["args"]
  55. data["type"] = "ownership"
  56. if args.mode == "all" and args.output:
  57. output = get_plot_path(args.output, "people")
  58. else:
  59. output = args.output
  60. with open(output, "w") as fout:
  61. json.dump(data, fout, sort_keys=True, default=default_json)
  62. return
  63. matplotlib, pyplot = import_pyplot(args.backend, args.style)
  64. polys = pyplot.stackplot(date_range, people, labels=names)
  65. if names[-1] == "others":
  66. polys[-1].set_hatch("/")
  67. pyplot.xlim(
  68. parse_date(args.start_date, date_range[0]), parse_date(args.end_date, last)
  69. )
  70. if args.relative:
  71. for i in range(people.shape[1]):
  72. people[:, i] /= people[:, i].sum()
  73. pyplot.ylim(0, 1)
  74. legend_loc = 3
  75. else:
  76. legend_loc = 2
  77. ncol = 1 if len(names) < 15 else 2
  78. legend = pyplot.legend(loc=legend_loc, fontsize=args.font_size, ncol=ncol)
  79. apply_plot_style(
  80. pyplot.gcf(), pyplot.gca(), legend, args.background, args.font_size, args.size
  81. )
  82. if args.mode == "all" and args.output:
  83. output = get_plot_path(args.output, "people")
  84. else:
  85. output = args.output
  86. deploy_plot("%s code ownership through time" % repo, output, args.background)