pyredshift 1.15__tar.gz → 1.17__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyredshift
3
- Version: 1.15
3
+ Version: 1.17
4
4
  Summary: Interactive redshifting of 1D astronomical spectra (Python successor of pdlredshift / redshift.f)
5
5
  Home-page: https://github.com/karlglazebrook/pyredshift
6
6
  Author: Karl Glazebrook
@@ -70,6 +70,7 @@ Requires python ≥ 3.9 with numpy, matplotlib, astropy and scipy.
70
70
 
71
71
  ```
72
72
  pyredshift spectrum.fits # format auto-detected
73
+ pyredshift https://host/spectrum.fits # straight from an archive URL
73
74
  pyredshift spectrum.fits -f sdss # force a format
74
75
  pyredshift spectrum.fits -z 2.19 # start from a known redshift
75
76
  pyredshift spectrum.fits --retro # retro PGPLOT-style black background
@@ -36,6 +36,7 @@ Requires python ≥ 3.9 with numpy, matplotlib, astropy and scipy.
36
36
 
37
37
  ```
38
38
  pyredshift spectrum.fits # format auto-detected
39
+ pyredshift https://host/spectrum.fits # straight from an archive URL
39
40
  pyredshift spectrum.fits -f sdss # force a format
40
41
  pyredshift spectrum.fits -z 2.19 # start from a known redshift
41
42
  pyredshift spectrum.fits --retro # retro PGPLOT-style black background
@@ -199,6 +199,27 @@ def read_outthere(hdul):
199
199
  return wav, spec
200
200
 
201
201
 
202
+ def fetch_url(url):
203
+ """Download a spectrum URL to a temporary file and return its path.
204
+ The URL's file extension is kept so format auto-detection still works."""
205
+ import shutil
206
+ import tempfile
207
+ import urllib.request
208
+ from urllib.parse import urlparse
209
+ suffix = os.path.splitext(urlparse(url).path)[1] or ".fits"
210
+ print("Downloading %s ..." % url)
211
+ fd, path = tempfile.mkstemp(prefix="pyredshift-", suffix=suffix)
212
+ try:
213
+ with urllib.request.urlopen(url, timeout=120) as resp, \
214
+ os.fdopen(fd, "wb") as out:
215
+ shutil.copyfileobj(resp, out)
216
+ except Exception as e:
217
+ os.unlink(path)
218
+ sys.exit("Could not download %s\n (%s)" % (url, e))
219
+ print(" %d bytes" % os.path.getsize(path))
220
+ return path
221
+
222
+
202
223
  def read_spectrum(fname, fmt=None):
203
224
  if not os.path.exists(fname):
204
225
  sys.exit("File %s not found" % fname)
@@ -270,7 +291,7 @@ def main():
270
291
  ap = argparse.ArgumentParser(
271
292
  prog="pyredshift",
272
293
  usage="pyredshift [-help] [-f FORMAT] [-z REDSHIFT] [--retro] "
273
- "[--microns] file",
294
+ "[--microns] file_or_URL",
274
295
  description="Interactive redshifting of 1D spectra "
275
296
  "(port of pdlredshift), v%s." % redshift_module.__version__,
276
297
  formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -278,7 +299,9 @@ def main():
278
299
  # -h epilog and the '?' help page cannot drift apart
279
300
  epilog=redshift_module.formats_text())
280
301
  ap.add_argument("-help", action="help", help=argparse.SUPPRESS)
281
- ap.add_argument("file", help="spectrum file (FITS, CSV or 2-column ascii)")
302
+ ap.add_argument("file", metavar="file_or_URL",
303
+ help="spectrum file (FITS, CSV or 2-column ascii), "
304
+ "or an http(s)/ftp URL of one")
282
305
  ap.add_argument("-f", "--format", default=None, metavar="FORMAT",
283
306
  help="force the input format instead of auto-detecting")
284
307
  ap.add_argument("-z", "--redshift", type=float, default=None,
@@ -292,14 +315,23 @@ def main():
292
315
  help=argparse.SUPPRESS) # deprecated alias for --retro
293
316
  args = ap.parse_args()
