fullplot 0.1.0__tar.gz → 0.1.1__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 (49) hide show
  1. {fullplot-0.1.0 → fullplot-0.1.1}/CHANGELOG.md +15 -0
  2. {fullplot-0.1.0 → fullplot-0.1.1}/PKG-INFO +253 -93
  3. {fullplot-0.1.0 → fullplot-0.1.1}/README.md +252 -92
  4. fullplot-0.1.1/examples/traces/11_shared_time_axis_window.py +28 -0
  5. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/TRACES.md +11 -6
  6. fullplot-0.1.1/pyproject.toml +89 -0
  7. fullplot-0.1.0/pyproject.toml → fullplot-0.1.1/pyproject.toml.orig +1 -1
  8. {fullplot-0.1.0 → fullplot-0.1.1}/src/fullplot/__init__.py +1 -1
  9. {fullplot-0.1.0 → fullplot-0.1.1}/src/fullplot/fullplot.py +187 -70
  10. {fullplot-0.1.0 → fullplot-0.1.1}/LICENSE +0 -0
  11. {fullplot-0.1.0 → fullplot-0.1.1}/THIRD_PARTY_LICENSES.md +0 -0
  12. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/0generate_plotting_data.py +0 -0
  13. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/10multidimensional_slices.py +0 -0
  14. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/11show_multiple_figures.py +0 -0
  15. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/12light_theme.py +0 -0
  16. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/13module_level_api.py +0 -0
  17. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/14save_formats.py +0 -0
  18. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/1inspect_hdf5.py +0 -0
  19. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/2single_trace.py +0 -0
  20. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/3multiple_traces.py +0 -0
  21. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/4dual_axis.py +0 -0
  22. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/5heatmap_2d_dataset.py +0 -0
  23. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/6heatmap_stacked_1d.py +0 -0
  24. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/7log_axes.py +0 -0
  25. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/8log_color_map.py +0 -0
  26. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/9multidimensional_line_traces.py +0 -0
  27. {fullplot-0.1.0 → fullplot-0.1.1}/examples/hdf5_plotting/PLOTTING.md +0 -0
  28. {fullplot-0.1.0 → fullplot-0.1.1}/examples/maps/1_generate_map.py +0 -0
  29. {fullplot-0.1.0 → fullplot-0.1.1}/examples/maps/2_axis_types.py +0 -0
  30. {fullplot-0.1.0 → fullplot-0.1.1}/examples/maps/3_metadata_and_outputs.py +0 -0
  31. {fullplot-0.1.0 → fullplot-0.1.1}/examples/maps/4_hdf5_layout.py +0 -0
  32. {fullplot-0.1.0 → fullplot-0.1.1}/examples/maps/MAPS.md +0 -0
  33. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/0_generate_trace_demo_file.py +0 -0
  34. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/10_windowed_trace_keeps_full_time.py +0 -0
  35. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/1_quick_hdf5_trace_plot.py +0 -0
  36. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/2_extract_trace_and_filter.py +0 -0
  37. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/3_create_redlines_bluelines.py +0 -0
  38. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/4_command_and_sequence_traces.py +0 -0
  39. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/5_trace_math_resample_error.py +0 -0
  40. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/6_window_scale_offset_derivative.py +0 -0
  41. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/7_save_processed_traces.py +0 -0
  42. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/8_missing_nan_values_create_gaps.py +0 -0
  43. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/9_shared_time_axis_alignment.py +0 -0
  44. {fullplot-0.1.0 → fullplot-0.1.1}/examples/traces/_trace_demo_data.py +0 -0
  45. {fullplot-0.1.0 → fullplot-0.1.1}/src/fullplot/cli.py +0 -0
  46. {fullplot-0.1.0 → fullplot-0.1.1}/src/fullplot/hdf5.py +0 -0
  47. {fullplot-0.1.0 → fullplot-0.1.1}/src/fullplot/maps.py +0 -0
  48. {fullplot-0.1.0 → fullplot-0.1.1}/src/fullplot/themes.py +0 -0
  49. {fullplot-0.1.0 → fullplot-0.1.1}/tests/test_imports.py +0 -0
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Added
6
+
7
+ * Added shared `TimeAxis.window(...)`, `clear_window()`, and `windowed(...)` support so every trace using the same time axis follows one common data window.
8
+ * Added `TimeAxis.full_values`, `raw_count`, `raw_duration`, `raw_dt_array`, `window_range`, and `has_window` for working with the original and active time ranges.
9
+ * Added `Trace.raw_y` so the original y-data remains available when a shared `TimeAxis` is windowed.
10
+ * Added `xlim`, `ylim`, and `y2lim` plotting arguments for display-only axis limits.
11
+
12
+ ### Changed
13
+
14
+ * Shared `TimeAxis` windowing now propagates automatically through attached traces, HDF5 trace extraction, and direct HDF5 plotting.
15
+ * `TimeAxis.count`, `duration`, `dt_array`, and related active-axis properties now describe the current window, while the new `raw_*` properties describe the complete source axis.
16
+ * Trace constructors that use a `TimeAxis` preserve the complete source-length data so windows can be changed or cleared later.
17
+
3
18
  ## 0.1.0
