eulumdat-plot 1.0.2__py3-none-any.whl → 1.0.4__py3-none-any.whl

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.
eulumdat_plot/__init__.py CHANGED
@@ -39,12 +39,14 @@ Public API
39
39
  Convert polar ``(r, θ)`` to NAT ``(x, y)`` Cartesian coordinates.
40
40
  """
41
41
 
42
- from .plot import plot_ldt
43
- from .renderer import Layout, make_svg, polar_to_nat
42
+ from .plot import plot_ldt, plot_ldt_svg
43
+ from .renderer import Layout, make_svg, make_svg_str, polar_to_nat
44
44
 
45
45
  __all__ = [
46
46
  "plot_ldt",
47
+ "plot_ldt_svg",
47
48
  "Layout",
48
49
  "make_svg",
50
+ "make_svg_str",
49
51
  "polar_to_nat",
50
52
  ]
eulumdat_plot/plot.py CHANGED
@@ -52,7 +52,7 @@ try:
52
52
  except ImportError:
53
53
  _HAS_SCIPY = False
54
54
 
55
- from .renderer import Layout, NatCurve, make_svg, polar_to_nat
55
+ from .renderer import Layout, NatCurve, make_svg, make_svg_str, polar_to_nat
56
56
 
57
57
 
58
58
  # ---------------------------------------------------------------------------
@@ -363,3 +363,83 @@ def plot_ldt(
363
363
  strokes_solid=strokes_solid,
364
364
  strokes_dotted=strokes_dotted,
365
365
  )
366
+
367
+
368
+ def plot_ldt_svg(
369
+ ldt_path: str | Path,
370
+ *,
371
+ code: str = "",
372
+ layout: Optional[Layout] = None,
373
+ interpolate: bool = True,
374
+ interp_step_deg: float = 1.0,
375
+ interp_method: str = "linear",
376
+ ) -> str:
377
+ """
378
+ Same as :func:`plot_ldt` but returns the SVG as a string instead of
379
+ writing to disk.
380
+
381
+ Returns
382
+ -------
383
+ str
384
+ SVG document as a string (starts with ``<svg``).
385
+ """
386
+ ldt_path = Path(ldt_path)
387
+ if layout is None:
388
+ layout = Layout()
389
+
390
+ ldt = LdtReader.read(ldt_path)
391
+
392
+ I_C0 = _get_plane(ldt, 0.0)
393
+ I_C90 = _get_plane(ldt, 90.0)
394
+ I_C180 = _get_plane(ldt, 180.0)
395
+ I_C270 = _get_plane(ldt, 270.0)
396
+
397
+ available = [p for p in (I_C0, I_C90, I_C180, I_C270) if p is not None]
398
+ if not available:
399
+ raise ValueError(f"No usable C-plane data found in '{ldt_path}'.")
400
+
401
+ r_data_max = float(np.vstack(available).max())
402
+
403
+ g_deg = np.asarray(ldt.header.g_angles, dtype=float)
404
+ if interpolate and g_deg.size > 1:
405
+ g_deg, (I_C0, I_C90, I_C180, I_C270) = _resample(
406
+ g_deg, I_C0, I_C90, I_C180, I_C270,
407
+ step_deg=interp_step_deg,
408
+ method=interp_method,
409
+ )
410
+
411
+ curves_solid: List[NatCurve] = []
412
+ curves_dotted: List[NatCurve] = []
413
+ colors_solid: List[str] = []
414
+ colors_dotted: List[str] = []
415
+ strokes_solid: List[float] = []
416
+ strokes_dotted: List[float] = []
417
+
418
+ def _register(arr_right, arr_left, *, solid: bool) -> None:
419
+ cr, cl = _build_nat_pair(g_deg, arr_right, arr_left)
420
+ for curve in (cr, cl):
421
+ if curve is None:
422
+ continue
423
+ if solid:
424
+ curves_solid.append(curve)
425
+ colors_solid.append("black")
426
+ strokes_solid.append(layout.stroke_curve_solid)
427
+ else:
428
+ curves_dotted.append(curve)
429
+ colors_dotted.append("black")
430
+ strokes_dotted.append(layout.stroke_curve_dotted)
431
+
432
+ _register(I_C0, I_C180, solid=True)
433
+ _register(I_C90, I_C270, solid=False)
434
+
435
+ return make_svg_str(
436
+ curves_solid=curves_solid,
437
+ curves_dotted=curves_dotted,
438
+ r_data_max=r_data_max,
439
+ code=code,
440
+ layout=layout,
441
+ colors_solid=colors_solid,
442
+ colors_dotted=colors_dotted,
443
+ strokes_solid=strokes_solid,
444
+ strokes_dotted=strokes_dotted,
445
+ )
eulumdat_plot/renderer.py CHANGED
@@ -257,12 +257,12 @@ def _nice_levels(r_max: float) -> List[int]:
257
257
  # SVG renderer
258
258
  # ---------------------------------------------------------------------------
259
259
 
260
- def make_svg(
260
+ def _build_drawing(
261
261
  curves_solid: List[NatCurve],
262
262
  curves_dotted: List[NatCurve],
263
263
  r_data_max: float,
264
264
  *,
265
- outfile: str | Path = "photometric.svg",
265
+ filename: str = "_",
266
266
  code: str = "",
267
267
  layout: Optional[Layout] = None,
268
268
  debug: bool = False,
@@ -270,42 +270,8 @@ def make_svg(
270
270
  colors_dotted: Optional[List[str]] = None,
271
271
  strokes_solid: Optional[List[float]] = None,
272
272
  strokes_dotted: Optional[List[float]] = None,
273
- ) -> Path:
274
- """
275
- Generate a Lumtopic-style photometric polar diagram as an SVG file.
276
-
277
- Parameters
278
- ----------
279
- curves_solid :
280
- Solid curves (typically C0 / C180), each as a list of
281
- ``(x_nat, y_nat)`` points.
282
- curves_dotted :
283
- Dotted curves (typically C90 / C270), same format.
284
- r_data_max :
285
- Maximum intensity across all curves (cd/klm).
286
- Drives the radial scale computation.
287
- outfile :
288
- Destination SVG path. Default: ``"photometric.svg"``.
289
- code :
290
- Distribution code shown in the banner centre (e.g. ``"D53"``).
291
- Pass an empty string to leave it blank.
292
- layout :
293
- Visual parameters. If ``None``, :class:`Layout` defaults are used.
294
- debug :
295
- If ``True``, draw the plot area in blue and the curve bounding box
296
- in green as diagnostic overlays.
297
- colors_solid / colors_dotted :
298
- Per-curve SVG stroke colours. Defaults to black for all curves.
299
- strokes_solid / strokes_dotted :
300
- Per-curve stroke widths. Defaults to ``layout.stroke_curve_solid``
301
- and ``layout.stroke_curve_dotted`` respectively.
302
-
303
- Returns
304
- -------
305
- :class:`pathlib.Path`
306
- Absolute path to the generated SVG file.
307
- """
308
- outfile = Path(outfile)
273
+ ) -> "svgwrite.Drawing":
274
+ """Build and return the svgwrite Drawing object (without saving)."""
309
275
  if layout is None:
310
276
  layout = Layout()
311
277
 
@@ -395,7 +361,7 @@ def make_svg(
395
361
  # ------------------------------------------------------------------
396
362
  # 6. Assemble SVG
397
363
  # ------------------------------------------------------------------
398
- dwg = svgwrite.Drawing(str(outfile), size=(W, H))
364
+ dwg = svgwrite.Drawing(filename, size=(W, H))
399
365
 
400
366
  # --- Clip path (plot area only) ---
401
367
  clip_id = "plot_clip"
@@ -508,5 +474,95 @@ def make_svg(
508
474
  stroke="green", stroke_width=5, fill="none",
509
475
  ))
510
476
 
477
+ return dwg
478
+
479
+
480
+ def make_svg(
481
+ curves_solid: List[NatCurve],
482
+ curves_dotted: List[NatCurve],
483
+ r_data_max: float,
484
+ *,
485
+ outfile: str | Path = "photometric.svg",
486
+ code: str = "",
487
+ layout: Optional[Layout] = None,
488
+ debug: bool = False,
489
+ colors_solid: Optional[List[str]] = None,
490
+ colors_dotted: Optional[List[str]] = None,
491
+ strokes_solid: Optional[List[float]] = None,
492
+ strokes_dotted: Optional[List[float]] = None,
493
+ ) -> Path:
494
+ """
495
+ Generate a Lumtopic-style photometric polar diagram as an SVG file.
496
+
497
+ Parameters
498
+ ----------
499
+ curves_solid :
500
+ Solid curves (typically C0 / C180), each as a list of
501
+ ``(x_nat, y_nat)`` points.
502
+ curves_dotted :
503
+ Dotted curves (typically C90 / C270), same format.
504
+ r_data_max :
505
+ Maximum intensity across all curves (cd/klm).
506
+ Drives the radial scale computation.
507
+ outfile :
508
+ Destination SVG path. Default: ``"photometric.svg"``.
509
+ code :
510
+ Distribution code shown in the banner centre (e.g. ``"D53"``).
511
+ Pass an empty string to leave it blank.
512
+ layout :
513
+ Visual parameters. If ``None``, :class:`Layout` defaults are used.
514
+ debug :
515
+ If ``True``, draw the plot area in blue and the curve bounding box
516
+ in green as diagnostic overlays.
517
+ colors_solid / colors_dotted :
518
+ Per-curve SVG stroke colours. Defaults to black for all curves.
519
+ strokes_solid / strokes_dotted :
520
+ Per-curve stroke widths. Defaults to ``layout.stroke_curve_solid``
521
+ and ``layout.stroke_curve_dotted`` respectively.
522
+
523
+ Returns
524
+ -------
525
+ :class:`pathlib.Path`
526
+ Absolute path to the generated SVG file.
527
+ """
528
+ outfile = Path(outfile)
529
+ dwg = _build_drawing(
530
+ curves_solid, curves_dotted, r_data_max,
531
+ filename=str(outfile),
532
+ code=code, layout=layout, debug=debug,
533
+ colors_solid=colors_solid, colors_dotted=colors_dotted,
534
+ strokes_solid=strokes_solid, strokes_dotted=strokes_dotted,
535
+ )
511
536
  dwg.save()
512
537
  return outfile.resolve()
538
+
539
+
540
+ def make_svg_str(
541
+ curves_solid: List[NatCurve],
542
+ curves_dotted: List[NatCurve],
543
+ r_data_max: float,
544
+ *,
545
+ code: str = "",
546
+ layout: Optional[Layout] = None,
547
+ debug: bool = False,
548
+ colors_solid: Optional[List[str]] = None,
549
+ colors_dotted: Optional[List[str]] = None,
550
+ strokes_solid: Optional[List[float]] = None,
551
+ strokes_dotted: Optional[List[float]] = None,
552
+ ) -> str:
553
+ """
554
+ Same as :func:`make_svg` but returns the SVG as a string instead of
555
+ writing to disk.
556
+
557
+ Returns
558
+ -------
559
+ str
560
+ SVG document as a string (starts with ``<svg``).
561
+ """
562
+ dwg = _build_drawing(
563
+ curves_solid, curves_dotted, r_data_max,
564
+ code=code, layout=layout, debug=debug,
565
+ colors_solid=colors_solid, colors_dotted=colors_dotted,
566
+ strokes_solid=strokes_solid, strokes_dotted=strokes_dotted,
567
+ )
568
+ return dwg.tostring()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eulumdat-plot
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: Photometric polar diagram generator for EULUMDAT (.ldt) files — extension to eulumdat-py
5
5
  Author: 123VincentB
6
6
  License: MIT
@@ -21,12 +21,13 @@ Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
22
  Requires-Python: >=3.9
23
23
  Description-Content-Type: text/markdown
24
+ License-File: LICENSE
24
25
  Requires-Dist: eulumdat-py>=1.0.0
25
26
  Requires-Dist: numpy>=1.21
26
27
  Requires-Dist: svgwrite>=1.4
28
+ Requires-Dist: vl-convert-python>=1.6
29
+ Requires-Dist: Pillow>=9.0
27
30
  Provides-Extra: export
28
- Requires-Dist: vl-convert-python>=1.6; extra == "export"
29
- Requires-Dist: Pillow>=9.0; extra == "export"
30
31
  Provides-Extra: cubic
31
32
  Requires-Dist: scipy>=1.7; extra == "cubic"
32
33
  Provides-Extra: full
@@ -37,12 +38,13 @@ Requires-Dist: build; extra == "dev"
37
38
  Requires-Dist: twine; extra == "dev"
38
39
  Requires-Dist: pytest>=7.0; extra == "dev"
39
40
  Requires-Dist: eulumdat-plot[full]; extra == "dev"
41
+ Dynamic: license-file
40
42
 
41
43
  # eulumdat-plot
42
44
 
43
45
  [![PyPI](https://img.shields.io/pypi/v/eulumdat-plot)](https://pypi.org/project/eulumdat-plot/)
44
46
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/eulumdat-plot)](https://pypi.org/project/eulumdat-plot/)
45
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/123VincentB/eulumdat-plot/blob/main/LICENSE)
47
+ [![License: MIT](https://img.shields.io/github/license/123VincentB/eulumdat-plot)](https://github.com/123VincentB/eulumdat-plot/blob/main/LICENSE)
46
48
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19096110.svg)](https://doi.org/10.5281/zenodo.19096110)
47
49
 
48
50
  Photometric polar diagram generator for EULUMDAT (`.ldt`) files —
@@ -105,13 +107,16 @@ pip install "eulumdat-plot[full]"
105
107
  ## Quick start
106
108
 
107
109
  ```python
108
- from eulumdat_plot import plot_ldt
110
+ from eulumdat_plot import plot_ldt, plot_ldt_svg
109
111
 
110
- # Generate an SVG next to the source file
111
- svg = plot_ldt("luminaire.ldt")
112
+ # Generate an SVG file next to the source file
113
+ path = plot_ldt("luminaire.ldt")
112
114
 
113
115
  # With a distribution code in the banner centre
114
- svg = plot_ldt("luminaire.ldt", code="D53")
116
+ path = plot_ldt("luminaire.ldt", code="D53")
117
+
118
+ # Get the SVG as a string (for inline HTML embedding, no file written)
119
+ svg_str = plot_ldt_svg("luminaire.ldt")
115
120
  ```
116
121
 
117
122
  ## Scaling
@@ -167,6 +172,23 @@ def plot_ldt(
167
172
  | `interp_method` | `"linear"` | `"linear"` or `"cubic"` (requires scipy) |
168
173
  | `debug` | `False` | Colour-code C-planes for visual validation |
169
174
 
175
+ ### `plot_ldt_svg()`
176
+
177
+ Same as `plot_ldt()` but returns the SVG as a **string** instead of writing to
178
+ disk. Useful for inline HTML embedding (no temporary file created).
179
+
180
+ ```python
181
+ def plot_ldt_svg(
182
+ ldt_path: str | Path,
183
+ *,
184
+ code: str = "",
185
+ layout: Layout | None = None,
186
+ interpolate: bool = True,
187
+ interp_step_deg: float = 1.0,
188
+ interp_method: str = "linear",
189
+ ) -> str
190
+ ```
191
+
170
192
  ### `Layout.for_size()`
171
193
 
172
194
  ```python
@@ -219,15 +241,20 @@ eulumdat-plot/
219
241
  └── README.md
220
242
  ```
221
243
 
222
- ## EULUMDAT ecosystem
244
+ ## eulumdat-* ecosystem
245
+
246
+ > **New to the ecosystem?** [eulumdat-quickstart](https://github.com/123VincentB/eulumdat-quickstart) — a step-by-step guide covering all 8 packages with working examples.
223
247
 
224
- | Package | Status | Description |
225
- | ------------------------------------------------------------------ | ------- | -------------------------------------------- |
226
- | [`eulumdat-py`](https://pypi.org/project/eulumdat-py/) | v0.1.4 | Read / write EULUMDAT files |
227
- | [`eulumdat-symmetry`](https://pypi.org/project/eulumdat-symmetry/) | v1.0.0 | Symmetrise EULUMDAT files |
228
- | `eulumdat-plot` | v1.0.0 | Photometric polar diagram — **this package** |
229
- | `eulumdat-luminance` | planned | Luminance table cd/m² 55°–85°) |
230
- | `eulumdat-ugr` | planned | UGR calculation (CIE 117, CIE 190) |
248
+ | Package | Description |
249
+ |---|---|
250
+ | [eulumdat-py](https://pypi.org/project/eulumdat-py/) | Read / write EULUMDAT files |
251
+ | [eulumdat-symmetry](https://pypi.org/project/eulumdat-symmetry/) | Symmetrise and detect ISYM |
252
+ | **`eulumdat-plot`** | **Polar intensity diagram (SVG/PNG) — this package** |
253
+ | [eulumdat-luminance](https://pypi.org/project/eulumdat-luminance/) | Luminance table and polar diagram |
254
+ | [eulumdat-ugr](https://pypi.org/project/eulumdat-ugr/) | UGR catalogue (CIE 117/190) |
255
+ | [eulumdat-analysis](https://pypi.org/project/eulumdat-analysis/) | Beam half-angle, FWHM |
256
+ | [eulumdat-report](https://pypi.org/project/eulumdat-report/) | Full photometric datasheet (HTML/PDF) |
257
+ | [eulumdat-ies](https://pypi.org/project/eulumdat-ies/) | LDT ↔ IES LM-63-2002 conversion |
231
258
 
232
259
  ## Requirements
233
260
 
@@ -0,0 +1,9 @@
1
+ eulumdat_plot/__init__.py,sha256=CBuQ_h9whhzjHicXgDruduTsagbCbnzZJ459EpigZy8,1647
2
+ eulumdat_plot/export.py,sha256=UOgugmd1jkFqoEkuQlY1dPatcMhv_JVQfV3Uv7oGkPg,4454
3
+ eulumdat_plot/plot.py,sha256=a4zcg8yUbFLczenzYQ_CjplrKyr3VPi_GGN0nULjuaA,14881
4
+ eulumdat_plot/renderer.py,sha256=YLM7D-_zRWNDPJbUoZz734_rdaSuRWIVRh-3emXlyHM,19609
5
+ eulumdat_plot-1.0.4.dist-info/licenses/LICENSE,sha256=C7zou5wilUMnyyvwyhL_QY0gLMRKlRiAgqw7ViCxNtc,1068
6
+ eulumdat_plot-1.0.4.dist-info/METADATA,sha256=MzLh5x4RA663ek2tRBIV87DYbi9IGzsaN8RQpdo1wic,10098
7
+ eulumdat_plot-1.0.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
8
+ eulumdat_plot-1.0.4.dist-info/top_level.txt,sha256=AsBUEzqi7316GhS_tHqXncJ5_pUaXb0Gm2ozfpeNQBA,14
9
+ eulumdat_plot-1.0.4.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 123VincentB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,8 +0,0 @@
1
- eulumdat_plot/__init__.py,sha256=QiFUpZjjX7ZrVtJ4Q2be6BltzVp4tMa2xw23Zix_PmU,1579
2
- eulumdat_plot/export.py,sha256=UOgugmd1jkFqoEkuQlY1dPatcMhv_JVQfV3Uv7oGkPg,4454
3
- eulumdat_plot/plot.py,sha256=dIhPKN-Su6rdwWVstY2k7YzsG3PM6px1LpcmD1UK-N0,12475
4
- eulumdat_plot/renderer.py,sha256=3Oxc7jFhM6DLFwOwKuZW9zQEA0LmaYxT2sZ2VfPhv1U,17901
5
- eulumdat_plot-1.0.2.dist-info/METADATA,sha256=8gLBb8Xl-xv7aiWz9D_Oz3JHdEBj50i29D8bBa1ugik,9458
6
- eulumdat_plot-1.0.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
7
- eulumdat_plot-1.0.2.dist-info/top_level.txt,sha256=AsBUEzqi7316GhS_tHqXncJ5_pUaXb0Gm2ozfpeNQBA,14
8
- eulumdat_plot-1.0.2.dist-info/RECORD,,