prefig 0.3.8.dev20250725054648__tar.gz → 0.3.9.dev20250727054417__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/PKG-INFO +1 -1
  2. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/math_utilities.py +14 -0
  3. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/polygon.py +3 -0
  4. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/slope_field.py +77 -48
  5. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/tags.py +1 -1
  6. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/user_namespace.py +7 -0
  7. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/schema/pf_schema.rnc +31 -1
  8. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/schema/pf_schema.rng +68 -0
  9. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/pyproject.toml +1 -1
  10. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/LICENSE +0 -0
  11. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/README.md +0 -0
  12. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/__init__.py +0 -0
  13. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/cli.py +0 -0
  14. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/CTM.py +0 -0
  15. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/__init__.py +0 -0
  16. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/annotations.py +0 -0
  17. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/area.py +0 -0
  18. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/arrow.py +0 -0
  19. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/axes.py +0 -0
  20. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/calculus.py +0 -0
  21. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/circle.py +0 -0
  22. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/clip.py +0 -0
  23. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/compat.py +0 -0
  24. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/coordinates.py +0 -0
  25. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/definition.py +0 -0
  26. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/diagram.py +0 -0
  27. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/diffeqs.py +0 -0
  28. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/graph.py +0 -0
  29. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/grid_axes.py +0 -0
  30. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/group.py +0 -0
  31. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/implicit.py +0 -0
  32. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/label.py +0 -0
  33. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/label_tools.py +0 -0
  34. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/legend.py +0 -0
  35. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/line.py +0 -0
  36. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/network.py +0 -0
  37. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/parametric_curve.py +0 -0
  38. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/parse.py +0 -0
  39. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/path.py +0 -0
  40. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/point.py +0 -0
  41. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/read.py +0 -0
  42. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/rectangle.py +0 -0
  43. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/repeat.py +0 -0
  44. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/riemann_sum.py +0 -0
  45. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/shape.py +0 -0
  46. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/statistics.py +0 -0
  47. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/tangent_line.py +0 -0
  48. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/utilities.py +0 -0
  49. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/core/vector.py +0 -0
  50. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/engine.py +0 -0
  51. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/diagcess/diagcess.html +0 -0
  52. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/diagcess/diagcess.js +0 -0
  53. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/de-system.xml +0 -0
  54. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/derivatives.xml +0 -0
  55. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/diffeqs.xml +0 -0
  56. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/implicit.xml +0 -0
  57. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/projection.xml +0 -0
  58. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/riemann.xml +0 -0
  59. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/roots_of_unity.xml +0 -0
  60. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/examples/tangent.xml +0 -0
  61. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/fonts/Braille29.ttf +0 -0
  62. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/js/mj-sre-page.js +0 -0
  63. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/js/package.json +0 -0
  64. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/resources/template/pf_publication.xml +0 -0
  65. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/scripts/__init__.py +0 -0
  66. {prefig-0.3.8.dev20250725054648 → prefig-0.3.9.dev20250727054417}/prefig/scripts/install_mj.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prefig
3
- Version: 0.3.8.dev20250725054648
3
+ Version: 0.3.9.dev20250727054417
4
4
  Summary: An authoring system for mathematical diagrams
5
5
  Home-page: https://prefigure.org
6
6
  License: GPL-3.0-or-later
@@ -15,6 +15,9 @@ def set_diagram(d):
15
15
  # introduce some useful mathematical operations
16
16
  # that are meant to be available to authors
17
17
 
18
+ def ln(x):
19
+ return math.log(x)
20
+
18
21
  def dot(u, v):
19
22
  return np.dot(np.array(u), np.array(v))
20
23
 
@@ -80,6 +83,17 @@ def rotate(v, theta):
80
83
  def deriv(f, a):
81
84
  return calculus.derivative(f, a)
82
85
 
86
+ def grad(f, a):
87
+ a = list(a)
88
+ grad = []
89
+ for j in range(len(a)):
90
+ def f_trace(x):
91
+ b = a[:]
92
+ b[j] = x
93
+ return f(*b)
94
+ grad.append(calculus.derivative(f_trace, a[j]))
95
+ return np.array(grad)
96
+
83
97
  def zip_lists(a, b):