294
317
 
295
- wav, spec, has_wcs = read_spectrum(args.file, args.format)
318
+ # A URL instead of a file: download to a temp file, label by its name
319
+ fname, label, tmp = args.file, os.path.basename(args.file), None
320
+ if re.match(r"^(https?|ftp)://", args.file, re.I):
321
+ from urllib.parse import urlparse
322
+ tmp = fname = fetch_url(args.file)
323
+ label = os.path.basename(urlparse(args.file).path) or args.file
324
+
325
+ wav, spec, has_wcs = read_spectrum(fname, args.format)
326
+ if tmp is not None:
327
+ os.unlink(tmp) # arrays are in memory; the download can go
296
328
 
297
329
  if np.nanmax(wav) < 100 and has_wcs and not args.microns:
298
330
  print(" Detected microns -> Angstroms (--microns to keep)")
299
331
  wav = wav * 10000.0
300
332
 
301
333
  z = redshift_module.redshift(wav, spec, args.redshift,
302
- os.path.basename(args.file), dark=args.retro)
334
+ label, dark=args.retro)
303
335
  if z is not None:
304
336
  print("Final redshift = %.6g" % z)
305
337
 
@@ -13,7 +13,7 @@ from setuptools import setup
13
13
 
14
14
  setup(
15
15
  name="pyredshift",
16
- version="1.15",
16
+ version="1.17",
17
17
  description="Interactive redshifting of 1D astronomical spectra "
18
18
  "(Python successor of pdlredshift / redshift.f)",
19
19
  long_description=open("README.md").read(),
@@ -68,6 +68,16 @@ V1.14 - Saving works properly: the toolbar save button no longer
68
68
  - Lineage/credits at the top of the help page.
69
69
  V1.15 - Help-page credits link to the GitHub repo; lineage text in a
70
70
  readable muted grey in both themes.
71
+ V1.16 - Bare modifier presses are no longer input: ESC shift-O works
72
+ (the 'shift' keydown used to be read as the shortcut key), a
73
+ stray shift can't consume the second pick of x/y/e/m or close
74
+ the line menu.
75
+ - matplotlib 3.11 compatibility: keep full-figure blitting on
76
+ when another axes overlaps (3.11 would silently disable it on
77
+ tall windows), manage the cursor background ourselves.
78
+ V1.17 - An http(s)/ftp URL may be given instead of a file: downloaded
79
+ to a temp file (extension kept so auto-detection works, deleted
80
+ once read), window labelled with the URL's filename.
71
81
  """
72
82
 
73
83
  import ctypes
@@ -113,7 +123,7 @@ try:
113
123
  except AttributeError:
114
124
  pass
115
125
 
116
- __version__ = "1.15"
126
+ __version__ = "1.17"
117
127
 
118
128
  C_LIGHT = 2.99792458e8 # m/s
119
129
 
@@ -136,9 +146,11 @@ FORMAT_HELP = [
136
146
  ("csv", "comma-separated, header rows skipped"),
137
147
  ("ascii", "2-column text"),
138
148
  ]
139
- FORMAT_NOTES = ("Default is auto-detection. Wavelengths that look like "
140
- "microns are converted to Angstroms (--microns keeps them); "
141
- "NaNs are treated as bad pixels and plot as gaps.")
149
+ FORMAT_NOTES = ("Default is auto-detection. An http(s)/ftp URL may be given "
150
+ "instead of a file (downloaded to a temp file). Wavelengths "
151
+ "that look like microns are converted to Angstroms "
152
+ "(--microns keeps them); NaNs are treated as bad pixels "
153
+ "and plot as gaps.")
142
154
 
143
155
  CONFIG_FILE = os.path.expanduser("~/.pyredshift.json") # remembers window size
144
156
  DEFAULT_FIGSIZE = (13.0, 5.5) # inches
@@ -365,7 +377,19 @@ class StickyCursor(Cursor):
365
377
 
366
378
  def __init__(self, ax_, **kwargs):
367
379
  self._last_event = None
368
- super().__init__(ax_, **kwargs)
380
+ with warnings.catch_warnings():
381
+ # mpl 3.11 warns + disables useblit on overlapping axes;
382
+ # we re-assert it below, so don't let the warning through
383
+ warnings.simplefilter("ignore", UserWarning)
384
+ super().__init__(ax_, **kwargs)
385
+ # matplotlib 3.11 disables useblit when another axes overlaps (the
386
+ # '?' button can overlap on tall windows) - a guard our full-figure
387
+ # blit doesn't need; it also no longer initialises self.background
388
+ # (we manage it ourselves in clear())
389
+ self.useblit = self.canvas.supports_blit
390
+ self.linev.set_animated(self.useblit)
391
+ self.lineh.set_animated(self.useblit)
392
+ self.background = None
369
393
  self.linev.set_clip_on(False) # let the crosshair escape the box
370
394
  self.lineh.set_clip_on(False)
371
395
  self.connect_event("draw_event", self._redraw)
@@ -380,9 +404,10 @@ class StickyCursor(Cursor):
380
404
  self.background = self.canvas.copy_from_bbox(self.canvas.figure.bbox)
381
405
 
382
406
  def onmove(self, event):
383
- # Copy of Cursor.onmove from matplotlib 3.9, minus the widgetlock
384
- # check (version sensitive - revisit if matplotlib is upgraded),
385
- # with whole-window coords and full-figure blitting.
407
+ # Based on Cursor.onmove from matplotlib 3.9, minus the widgetlock
408
+ # check, with whole-window coords and full-figure blitting. Checked
409
+ # against matplotlib 3.11 (which moved to _save/_load_blit_background
410
+ # helpers - we keep our own self.background instead).
386
411
  if self.ignore(event):
387
412
  return
388
413
  xdata, ydata = surface_xy(self.ax, event)
@@ -443,6 +468,12 @@ class StickyCursor(Cursor):
443
468
  update_readout(readout_lastev)
444
469
 
445
470
 
471
+ # Pressing a modifier fires its own key_press_event before the combination
472
+ # (ESC shift-O used to read the bare 'shift' as the shortcut key)
473
+ MODIFIER_KEYS = ("shift", "control", "ctrl", "alt", "cmd", "super", "meta",
474
+ "caps_lock", "fn")
475
+
476
+
446
477
  def normkey(ch):
447
478
  # Some backends report shifted letters as 'shift+b' - normalise to 'B'
448
479
  if ch is not None and ch.startswith("shift+") and len(ch) == 7:
@@ -484,6 +515,8 @@ def pgband(allow_drag=False):
484
515
  return surface_xy(ax, ev)
485
516
 
486
517
  def on_key(ev):
518
+ if ev.key in MODIFIER_KEYS:
519
+ return # a bare modifier press is not input
487
520
  xd, yd = data_xy(ev)
488
521
  done(xd, yd, normkey(ev.key))
489
522
 
@@ -649,6 +682,8 @@ def line_menu(xd, yd):
649
682
  fig.canvas.stop_event_loop()
650
683
 
651
684
  def on_key(ev):
685
+ if ev.key in MODIFIER_KEYS:
686
+ return # don't let a bare shift press close the menu
652
687
  state["picked"] = None
653
688
  fig.canvas.stop_event_loop()
654
689
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyredshift
3
- Version: 1.15
3
+ Version: 1.17
4
4
  Summary: Interactive redshifting of 1D astronomical spectra (Python successor of pdlredshift / redshift.f)
5
5
  Home-page: https://github.com/karlglazebrook/pyredshift
6
6
  Author: Karl Glazebrook
@@ -70,6 +70,7 @@ Requires python ≥ 3.9 with numpy, matplotlib, astropy and scipy.
70
70
 
71
71
  ```
72
72
  pyredshift spectrum.fits # format auto-detected
73
+ pyredshift https://host/spectrum.fits # straight from an archive URL
73
74
  pyredshift spectrum.fits -f sdss # force a format
74
75
  pyredshift spectrum.fits -z 2.19 # start from a known redshift
75
76
  pyredshift spectrum.fits --retro # retro PGPLOT-style black background
File without changes
File without changes
File without changes