4
19
 
5
20
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fullplot
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: A documented HDF5 plotting, trace-processing, and map-generation package for engineering simulation and test data.
5
5
  Keywords: hdf5,plotting,engineering,simulation,test-data,map-generation,scientific-computing
6
6
  Author: Saaketh Ramoju
@@ -60,48 +60,14 @@ FullPlot does **not** require a special FullFlow file format. If your HDF5 file
60
60
 
61
61
  ---
62
62
 
63
- ## Repository status for 0.1.0
64
-
65
- FullPlot 0.1.0 is prepared as the first publish-ready public release of the package.
66
-
67
- There is no separate official documentation site yet, so the repository is intentionally documentation-heavy:
68
-
69
- * `README.md` is the primary user guide.
70
- * `CHANGELOG.md` records release-level changes and bug fixes.
71
- * `PUBLISHING.md` records the build, smoke-test, artifact-inspection, and upload checklist.
72
- * `THIRD_PARTY_LICENSES.md` records dependency and license notes.
73
- * `examples/` contains detailed runnable examples.
74
- * Public classes, functions, properties, and exceptions include docstrings so `help(fullplot.Trace)`, IDE inspection, and future generated API docs are useful immediately.
75
-
76
- The 0.1.0 release focuses on documentation, packaging, smoke testing, public API docstrings, and fixing obvious publish-blocking bugs. The core plotting, trace, and map-generation model is intentionally small.
77
-
78
- ---
79
-
80
63
  ## Installation
81
64
 
82
65
  ```bash
83
- pip install fullplot
66
+ pip3 install fullplot
84
67
  ```
85
68
 
86
69
  FullPlot requires Python 3.11 or newer.
87
70
 
88
- For local development from the repository:
89
-
90
- ```bash
91
- python -m venv .venv
92
- source .venv/bin/activate
93
- python -m pip install --upgrade pip
94
- python -m pip install -e .
95
- python -m pytest
96
- ```
97
-
98
- With `uv`:
99
-
100
- ```bash
101
- uv sync --dev
102
- uv run pytest
103
- ```
104
-
105
71
  ---
106
72
 
107
73
  ## Quick start
@@ -255,7 +221,7 @@ The main classes are:
255
221
  | --- | --- |
256
222
  | `H5File` | Lightweight handle for one HDF5 file and root group. Created with `fplt.open(...)`. |
257
223
  | `Trace` | Reusable one-dimensional x/y data object. Used for raw data, filtered data, generated limits, commands, and derived traces. |