84
98
  return list(zip(a, b))
85
99
 
@@ -188,6 +188,9 @@ def spline(element, diagram, parent, outline_status):
188
188
 
189
189
  cs = CubicSpline(t_vals, points, bc_type=bc)
190
190
 
191
+ if element.get('name', None) is not None:
192
+ un.enter_function(element.get('name'), cs)
193
+
191
194
  N = un.valid_eval(element.get('N', '100'))
192
195
  domain = element.get('domain', None)
193
196
  if domain is not None:
@@ -11,6 +11,7 @@ from . import math_utilities as math_util
11
11
  from . import calculus
12
12
 
13
13
  log = logging.getLogger('prefigure')
14
+ np.seterr(divide="ignore", invalid="ignore")
14
15
 
15
16
  # Add a graphical element for slope fields
16
17
  def slope_field(element, diagram, parent, outline_status):
@@ -140,52 +141,95 @@ def vector_field(element, diagram, parent, outline_status):
140
141
  else:
141
142
  line_template.set('stroke', element.get('stroke', 'blue'))
142
143
  line_template.set('thickness', element.get('thickness', '2'))
143
- if element.get('arrows', 'yes') == 'yes':
144
- line_template.set('arrows', '1')
144
+ line_template.set('arrows', '1')
145
145
 
146
146
  if element.get('arrow-width', None) is not None:
147
147
  line_template.set('arrow-width', element.get('arrow-width'))
148
148
  if element.get('arrow-angles', None) is not None:
149
149
  line_template.set('arrow-angles', element.get('arrow-angles'))
150
150
 
151
- spacings = element.get('spacings', None)
152
- if spacings is not None:
151
+ field_data = []
152
+ if element.get('curve', None) is not None:
153
+ curve = un.valid_eval(element.get('curve'))
153
154
  try:
154
- spacings = un.valid_eval(spacings)
155
- rx, ry = spacings
155
+ domain = un.valid_eval(element.get('domain'))
156
156
  except:
157
- log.error(f"Error parsing slope-field attribute @spacings={element.get('spacings')}")
157
+ log.error('A @domain is needed if adding a vector field to a curve')
158
+ return
159
+ try:
160
+ N = un.valid_eval(element.get('N'))
161
+ except:
162
+ log.error('A @N is needed if adding a vector field to a curve')
158
163
  return
159
- else:
160
- rx = grid_axes.find_gridspacing((bbox[0], bbox[2]))
161
- ry = grid_axes.find_gridspacing((bbox[1], bbox[3]))
162
164
 
163
- # we will go through and generate the vectors first
164
- # since we'll need to scale them
165
- field_data = []
166
- max_scale = 0
167
- x = rx[0]
168
- while x <= rx[2]:
169
- y = ry[0]
170
- while y <= ry[2]:
171
- f_value = f(x, y)
165
+ t = domain[0]
166
+ # if "f" a function of t or (x,y)?
167
+ one_variable = True
168
+ try:
169
+ f(t)
170
+ except TypeError:
171
+ one_variable = False
172
+
173
+ dt = (domain[1]-domain[0])/(N-1)
174
+ for _ in range(N):
175
+ position = curve(t)
176
+ if one_variable:
177
+ field_data.append([position, f(t)])
178
+ else:
179
+ field_data.append([position, f(*position)])
180
+ t += dt
181
+ scale_factor = un.valid_eval(element.get('scale', '1'))
182
+
183
+ else:
184
+ spacings = element.get('spacings', None)
185
+ if spacings is not None:
172
186
  try:
173
- if len(f_value) != 2:
174
- log.error("Only two-dimensional vector fields are supported")
175
- return;
187
+ spacings = un.valid_eval(spacings)
188
+ rx, ry = spacings
176
189
  except:
