info_surface.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. ###############################################################################
  2. ## information as function of delay and kernel ##
  3. from argparse import ArgumentError
  4. import os
  5. import numpy as np
  6. import pandas as pd
  7. import matplotlib.pyplot as plt
  8. import matplotlib.image as mpimg
  9. import matplotlib.patches as mpatches
  10. from matplotlib import cm
  11. from .figure_style import subfig_labelsize, subfig_labelweight, despine
  12. from ..util import DelayType
  13. def plot_surface(df, axis, args):
  14. kernels = df.kernel_sigma.unique()
  15. delays = df.delay.unique()
  16. delays = delays[delays >= 0.0]
  17. if args.pop_size not in df.pop_size.unique():
  18. raise ValueError("Requested population size %i was not analyzed! valid values are: " % args.pop_size, df.pop_size.unique())
  19. if args.delay_type not in df.delay_type.unique():
  20. raise ArgumentError(f"Delay type argument ({args.delay_type}) is invalid in data frame {args.heterogeneous_data}! Valid options are: {list(df.delay_type.unique())}")
  21. # create the surface plot
  22. log_delays = delays.copy()
  23. log_delays[0] += 0.00005
  24. log_delays = np.log10(log_delays)
  25. log_kernels = np.log10(kernels)
  26. X, Y = np.meshgrid(log_delays, log_kernels)
  27. Z = np.zeros_like(X)
  28. E = np.zeros_like(X)
  29. for i, d in enumerate(delays):
  30. for j, k in enumerate(kernels):
  31. data_df = df[(df.kernel_sigma == k) & (df.pop_size == args.pop_size) & (df.delay == d)]
  32. Z[j, i] = np.mean(data_df.mi)
  33. E[j, i] = np.std(data_df.mi)
  34. CS = axis.contourf(X, Y, Z, cmap=cm.coolwarm, antialiased=True, alpha=0.85, levels=20)
  35. axis.set_xlabel(r"$\sigma_{delay}$ [ms]")
  36. xticklabels = list(map(lambda s: str(np.round(s*1000, 1)), delays))
  37. x2ticklabels = list(map(lambda s: str(np.round((s*2)/np.sqrt(12)*1000, 1)), delays))
  38. for i in [4, 5, 7, 8, 9, 10, 12, 13]:
  39. xticklabels[i] = ""
  40. x2ticklabels[i] = ""
  41. axis.plot([np.log10(0.000125), np.log10(0.015)], [np.log10(0.000125), np.log10(0.015)], ls="--", lw=0.5, color="k")
  42. axis.set_xlim([log_delays[0], log_delays[-1]])
  43. axis.set_xticks(log_delays, minor=True)
  44. axis.set_xticks([log_delays[0], np.log10(0.001), np.log10(0.01)])
  45. axis.set_xticklabels([0.0, 1.0, 10.0], fontsize=7, rotation=90, ha="center")
  46. axis.set_ylim([min(log_kernels), max(log_kernels)])
  47. axis.set_yticks(log_kernels)
  48. axis.set_yticklabels(kernels*1000, fontsize=7)
  49. axis.set_ylabel(r"$\sigma_{kernel}$ [ms]")
  50. axis.xaxis.grid(b=True, which="major", color="white", ls="--", lw=0.1)
  51. axis.yaxis.grid(b=True, which="major", color="white", ls="--", lw=0.1)
  52. cbar = plt.gcf().colorbar(CS, ax=axis)
  53. cbar.set_ticks(np.arange(200, 751, 100))
  54. cbar.ax.set_ylabel('mutual information [bit/s]')
  55. # add a rectangle for LS delays
  56. rect = mpatches.Rectangle([np.log10(0.0002), log_kernels[0]],
  57. np.log10(0.0007) - np.log10(0.0002),
  58. log_kernels[-1] - log_kernels[0], lw=1., ls="--", ec="silver", fc="None", alpha=1.0)
  59. axis.add_patch(rect)
  60. axis.text(np.log10(0.0002), log_kernels[-2], r"receptive field size lower bound", rotation=90, fontsize=5, va="top", ha="right")
  61. axis.text(np.log10(0.0007), log_kernels[-2], r"receptive field size upper bound", rotation=90, fontsize=5, va="top", ha="right")
  62. rect = mpatches.Rectangle([log_delays[0], np.log10(0.0005)],
  63. log_delays[-1] - log_delays[0],
  64. np.log10(0.0015) - np.log10(0.0005), lw=1., ls="--", ec="silver", fc="None", alpha=1.0)
  65. axis.add_patch(rect)
  66. axis.text(log_delays[-2], np.log10(0.0005), r"fast EPSP component", rotation=0, fontsize=5, va="top", ha="right")
  67. axis.text(log_delays[-2], np.log10(0.0015), r"slow EPSP component", rotation=0, fontsize=5, va="top", ha="right")
  68. def layout_figure():
  69. fig = plt.figure(figsize=(3.42, 2.5))
  70. axis = fig.add_subplot()
  71. fig.subplots_adjust(left=0.175, top=0.95, right=0.95, bottom=0.2)
  72. return fig, axis
  73. def performance_surface(args):
  74. """ The postsynaptic pyramidal cells in the ELL integrate over different population size, i.e.
  75. receptive fields of different sizes (Maler 2009) and do show different EPSP time courses.
  76. This function creates a surface plot
  77. Args:
  78. args (argparse.arguments): the command line arguments
  79. Returns:
  80. [type]: [description]
  81. """
  82. if not os.path.exists(args.heterogeneous_data):
  83. raise ValueError(f"Results DataFrame does not exist! {args.heterogeneous_data}")
  84. het_df = pd.read_csv(args.heterogeneous_data, sep=";", index_col=0)
  85. fig, axis = layout_figure()
  86. if "delay_type" in het_df.columns:
  87. plot_surface(het_df[het_df.delay_type=="gaussian"], axis, args)
  88. else:
  89. plot_surface(het_df, axis, args)
  90. if args.nosave:
  91. plt.show()
  92. else:
  93. fig.savefig(args.outfile, dpi=500)
  94. plt.close()
  95. def command_line_parser(subparsers):
  96. parser = subparsers.add_parser("info_surface", help="Plots the mutual information as function of delay and (synpatic) kernel width.")
  97. parser.add_argument("-hetdf", "--heterogeneous_data", default=os.path.join("derived_data", "heterogeneous_populationcoding.csv"))
  98. parser.add_argument("-o", "--outfile", type=str, default=os.path.join("figures", "performance_surface.pdf"), help="The filename of the figure")
  99. parser.add_argument("-ps", "--pop_size", type=int, default=16, help="The population size")
  100. parser.add_argument("-dt", "--delay_type", type=str, default=str(DelayType.Gaussian), help="The type of distribution from which delays have been drawn. Usually a Gaussian normal distribution.")
  101. parser.add_argument("-n", "--nosave", action='store_true', help="No saving of the figure, just showing.")
  102. parser.set_defaults(func=performance_surface)