plot_interval.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. from sympy.core.singleton import S
  2. from sympy.core.symbol import Symbol
  3. from sympy.core.sympify import sympify
  4. from sympy.core.numbers import Integer
  5. class PlotInterval:
  6. """
  7. """
  8. _v, _v_min, _v_max, _v_steps = None, None, None, None
  9. def require_all_args(f):
  10. def check(self, *args, **kwargs):
  11. for g in [self._v, self._v_min, self._v_max, self._v_steps]:
  12. if g is None:
  13. raise ValueError("PlotInterval is incomplete.")
  14. return f(self, *args, **kwargs)
  15. return check
  16. def __init__(self, *args):
  17. if len(args) == 1:
  18. if isinstance(args[0], PlotInterval):
  19. self.fill_from(args[0])
  20. return
  21. elif isinstance(args[0], str):
  22. try:
  23. args = eval(args[0])
  24. except TypeError:
  25. s_eval_error = "Could not interpret string %s."
  26. raise ValueError(s_eval_error % (args[0]))
  27. elif isinstance(args[0], (tuple, list)):
  28. args = args[0]
  29. else:
  30. raise ValueError("Not an interval.")
  31. if not isinstance(args, (tuple, list)) or len(args) > 4:
  32. f_error = "PlotInterval must be a tuple or list of length 4 or less."
  33. raise ValueError(f_error)
  34. args = list(args)
  35. if len(args) > 0 and (args[0] is None or isinstance(args[0], Symbol)):
  36. self.v = args.pop(0)
  37. if len(args) in [2, 3]:
  38. self.v_min = args.pop(0)
  39. self.v_max = args.pop(0)
  40. if len(args) == 1:
  41. self.v_steps = args.pop(0)
  42. elif len(args) == 1:
  43. self.v_steps = args.pop(0)
  44. def get_v(self):
  45. return self._v
  46. def set_v(self, v):
  47. if v is None:
  48. self._v = None
  49. return
  50. if not isinstance(v, Symbol):
  51. raise ValueError("v must be a SymPy Symbol.")
  52. self._v = v
  53. def get_v_min(self):
  54. return self._v_min
  55. def set_v_min(self, v_min):
  56. if v_min is None:
  57. self._v_min = None
  58. return
  59. try:
  60. self._v_min = sympify(v_min)
  61. float(self._v_min.evalf())
  62. except TypeError:
  63. raise ValueError("v_min could not be interpreted as a number.")
  64. def get_v_max(self):
  65. return self._v_max
  66. def set_v_max(self, v_max):
  67. if v_max is None:
  68. self._v_max = None
  69. return
  70. try:
  71. self._v_max = sympify(v_max)
  72. float(self._v_max.evalf())
  73. except TypeError:
  74. raise ValueError("v_max could not be interpreted as a number.")
  75. def get_v_steps(self):
  76. return self._v_steps
  77. def set_v_steps(self, v_steps):
  78. if v_steps is None:
  79. self._v_steps = None
  80. return
  81. if isinstance(v_steps, int):
  82. v_steps = Integer(v_steps)
  83. elif not isinstance(v_steps, Integer):
  84. raise ValueError("v_steps must be an int or SymPy Integer.")
  85. if v_steps <= S.Zero:
  86. raise ValueError("v_steps must be positive.")
  87. self._v_steps = v_steps
  88. @require_all_args
  89. def get_v_len(self):
  90. return self.v_steps + 1
  91. v = property(get_v, set_v)
  92. v_min = property(get_v_min, set_v_min)
  93. v_max = property(get_v_max, set_v_max)
  94. v_steps = property(get_v_steps, set_v_steps)
  95. v_len = property(get_v_len)
  96. def fill_from(self, b):
  97. if b.v is not None:
  98. self.v = b.v
  99. if b.v_min is not None:
  100. self.v_min = b.v_min
  101. if b.v_max is not None:
  102. self.v_max = b.v_max
  103. if b.v_steps is not None:
  104. self.v_steps = b.v_steps
  105. @staticmethod
  106. def try_parse(*args):
  107. """
  108. Returns a PlotInterval if args can be interpreted
  109. as such, otherwise None.
  110. """
  111. if len(args) == 1 and isinstance(args[0], PlotInterval):
  112. return args[0]
  113. try:
  114. return PlotInterval(*args)
  115. except ValueError:
  116. return None
  117. def _str_base(self):
  118. return ",".join([str(self.v), str(self.v_min),
  119. str(self.v_max), str(self.v_steps)])
  120. def __repr__(self):
  121. """
  122. A string representing the interval in class constructor form.
  123. """
  124. return "PlotInterval(%s)" % (self._str_base())
  125. def __str__(self):
  126. """
  127. A string representing the interval in list form.
  128. """
  129. return "[%s]" % (self._str_base())
  130. @require_all_args
  131. def assert_complete(self):
  132. pass
  133. @require_all_args
  134. def vrange(self):
  135. """
  136. Yields v_steps+1 SymPy numbers ranging from
  137. v_min to v_max.
  138. """
  139. d = (self.v_max - self.v_min) / self.v_steps
  140. for i in range(self.v_steps + 1):
  141. a = self.v_min + (d * Integer(i))
  142. yield a
  143. @require_all_args
  144. def vrange2(self):
  145. """
  146. Yields v_steps pairs of SymPy numbers ranging from
  147. (v_min, v_min + step) to (v_max - step, v_max).
  148. """
  149. d = (self.v_max - self.v_min) / self.v_steps
  150. a = self.v_min + (d * S.Zero)
  151. for i in range(self.v_steps):
  152. b = self.v_min + (d * Integer(i + 1))
  153. yield a, b
  154. a = b
  155. def frange(self):
  156. for i in self.vrange():
  157. yield float(i.evalf())