177
- pass
178
- max_scale = max(max_scale,
179
- abs((f_value[0])/rx[1]),
180
- abs((f_value[1])/ry[1]))
181
- field_data.append([np.array([x,y]), f_value])
182
- y += ry[1]
183
- x += rx[1]
190
+ log.error(f"Error parsing slope-field attribute @spacings={element.get('spacings')}")
191
+ return
192
+ else:
193
+ rx = grid_axes.find_gridspacing((bbox[0], bbox[2]))
194
+ ry = grid_axes.find_gridspacing((bbox[1], bbox[3]))
195
+
196
+ # we will go through and generate the vectors first
197
+ # since we'll need to scale them
198
+ max_scale = 0
199
+ exponent = un.valid_eval(element.get('exponent', '1'))
200
+ x = rx[0]
201
+ while x <= rx[2]:
202
+ y = ry[0]
203
+ while y <= ry[2]:
204
+ f_value = f(x, y)
205
+ if any(np.isnan(f_value)):
206
+ y += ry[1]
207
+ continue
184
208
 
185
- scale_factor = min(1, 0.75 / max_scale)
186
- if element.get('scale') is not None:
187
- scale = un.valid_eval(element.get('scale'))
188
- scale_factor = scale
209
+ try:
210
+ if len(f_value) != 2:
211
+ log.error("Only two-dimensional vector fields are supported")
212
+ return;
213
+ except:
214
+ pass
215
+ norm = math_util.length(f_value)
216
+ if norm < 1e-10:
217
+ f_value = np.array((0,0))
218
+ else:
219
+ # we will scale the length by length**exponent
220
+ # to promote the length of shorter vectors
221
+ f_value = norm**exponent * (1/norm * f_value)
222
+ max_scale = max(max_scale,
223
+ abs((f_value[0])/rx[1]),
224
+ abs((f_value[1])/ry[1]))
225
+ field_data.append([np.array([x,y]), f_value])
226
+ y += ry[1]
227
+ x += rx[1]
228
+
229
+ scale_factor = min(1, 0.75 / max_scale)
230
+ if element.get('scale') is not None:
231
+ scale = un.valid_eval(element.get('scale'))
232
+ scale_factor = scale
189
233
 
190
234
  for datum in field_data:
191
235
  p, v = datum
@@ -205,18 +249,3 @@ def vector_field(element, diagram, parent, outline_status):
205
249
 
206
250
  group.group(element, diagram, parent, outline_status)
207
251
 
208
- def gradient(element, diagram, parent, outline_status):
209
- try:
210
- f = un.valid_eval(element.get("function"))
211
- except:
212
- log.error("Error retrieving function in gradient element")
213
- return
214
-
215
- def grad(a, b):
216
- f_x_trace = lambda x: f(x, b)
217
- f_y_trace = lambda y: f(a, y)
218
- return np.array([calculus.derivative(f_x_trace, a),
219
- calculus.derivative(f_y_trace, b)])
220
- un.enter_namespace("__grad", grad)
221
- element.set("function", "__grad")
222
- vector_field(element, diagram, parent, outline_status)
@@ -41,11 +41,11 @@ tag_dict = {
41
41
  'caption': label.caption,
42
42
  'circle': circle.circle,
43
43
  'clip': clip.clip,
44
+ 'contour': implicit.implicit_curve,
44
45
  'coordinates': coordinates.coordinates,
45
46
  'definition': definition.definition,
46
47
  'derivative': definition.derivative,
47
48
  'ellipse': circle.ellipse,
48
- 'gradient': slope_field.gradient,
49
49
  'graph': graph.graph,
50
50
  'grid': grid_axes.grid,
51
51
  'grid-axes': grid_axes.grid_axes,
@@ -66,6 +66,8 @@ def validate_node(node, args=None):
66
66
  return True
67
67
  if isinstance(node, ast.Expression):
68
68
  return validate_node(node.body, args)
69
+ if isinstance(node, ast.Starred):
70
+ return validate_node(node.value)
69
71
  if isinstance(node, ast.Name):
70
72
  if node.id in variables:
71
73
  return True
@@ -170,6 +172,11 @@ def derivative(f, name):
170
172
  functions.add(name)
171
173
  variables.add(name)
172
174
 
175
+ def enter_function(name, f):
176
+ globals()[name] = f
177
+ functions.add(name)
178
+ variables.add(name)
179
+
173
180
  def enter_namespace(name, value):
174
181
  globals()[name] = value
175
182
  variables.add(name)
@@ -313,6 +313,7 @@ GraphicalElements =
313
313
  Area-Under-Curve* &
314
314
  Axes* &
315
315
  Circle* &
316
+ Contour* &
316
317
  Ellipse* &
317
318
  Graph* &
318
319
  Grid* &
@@ -337,7 +338,8 @@ GraphicalElements =
337
338
  Tick-Mark* &
338
339
  Tangent-line* &
339
340
  Triangle* &
340
- Vector*
341
+ Vector* &
342
+ Vector-Field*
341
343
  )