258
- | `TimeAxis` | Shared shiftable time basis. Several traces can share one time axis and be shifted together. |
224
+ | `TimeAxis` | Shared shiftable and windowable time basis. Several traces can share one axis and follow the same alignment/window. |
259
225
  | `Axis` | Independent variable definition for rectangular-grid map generation. |
260
226
 
261
227
  Important exceptions are:
@@ -405,7 +371,7 @@ Shift the shared time axis so raw test time 95 seconds becomes model time zero:
405
371
  time.zero_at(95.0)
406
372
  ```
407
373
 
408
- All three traces now report shifted x-values because they share the same `TimeAxis` object.
374
+ All three traces shift because they share the same `TimeAxis` object.
409
375
 
410
376
  Use `align(...)` when matching a raw data time to a model time:
411
377
 
@@ -413,33 +379,59 @@ Use `align(...)` when matching a raw data time to a model time:
413
379
  time.align(data_time=95.0, model_time=0.0)
414
380
  ```
415
381
 
382
+ Window the shared time axis when every attached trace should use the same section of the test:
383
+
384
+ ```python
385
+ time.window(start=2.0, stop=6.5)
386
+
387
+ pc.x # only 2.0 ... 6.5 s
388
+ pc.y # matching PCMC samples
389
+ oipt.y # matching OIPT samples
390
+ fipt.y # matching FIPT samples
391
+ ```
392
+
393
+ The original arrays are preserved. Restore the full range with:
394
+
395
+ ```python
396
+ time.clear_window()
397
+ ```
398
+
399
+ Or create an independently windowed copy:
400
+
401
+ ```python
402
+ mainstage_time = time.windowed(2.0, 6.5)
403
+ ```
404
+
416
405
  Useful `TimeAxis` attributes:
417
406
 
418
407
  ```python
419
- time.raw # original samples
420
- time.values # shifted samples
421
- time.value # alias for values
422
- time.time # alias for values
423
- time.zero # current zero offset
424
- time.dt # median sample spacing
425
- time.dt_array # array of adjacent spacings
426
- time.duration # raw time span
427
- time.is_uniform # approximate uniform-spacing check
408
+ time.raw # original unshifted samples
409
+ time.full_values # all shifted samples before windowing
410
+ time.values # shifted samples in the active window
411
+ time.zero # current zero offset
412
+ time.count # active sample count
413
+ time.raw_count # original sample count
414
+ time.duration # active time span
415
+ time.raw_duration # original time span
416
+ time.window_range # (start, stop)
417
+ time.has_window # whether a shared window is active
428
418
  ```
429
419
 
420
+ For a trace that uses a shared `TimeAxis`, `trace.raw_y` gives the original y-array while `trace.y` follows the active time window.
421
+
430
422
  ---
431
423
 
432
424
  ## Missing values and windows
433
425
 
434
426
  FullPlot preserves non-finite y-values such as `NaN`. This is deliberate. Missing test-data samples should appear as gaps in plots instead of being connected by a misleading line.
435
427
 
436
- Create a windowed trace:
428
+ Use `TimeAxis.window(...)` when several traces should be cropped together. Use `Trace.window(...)` when only one trace should be valid over part of the otherwise unchanged time axis:
437
429
 
438
430
  ```python
439
431
  startup = pc.window(start=0.0, stop=3.0, name="Startup Window")
440
432
  ```
441
433
 
442
- `Trace.window(...)` keeps the full time axis and replaces values outside the window with `NaN`. This is useful when a solver or comparison routine should know that the trace only provides valid data inside a specific interval.
434
+ `Trace.window(...)` keeps its current x-axis and replaces y-values outside the interval with `NaN`. This is useful when a solver or comparison routine should treat one signal as unavailable outside that interval.
443
435
 
444
436
  Remove missing samples when you explicitly need compact finite data:
445
437
 
@@ -564,6 +556,7 @@ Trace metadata is stored as HDF5 attributes when possible.
564
556
  * HDF5 datasets and `Trace` objects in the same plot,
565
557
  * custom labels,
