prefig 0.3.9.dev20250728054658__tar.gz → 0.3.9.dev20250730054824__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 (67) hide show
  1. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/PKG-INFO +1 -1
  2. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/__init__.py +1 -0
  3. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/axes.py +4 -4
  4. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/graph.py +4 -0
  5. prefig-0.3.9.dev20250730054824/prefig/core/image.py +127 -0
  6. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/path.py +25 -0
  7. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/rectangle.py +4 -2
  8. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/tags.py +2 -0
  9. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/schema/pf_schema.rnc +13 -0
  10. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/schema/pf_schema.rng +40 -0
  11. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/pyproject.toml +1 -1
  12. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/LICENSE +0 -0
  13. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/README.md +0 -0
  14. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/__init__.py +0 -0
  15. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/cli.py +0 -0
  16. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/CTM.py +0 -0
  17. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/annotations.py +0 -0
  18. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/area.py +0 -0
  19. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/arrow.py +0 -0
  20. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/calculus.py +0 -0
  21. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/circle.py +0 -0
  22. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/clip.py +0 -0
  23. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/compat.py +0 -0
  24. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/coordinates.py +0 -0
  25. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/definition.py +0 -0
  26. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/diagram.py +0 -0
  27. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/diffeqs.py +0 -0
  28. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/grid_axes.py +0 -0
  29. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/group.py +0 -0
  30. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/implicit.py +0 -0
  31. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/label.py +0 -0
  32. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/label_tools.py +0 -0
  33. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/legend.py +0 -0
  34. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/line.py +0 -0
  35. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/math_utilities.py +0 -0
  36. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/network.py +0 -0
  37. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/parametric_curve.py +0 -0
  38. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/parse.py +0 -0
  39. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/point.py +0 -0
  40. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/polygon.py +0 -0
  41. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/read.py +0 -0
  42. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/repeat.py +0 -0
  43. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/riemann_sum.py +0 -0
  44. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/shape.py +0 -0
  45. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/slope_field.py +0 -0
  46. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/statistics.py +0 -0
  47. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/tangent_line.py +0 -0
  48. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/user_namespace.py +0 -0
  49. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/utilities.py +0 -0
  50. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/core/vector.py +0 -0
  51. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/engine.py +0 -0
  52. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/diagcess/diagcess.html +0 -0
  53. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/diagcess/diagcess.js +0 -0
  54. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/de-system.xml +0 -0
  55. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/derivatives.xml +0 -0
  56. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/diffeqs.xml +0 -0
  57. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/implicit.xml +0 -0
  58. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/projection.xml +0 -0
  59. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/riemann.xml +0 -0
  60. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/roots_of_unity.xml +0 -0
  61. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/examples/tangent.xml +0 -0
  62. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/fonts/Braille29.ttf +0 -0
  63. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/js/mj-sre-page.js +0 -0
  64. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/js/package.json +0 -0
  65. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/resources/template/pf_publication.xml +0 -0
  66. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/prefig/scripts/__init__.py +0 -0
  67. {prefig-0.3.9.dev20250728054658 → prefig-0.3.9.dev20250730054824}/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.9.dev20250728054658
3
+ Version: 0.3.9.dev20250730054824
4
4
  Summary: An authoring system for mathematical diagrams
5
5
  Home-page: https://prefigure.org
6
6
  License: GPL-3.0-or-later