342
344
 
343
345
  Angle-Marker = element angle-marker {
@@ -433,6 +435,7 @@ Grid = element grid {
433
435
  attribute coordinates {text}?,
434
436
  attribute spacing-degrees {"yes"|"no"}?,
435
437
  attribute scales {"linear"|"semilogx"|"semilogy"|"loglog"}?,
438
+ Stroke-Attributes,
436
439
  CommonAttributes
437
440
  }
438
441
 
@@ -457,6 +460,7 @@ Grid-Axes = element grid-axes {
457
460
  attribute h-zero-label {"yes"|"no"}?,
458
461
  attribute v-zero-label {"yes"|"no"}?,
459
462
  attribute label-commas {"yes"|"no"}?,
463
+ StrokeAttributes,
460
464
  CommonAttributes,
461
465
  XLabel?,
462
466
  YLabel?
@@ -469,10 +473,21 @@ Tick-Mark = element tick-mark {
469
473
  attribute stroke {text}?,
470
474
  attribute size {text}?,
471
475
  attribute thickness {text}?,
476
+ StrokeAttributes,
472
477
  LabelAttributes,
473
478
  LabelText?
474
479
  }
475
480
 
481
+ Contour = element contour {
482
+ attribute at {text}?,
483
+ attribute function {text},
484
+ attribute k {text}?,
485
+ attribute depth {text}?,
486
+ attribute initial-depth {text}?,
487
+ StrokeAttributes,
488
+ CommonAttributes
489
+ }
490
+
476
491
  Circle = element circle {
477
492
  attribute at {text}?,
478
493
  attribute center {text},
@@ -744,6 +759,7 @@ Spline = element spline {
744
759
  attribute closed {"yes"|"no"}?,
745
760
  attribute arrow-width {text}?,
746
761
  attribute arrow-angles {text}?,
762
+ attribute name {text}?,
747
763
  FillAttributes,
748
764
  CommonAttributes
749
765
  }
@@ -781,4 +797,18 @@ Vector = element vector {
781
797
  CommonAttributes
782
798
  }
783
799
 
800
+ Vector-Field = element vector-field {
801
+ attribute at {text}?,
802
+ attribute function {text}?,
803
+ attribute spacings {text}?,
804
+ attribute scale {text}?,
805
+ attribute curve {text}?,
806
+ attribute domain {text}?,
807
+ attribute N {text}?,
808
+ attribute arrow-width {text}?,
809
+ attribute arrow-angles {text?}?,
810
+ StrokeAttributes,
811
+ CommonAttributes
812
+ }
813
+
784
814
  }
@@ -762,6 +762,9 @@
762
762
  <zeroOrMore>
763
763
  <ref name="Circle"/>
764
764
  </zeroOrMore>
765
+ <zeroOrMore>
766
+ <ref name="Contour"/>
767
+ </zeroOrMore>
765
768
  <zeroOrMore>
766
769
  <ref name="Ellipse"/>
767
770
  </zeroOrMore>
@@ -837,6 +840,9 @@
837
840
  <zeroOrMore>
838
841
  <ref name="Vector"/>
839
842
  </zeroOrMore>
843
+ <zeroOrMore>
844
+ <ref name="Vector-Field"/>
845
+ </zeroOrMore>
840
846
  </interleave>
841
847
  </define>
842
848
  <define name="Angle-Marker">
@@ -1176,6 +1182,7 @@
1176
1182
  </choice>
1177
1183
  </attribute>
1178
1184
  </optional>
1185
+ <ref name="Stroke-Attributes"/>
1179
1186
  <ref name="CommonAttributes"/>
1180
1187
  </element>
1181
1188
  </define>
@@ -1291,6 +1298,7 @@
1291
1298
  </choice>
1292
1299
  </attribute>
1293
1300
  </optional>
1301
+ <ref name="StrokeAttributes"/>
1294
1302
  <ref name="CommonAttributes"/>
1295
1303
  <optional>
1296
1304
  <ref name="XLabel"/>
@@ -1318,12 +1326,32 @@
1318
1326
  <optional>
1319
1327
  <attribute name="thickness"/>
1320
1328
  </optional>
1329
+ <ref name="StrokeAttributes"/>
1321
1330
  <ref name="LabelAttributes"/>
1322
1331
  <optional>
1323
1332
  <ref name="LabelText"/>
1324
1333
  </optional>
1325
1334
  </element>
1326
1335
  </define>
1336
+ <define name="Contour">
1337
+ <element name="contour">
1338
+ <optional>
1339
+ <attribute name="at"/>
1340
+ </optional>
1341
+ <attribute name="function"/>
1342
+ <optional>
1343
+ <attribute name="k"/>
1344
+ </optional>
1345
+ <optional>
1346
+ <attribute name="depth"/>
1347
+ </optional>
1348
+ <optional>
1349
+ <attribute name="initial-depth"/>
1350
+ </optional>
1351
+ <ref name="StrokeAttributes"/>
1352
+ <ref name="CommonAttributes"/>
1353
+ </element>
1354
+ </define>
1327
1355
  <define name="Circle">
1328
1356
  <element name="circle">
1329
1357
  <optional>
@@ -2029,6 +2057,9 @@
2029
2057
  <optional>
2030
2058
  <attribute name="arrow-angles"/>
2031
2059
  </optional>
2060
+ <optional>
2061
+ <attribute name="name"/>
2062
+ </optional>
2032
2063
  <ref name="FillAttributes"/>
2033
2064
  <ref name="CommonAttributes"/>
2034
2065
  </element>
@@ -2112,4 +2143,41 @@
2112
2143
  <ref name="CommonAttributes"/>
2113
2144
  </element>
2114
2145
  </define>
2146
+ <define name="Vector-Field">
2147
+ <element name="vector-field">
2148
+ <optional>
2149
+ <attribute name="at"/>
2150
+ </optional>
2151
+ <optional>
2152
+ <attribute name="function"/>
2153
+ </optional>
2154
+ <optional>
2155
+ <attribute name="spacings"/>
2156
+ </optional>
2157
+ <optional>
2158
+ <attribute name="scale"/>
2159
+ </optional>
2160
+ <optional>
2161
+ <attribute name="curve"/>
2162
+ </optional>
2163
+ <optional>
2164
+ <attribute name="domain"/>
2165
+ </optional>
2166
+ <optional>
2167
+ <attribute name="N"/>
2168
+ </optional>
2169
+ <optional>
2170
+ <attribute name="arrow-width"/>
2171
+ </optional>
2172
+ <optional>
2173
+ <attribute name="arrow-angles">
2174
+ <optional>
2175
+ <text/>
2176
+ </optional>
2177
+ </attribute>
2178
+ </optional>
2179
+ <ref name="StrokeAttributes"/>
2180
+ <ref name="CommonAttributes"/>
2181
+ </element>
2182
+ </define>
2115
2183
  </grammar>
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "prefig"
3
- version = "0.3.8.dev20250725054648"
3
+ version = "0.3.9.dev20250727054417"
4
4
  description = "An authoring system for mathematical diagrams"
5
5
  readme = "README.md"
6
6
  homepage = "https://prefigure.org"