566
558
  * log x/y axes,
559
+ * display-only `xlim`, `ylim`, and `y2lim` limits,
567
560
  * dark and light themes,
568
561
  * saving to PNG, SVG, PDF, or any Matplotlib-supported output,
569
562
  * returning Matplotlib objects for custom edits.
@@ -581,6 +574,9 @@ fig, axes = run.plot(
581
574
  ylabel="Pressure [psia]",
582
575
  y2label="Command [-]",
583
576
  title="Pressure and Valve Command",
577
+ xlim=(2.0, 8.0),
578
+ ylim=(0.0, 500.0),
579
+ y2lim=(-0.1, 1.1),
584
580
  theme="light",
585
581
  save="pressure_command.svg",
586
582
  show=False,
@@ -603,42 +599,227 @@ For trace-only plotting:
603
599
  fplt.plot([pc, pc_filtered, redline])
604
600
  ```
605
601
 
602
+ Plot limits only change what is displayed; they do not window or modify the underlying trace data:
603
+
604
+ ```python
605
+ fplt.plot([pc, oipt], xlim=(2.0, 6.5))
606
+ ```
607
+
606
608
  ---
607
609
 
608
- ## Multidimensional datasets
610
+ ## Multidimensional datasets, axes, and slices
611
+
612
+ FullPlot can plot and trace 2D or higher-dimensional datasets by selecting one dimension to vary and holding the other dimensions fixed.
613
+
614
+ The two key arguments are:
609
615
 
610
- FullPlot can expand a 2D or higher-dimensional dataset into several line traces.
616
+ | Argument | Meaning |
617
+ | --- | --- |
618
+ | `axis` | The dataset dimension that remains as the plotted line direction. |
619
+ | `slice` | A dictionary of `{dimension_index: fixed_index}` values used to hold the other dimensions fixed. |
620
+
621
+ For a dataset with shape:
611
622
 
612
- Use `axis` to choose which dimension becomes the line direction:
623
+ ```text
624
+ (chamber_pressure, mixture_ratio, expansion_ratio, ambient_pressure, nfz)
625
+ ```
626
+
627
+ the dimension numbers are:
628
+
629
+ ```text
630
+ axis 0 -> chamber_pressure
631
+ axis 1 -> mixture_ratio
632
+ axis 2 -> expansion_ratio
633
+ axis 3 -> ambient_pressure
634
+ axis 4 -> nfz
635
+ ```
636
+
637
+ So this call plots a line that varies along chamber pressure:
613
638
 
614
639
  ```python
615
640
  run.plot(
616
- x="time",
617
- y="pressure_grid",
618
- axis=-1,
641
+ x="axes/chamber_pressure",
642
+ y="outputs/thrust_coefficient",
643
+ axis=0,
644
+ slice={
645
+ 1: 12, # fixed mixture_ratio index
646
+ 2: 10, # fixed expansion_ratio index
647
+ 3: 3, # fixed ambient_pressure index
648
+ 4: 0, # fixed nfz index
649
+ },
650
+ xlabel="Chamber Pressure [Pa]",
651
+ ylabel="Thrust Coefficient [-]",
619
652
  )
620
653
  ```
621
654
 
622
- Use `slice` to reduce higher-dimensional arrays before plotting:
655
+ The dimension selected by `axis` is the dimension that becomes the line. The dimensions listed in `slice` are reduced to one fixed index.
656
+
657
+ ### Creating traces from multidimensional data
658
+
659
+ `trace(...)` accepts the same `axis` and `slice` arguments as `plot(...)`. This makes it possible to create reusable traces from multidimensional map data and then plot them together.
623
660
 
624
661
  ```python
625
- run.plot(
626
- x="time",
627
- y="pressure_3d",
628
- slice={0: 1},
629
- axis=-1,
662
+ import fullplot as fplt
663
+
664
+ psia_to_pa = 6894.75728
665
+
666
+ file = fplt.open("sizer_lookups.h5")
667
+ result = file.at("/engine_lookup")
668
+
669
+ pc_psia = result.read("axes/chamber_pressure") / psia_to_pa
670
+
671
+ cf_eps_4 = result.trace(
672
+ y="outputs/thrust_coefficient",
673
+ x=pc_psia,
674
+ axis=0,
675
+ slice={
676
+ 1: 12, # mixture_ratio index
677
+ 2: 8, # expansion_ratio index
678
+ 3: 3, # ambient_pressure index
679
+ 4: 0, # nfz index
680
+ },
681
+ name="eps = 4",
682
+ )
683
+
684
+ cf_eps_6 = result.trace(
685
+ y="outputs/thrust_coefficient",
686
+ x=pc_psia,
687
+ axis=0,
688
+ slice={
689
+ 1: 12,
690
+ 2: 14,
691
+ 3: 3,
692
+ 4: 0,
693
+ },
694
+ name="eps = 6",
695
+ )
696
+
697
+ result.plot(
698
+ y=[cf_eps_4, cf_eps_6],
699
+ xlabel="Chamber Pressure [psia]",
700
+ ylabel="Thrust Coefficient [-]",
701
+ title="Thrust Coefficient vs Chamber Pressure",
630
702
  )
631
703
  ```
632
704
 
633
- The same idea applies to maps. A 3D dataset can become a 2D heat map after slicing:
705
+ This is equivalent to manually extracting:
634
706
 
635
707
  ```python
636
- run.map(
637
- z="temperature_3d",
638
- slice={0: 2},
708
+ cf[:, 12, 8, 3, 0] # eps = 4 trace
709
+ cf[:, 12, 14, 3, 0] # eps = 6 trace
710
+ ```
711
+
712
+ but keeps the plotting workflow trace-based.
713
+
714
+ ### Selecting nearest physical values
715
+
716
+ `slice` uses integer indices, not physical axis values. If you want to select the nearest value on an axis, use a small helper:
717
+
718
+ ```python
719
+ import numpy as np
720
+
721
+
722
+ def nearest_index(values, target):
723
+ values = np.asarray(values, dtype=float)
724
+ return int(np.argmin(np.abs(values - target)))
725
+ ```
726
+
727
+ Example:
728
+
729
+ ```python
730
+ mr = result.read("axes/mixture_ratio")
731
+ eps = result.read("axes/expansion_ratio")
732
+ pamb_psia = result.read("axes/ambient_pressure") / psia_to_pa
733
+ nfz = result.read("axes/nfz")
734
+
735
+ mr_i = nearest_index(mr, 2.5)
736
+ pamb_i = nearest_index(pamb_psia, 14.7)
737
+ nfz_i = nearest_index(nfz, 0)
738
+
739
+ traces = []
740
+
741
+ for target_eps in [2, 4, 6, 8, 10]:
742
+ eps_i = nearest_index(eps, target_eps)
743
+
744
+ traces.append(
745
+ result.trace(
746
+ y="outputs/thrust_coefficient",
747
+ x=pc_psia,
748
+ axis=0,
749
+ slice={
750
+ 1: mr_i,
751
+ 2: eps_i,
752
+ 3: pamb_i,
753
+ 4: nfz_i,
754
+ },
755
+ name=f"eps = {eps[eps_i]:.1f}",
756
+ )
757
+ )
758
+
759
+ result.plot(
760
+ y=traces,
761
+ xlabel="Chamber Pressure [psia]",
762
+ ylabel="Thrust Coefficient [-]",
763
+ title="Thrust Coefficient vs Chamber Pressure",
764
+ )
765
+ ```
766
+
767
+ ### Common slicing patterns
768
+
769
+ For a dataset ordered as:
770
+
771
+ ```text
772
+ (chamber_pressure, mixture_ratio, expansion_ratio, ambient_pressure, nfz)
773
+ ```
774
+
775
+ these are common one-dimensional traces:
776
+
777
+ ```python
778
+ cf[:, mr_i, eps_i, pamb_i, nfz_i] # vary chamber pressure
779
+ cf[pc_i, :, eps_i, pamb_i, nfz_i] # vary mixture ratio
780
+ cf[pc_i, mr_i, :, pamb_i, nfz_i] # vary expansion ratio
781
+ cf[pc_i, mr_i, eps_i, :, nfz_i] # vary ambient pressure
782
+ cf[pc_i, mr_i, eps_i, pamb_i, :] # vary nfz
783
+ ```
784
+
785
+ The matching FullPlot arguments are:
786
+
787
+ ```python
788
+ # Vary chamber pressure.
789
+ axis=0
790
+ slice={1: mr_i, 2: eps_i, 3: pamb_i, 4: nfz_i}
791
+
792
+ # Vary mixture ratio.
793
+ axis=1
794
+ slice={0: pc_i, 2: eps_i, 3: pamb_i, 4: nfz_i}
795
+
796
+ # Vary expansion ratio.
797
+ axis=2
798
+ slice={0: pc_i, 1: mr_i, 3: pamb_i, 4: nfz_i}
799
+ ```
800
+
801
+ ### Slicing for heat maps
802
+
803
+ For heat maps, leave two dimensions unsliced. For example, to plot thrust coefficient as a function of mixture ratio and chamber pressure, hold expansion ratio, ambient pressure, and `nfz` fixed:
804
+
805
+ ```python
806
+ result.map(
807
+ z="outputs/thrust_coefficient",
808
+ x="axes/mixture_ratio",
809
+ y="axes/chamber_pressure",
810
+ slice={
811
+ 2: eps_i,
812
+ 3: pamb_i,
813
+ 4: nfz_i,
814
+ },
815
+ xlabel="Mixture Ratio [-]",
816
+ ylabel="Chamber Pressure [Pa]",
817
+ zlabel="Thrust Coefficient [-]",
639
818
  )
640
819
  ```
641
820
 
821
+ Use `xscale="log"`, `yscale="log"`, or `zscale="log"` only when the displayed values on that axis are positive.
822
+
642
823
  ---
643
824
 
644
825
  ## Heat maps
@@ -917,40 +1098,19 @@ This is deliberate. The package is meant to be a simple bridge between HDF5 engi
917
1098
 
918
1099
  ---
919
1100
 
920
- ## Development checks
1101
+ # Documentation
921
1102
 
922
- Useful local checks:
1103
+ Full documentation:
923
1104
 
924
- ```bash
925
- python -m compileall -q src tests examples
926
- python -m pytest -q
927
- uv build
928
- ```
1105
+ https://saakethramoju.github.io/softwares/fullplot/
929
1106
 
930
- A minimal smoke test:
1107
+ Source code:
931
1108
 
932
- ```python
933
- import tempfile
934
- from pathlib import Path
935
-
936
- import h5py
937
- import numpy as np
938
- import fullplot as fplt
939
-
940
- with tempfile.TemporaryDirectory() as tmp:
941
- filename = Path(tmp) / "demo.h5"
1109
+ https://github.com/saakethramoju/FullPlot
942
1110
 
943
- with h5py.File(filename, "w") as h5:
944
- h5["time"] = np.linspace(0.0, 1.0, 11)
945
- h5["pressure"] = np.linspace(100.0, 200.0, 11)
1111
+ PyPI:
946
1112
 
947
- run = fplt.open(filename)
948
- time = run.time("time")
949
- pressure = run.trace("pressure", x=time)
950
- redline = fplt.Trace.constant("redline", x=time, y=250.0, role="redline")
951
- run.plot(x="time", y="pressure", show=False)
952
- fplt.plot([pressure, redline], show=False)
953
- ```
1113
+ https://pypi.org/project/fullplot/
954
1114
 
955
1115
  ---
956
1116