labours.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import argparse
  2. from datetime import datetime, timedelta
  3. import sys
  4. import warnings
  5. import numpy
  6. if sys.version_info[0] < 3:
  7. # OK, ancients, I will support Python 2, but you owe me a beer
  8. input = raw_input
  9. def parse_args():
  10. parser = argparse.ArgumentParser()
  11. parser.add_argument("--output", default="",
  12. help="Path to the output file (empty for display).")
  13. parser.add_argument("--text-size", default=12,
  14. help="Size of the labels and legend.")
  15. parser.add_argument("--backend", help="Matplotlib backend to use.")
  16. parser.add_argument("--style", choices=["black", "white"], default="black",
  17. help="Plot's general color scheme.")
  18. parser.add_argument(
  19. "--resample", default="year",
  20. help="The way to resample the time series. Possible values are: "
  21. "\"month\", \"year\", \"no\", \"raw\" and pandas offset aliases ("
  22. "http://pandas.pydata.org/pandas-docs/stable/timeseries.html"
  23. "#offset-aliases).")
  24. args = parser.parse_args()
  25. return args
  26. def main():
  27. args = parse_args()
  28. import matplotlib
  29. if args.backend:
  30. matplotlib.use(args.backend)
  31. import matplotlib.pyplot as pyplot
  32. import pandas
  33. start, granularity, sampling = input().split()
  34. start = datetime.fromtimestamp(int(start))
  35. granularity = int(granularity)
  36. sampling = int(sampling)
  37. matrix = numpy.array([numpy.fromstring(line, dtype=int, sep=" ")
  38. for line in sys.stdin.read().split("\n")[:-1]]).T
  39. date_range_sampling = pandas.date_range(
  40. start, periods=matrix.shape[1], freq="%dD" % sampling)
  41. if args.resample not in ("no", "raw"):
  42. aliases = {
  43. "year": "A",
  44. "month": "M"
  45. }
  46. daily_matrix = numpy.zeros(
  47. (matrix.shape[0] * granularity, matrix.shape[1]),
  48. dtype=numpy.float32)
  49. for i in range(matrix.shape[0]):
  50. daily_matrix[i * granularity:(i + 1) * granularity] = \
  51. matrix[i] / granularity
  52. date_range_granularity = pandas.date_range(
  53. start, periods=daily_matrix.shape[0], freq="1D")
  54. df = pandas.DataFrame({
  55. dr: pandas.Series(row, index=date_range_sampling)
  56. for dr, row in zip(date_range_granularity, daily_matrix)
  57. }).T
  58. df = df.resample(aliases.get(args.resample, args.resample)).sum()
  59. matrix = df.as_matrix()
  60. if args.resample in ("year", "A"):
  61. labels = [dt.year for dt in df.index]
  62. elif args.resample in ("month", "M"):
  63. labels = [dt.strftime("%Y %B") for dt in df.index]
  64. else:
  65. labels = [dt.date() for dt in df.index]
  66. else:
  67. labels = [
  68. "%s - %s" % ((start + timedelta(days=i * granularity)).date(),
  69. (start + timedelta(days=(i + 1) * granularity)).date())
  70. for i in range(matrix.shape[0])]
  71. if len(labels) > 18:
  72. warnings.warn("Too many labels - consider resampling.")
  73. if args.style == "white":
  74. pyplot.gca().spines["bottom"].set_color("white")
  75. pyplot.gca().spines["top"].set_color("white")
  76. pyplot.gca().spines["left"].set_color("white")
  77. pyplot.gca().spines["right"].set_color("white")
  78. pyplot.gca().xaxis.label.set_color("white")
  79. pyplot.gca().yaxis.label.set_color("white")
  80. pyplot.gca().tick_params(axis="x", colors="white")
  81. pyplot.gca().tick_params(axis="y", colors="white")
  82. pyplot.stackplot(date_range_sampling, matrix, labels=labels)
  83. legend = pyplot.legend(loc=2, fontsize=args.text_size)
  84. frame = legend.get_frame()
  85. frame.set_facecolor("black" if args.style == "white" else "white")
  86. frame.set_edgecolor("black" if args.style == "white" else "white")
  87. for text in legend.get_texts():
  88. text.set_color(args.style)
  89. pyplot.ylabel("Lines of code", fontsize=args.text_size)
  90. pyplot.xlabel("Time", fontsize=args.text_size)
  91. pyplot.tick_params(labelsize=args.text_size)
  92. pyplot.xlim(date_range_sampling[0], date_range_sampling[-1])
  93. pyplot.gcf().set_size_inches(12, 9)
  94. if not args.output:
  95. pyplot.gcf().canvas.set_window_title(
  96. "Hercules %d x %d (granularity %d, sampling %d)" %
  97. (matrix.shape + (granularity, sampling)))
  98. pyplot.show()
  99. else:
  100. pyplot.tight_layout()
  101. pyplot.savefig(args.output, transparent=True)
  102. if __name__ == "__main__":
  103. sys.exit(main())