@@ -13,6 +13,7 @@ from . import (
13
13
  graph,
14
14
  grid_axes,
15
15
  group,
16
+ image,
16
17
  implicit,
17
18
  label,
18
19
  label_tools,
@@ -787,8 +787,8 @@ def tick_mark(element, diagram, parent, outline_status):
787
787
  size = un.valid_eval(element.get('size'))
788
788
  if not isinstance(size, np.ndarray):
789
789
  size = (size, size)
790
- else:
791
- size = (3,3)
790
+ else:
791
+ size = (3,3)
792
792
 
793
793
  if tactile:
794
794
  size = (18,0)
@@ -869,8 +869,8 @@ def tick_mark(element, diagram, parent, outline_status):
869
869
 
870
870
  if el_copy.get('alignment', None) is None:
871
871
  el_copy.set('alignment', align)
872
- if el_copy.get('offset', None) is None:
873
- el_copy.set('offset', off)
872
+ if el_copy.get('offset', None) is None:
873
+ el_copy.set('offset', off)
874
874
  el_copy.set("user-coords", "no")
875
875
  el_copy.set("anchor", util.pt2str(p, spacer=","))
876
876
  label.label(el_copy, diagram, parent, outline_status)
@@ -29,6 +29,10 @@ def graph(element, diagram, parent, outline_status = None):
29
29
  domain = [bbox[0], bbox[2]]
30
30
  else:
31
31
  domain = un.valid_eval(domain)
32
+ if domain[0] == -np.inf:
33
+ domain[0] = bbox[0]
34
+ if domain[1] == np.inf:
35
+ domain[1] = bbox[2]
32
36
 
33
37
  # if there are arrows, we need to pull the domain in by two pixels
34
38
  # so that the arrows don't go outside the domain
@@ -0,0 +1,127 @@
1
+ import lxml.etree as ET
2
+ import logging
3
+ import numpy as np
4
+ import base64
5
+ import lxml.etree as ET
6
+ from . import user_namespace as un
7
+ from . import group
8
+ from . import utilities as util
9
+ from . import CTM
10
+
11
+ log = logging.getLogger('prefigure')
12
+
13
+ type_dict = {'jpg':'jpeg',
14
+ 'jpeg':'jpeg',
15
+ 'png':'png',
16
+ 'gif':'gif',
17
+ 'svg':'svg'}
18
+
19
+ # Allows a block of XML to repeat with a changing parameter
20
+
21
+ def image(element, diagram, parent, outline_status):
22
+ if len(element) == 0:
23
+ log.error("An <image> must contain content to replace the image in a tactile build")
24
+ return;
25
+
26
+ if diagram.output_format() == 'tactile':
27
+ element.tag = 'group'
28
+ group.group(element, diagram, parent, outline_status)
29
+ return
30
+
31
+ source = element.get('source', None)
32
+ if source is None:
33
+ log.error("An <image> needs a @source attribute")
34
+ return
35
+ try:
36
+ ll = un.valid_eval(element.get('lower-left', '(0,0)'))
37
+ dims = un.valid_eval(element.get('dimensions', '(1,1)'))
38
+ center = element.get('center', None)
39
+ if center is not None:
40
+ center = un.valid_eval(center)
41
+ ll = center - 0.5 * dims
42
+ else:
43
+ center = ll + 0.5*dims
44
+ rotation = un.valid_eval(element.get('rotate', '0'))
45
+ scale = un.valid_eval(element.get('scale', '1'))
46
+ except:
47
+ log.error("Error parsing placement data in an <image>")
48
+ return
49
+
50
+ file_type = None
51
+ if element.get('filetype', None) is not None:
52
+ file_type = type_dict.get(element.get('filetype'), None)
53
+ if file_type is None:
54
+ suffix = source.split('.')[-1]
55
+ file_type = type_dict.get(suffix, None)
56
+ if file_type is None:
57
+ log.error(f"Cannot determine the type of image in {source}")
58
+ return
59
+
60
+ ll_svg = diagram.transform(ll)
61
+ ur_svg = diagram.transform(ll + dims)
62
+ center_svg = diagram.transform(center)
63
+ width, height = ur_svg - ll_svg
64
+ height = -height
65
+
66
+ if diagram.get_environment() == 'pretext':
67
+ source = 'data/' + source
68
+ else:
69
+ assets_dir = diagram.get_external()
70
+ if assets_dir is not None:
71
+ assets_dir = assets_dir.strip()
72
+ if assets_dir[-1] != '/':
73
+ assets_dir += '/'
74
+ source = assets_dir + source
75
+
76
+ opacity = element.get('opacity', None)
77
+ if opacity is not None:
78
+ opacity = un.valid_eval(opacity)
79
+ if file_type == 'svg':
80
+ svg_tree = ET.parse(source)
81
+ svg_root = svg_tree.getroot()
82
+ svg_width = svg_root.get('width', None)
83
+ svg_height = svg_root.get('height', None)
84
+
85
+ object = ET.SubElement(parent, 'foreignObject')
86
+ object.set('x', util.float2str(center_svg[0]-width/2))
87
+ object.set('y', util.float2str(center_svg[1]-height/2))
88
+ object.set('width', util.float2str(width))
89
+ object.set('height', util.float2str(height))
90
+ svg_root.set('width', '100%')
91
+ svg_root.set('height', '100%')
92
+ if svg_root.get('viewBox', None) is None:
93
+ svg_root.set('viewBox', f"0 0 {svg_width} {svg_height}")
94
+ object.append(svg_root)
95
+ diagram.add_id(object, element.get('id'))
96
+ svg_root.attrib.pop('id', None)
97
+ if opacity is not None:
98
+ object.set('opacity', util.float2str(opacity))
99
+ return
100
+
101
+ image_el = ET.SubElement(parent, 'image')
102
+ image_el.set('x', util.float2str(-width/2))
103
+ image_el.set('y', util.float2str(-height/2))
104
+ image_el.set('width', util.float2str(width))
105
+ image_el.set('height', util.float2str(height))
106
+ if opacity is not None:
107
+ image_el.set('opacity', util.float2str(opacity))
108
+ diagram.add_id(image_el, element.get('id'))
109
+
110
+ with open(source, "rb") as image_file:
111
+ encoded_string = base64.b64encode(image_file.read())
112
+ encoded_string = encoded_string.decode('utf-8')
113
+ ref = f"data:image/{file_type};base64,{encoded_string}"
114
+ image_el.set('href', ref)
115
+
116
+ transform_pieces = [CTM.translatestr(*center_svg)]
117
+
118
+ if isinstance(scale, np.ndarray):
119
+ transform_pieces.append(CTM.scalestr(*scale))
120
+ elif scale != '1':
121
+ transform_pieces.append(f"scale({scale})")
122
+
123
+ if rotation != 0:
124
+ transform_pieces.append(f"rotate({-rotation})")
125
+
126
+ image_el.set('transform', ' '.join(transform_pieces))
127
+
@@ -480,6 +480,31 @@ def decorate(child, diagram, current_point, cmds):
480
480
  cmds += ['L', util.pt2str(ctm.transform((x_pos,0)))]
481
481
  cmds += ['L', util.pt2str(ctm.transform((length, 0)))]
482
482
 
483
+ if decoration_data[0] == 'ragged':
484
+ # offset, step
485
+ try:
486
+ data = [d.split('=') for d in decoration_data[1:]]
487
+ data = {k:v for k, v in data}
488
+ except:
489
+ log.error("Error in wave decoration data")
490
+ return
491
+ try:
492
+ offset = un.valid_eval(data['offset'])
493
+ step = un.valid_eval(data['step'])
494
+ except:
495
+ log.error("Error in retrieving the step and an offset in a ragged decoration")
496
+
497
+ np.random.seed(int(data.get('seed','1')))
498
+ x_pos = 0
499
+ y_pos = 0
500
+ p = ctm.transform((0,0))
501
+ cmds += ['L', util.pt2str(ctm.transform((0,0)))]
502
+ while x_pos < length-step:
503
+ y_pos = 2 * offset * (np.random.random()-0.5)
504
+ x_pos += (0.5*np.random.random()+0.75)*step
505
+ cmds += ['L', util.pt2str(ctm.transform((x_pos,y_pos)))]
506
+ cmds += ['L', util.pt2str(ctm.transform((length, 0)))]
507
+
483
508
  if decoration_data[0] == 'capacitor':
484
509
  try:
485
510
  data = [d.split('=') for d in decoration_data[1:]]
@@ -71,9 +71,11 @@ def rectangle(element, diagram, parent, outline_status):
71
71
  path.set('d', ' '.join(cmds))
72
72
 
73
73
  if diagram.output_format() == 'tactile':
74
- if element.get('stroke') is not None:
74
+ stroke = element.get('stroke')
75
+ fill = element.get('fill')
76
+ if stroke is not None and stroke != 'none':
75
77
  element.set('stroke', 'black')
76
- if element.get('fill') is not None:
78
+ if fill is not None and fill != 'none':
77
79
  element.set('fill', 'lightgray')
78
80
  else:
79
81
  util.set_attr(element, 'stroke', 'none')
@@ -11,6 +11,7 @@ from . import definition
11
11
  from . import graph
12
12
  from . import grid_axes
13
13
  from . import group
14
+ from . import image
14
15
  from . import implicit
15
16
  from . import label
16
17
  from . import legend
@@ -51,6 +52,7 @@ tag_dict = {
51
52
  'grid-axes': grid_axes.grid_axes,
52
53
  'group': group.group,
53
54
  'histogram': statistics.histogram,
55
+ 'image': image.image,
54
56
  'implicit-curve': implicit.implicit_curve,
55
57
  'label': label.label,
56
58
  'legend': legend.legend,
@@ -319,6 +319,7 @@ GraphicalElements =
319
319
  Grid* &
320
320
  Grid-Axes* &
321
321
  Histogram* &
322
+ Image*&
322
323
  Implicit-Curve* &
323
324
  Label* &
324
325
  Legend* &
@@ -520,6 +521,18 @@ Graph = element graph {
520
521
  CommonAttributes
521
522
  }
522
523
 
524
+ Image = element image {
525
+ attribute at {text}?,
526
+ attribute source{text},
527
+ attribute lower-left {text}?,
528
+ attribute center {text}?,
529
+ attribute dimensions {text}?,
530
+ attribute opacity {text}?,
531
+ attribute filetype {"svg"|"png"|"gif"|"jpeg"|"jpg"}?,
532
+ attribute rotate {text}?,
533
+ attribute scale {text}?
534
+ }
535
+
523
536
  Histogram = element histogram {
524
537
  attribute at {text}?,
525
538
  attribute data {text},
@@ -780,6 +780,9 @@
780
780
  <zeroOrMore>
781
781
  <ref name="Histogram"/>
782
782
  </zeroOrMore>
783
+ <zeroOrMore>
784
+ <ref name="Image"/>
785
+ </zeroOrMore>
783
786
  <zeroOrMore>
784
787
  <ref name="Implicit-Curve"/>
785
788
  </zeroOrMore>
@@ -1430,6 +1433,43 @@
1430
1433
  <ref name="CommonAttributes"/>
1431
1434
  </element>
1432
1435
  </define>
1436
+ <define name="Image">
1437
+ <element name="image">
1438
+ <optional>
1439
+ <attribute name="at"/>
1440
+ </optional>
1441
+ <attribute name="source"/>
1442
+ <optional>
1443
+ <attribute name="lower-left"/>
1444
+ </optional>
1445
+ <optional>
1446
+ <attribute name="center"/>
1447
+ </optional>
1448
+ <optional>
1449
+ <attribute name="dimensions"/>
1450
+ </optional>
1451
+ <optional>
1452
+ <attribute name="opacity"/>
1453
+ </optional>
1454
+ <optional>
1455
+ <attribute name="filetype">
1456
+ <choice>
1457
+ <value>svg</value>
1458
+ <value>png</value>
1459
+ <value>gif</value>
1460
+ <value>jpeg</value>
1461
+ <value>jpg</value>
1462
+ </choice>
1463
+ </attribute>
1464
+ </optional>
1465
+ <optional>
1466
+ <attribute name="rotate"/>
1467
+ </optional>
1468
+ <optional>
1469
+ <attribute name="scale"/>
1470
+ </optional>
1471
+ </element>
1472
+ </define>
1433
1473
  <define name="Histogram">
1434
1474
  <element name="histogram">
1435
1475
  <optional>
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "prefig"
3
- version = "0.3.9.dev20250728054658"
3
+ version = "0.3.9.dev20250730054824"
4
4
  description = "An authoring system for mathematical diagrams"
5
5
  readme = "README.md"
6
6
  homepage = "https://prefigure.org"