pyredshift 1.9__tar.gz → 1.10__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.
- {pyredshift-1.9 → pyredshift-1.10}/PKG-INFO +4 -2
- {pyredshift-1.9 → pyredshift-1.10}/README.md +3 -1
- {pyredshift-1.9 → pyredshift-1.10}/setup.py +1 -1
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift/pyredshift-help.html +5 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift/redshift.py +104 -31
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift.egg-info/PKG-INFO +4 -2
- {pyredshift-1.9 → pyredshift-1.10}/LICENSE +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/pyproject.toml +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/pyredshift +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/setup.cfg +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift/__init__.py +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift/pyredshift.lines +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift.egg-info/SOURCES.txt +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift.egg-info/dependency_links.txt +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift.egg-info/requires.txt +0 -0
- {pyredshift-1.9 → pyredshift-1.10}/src/pyredshift.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyredshift
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10
|
|
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
|
|
@@ -134,7 +134,9 @@ short guide in separate tabs. The essentials:
|
|
|
134
134
|
- **Navigate**: drag the mouse for a rubber-band zoom (a purely horizontal
|
|
135
135
|
drag zooms X only), `z`/`u` and `i`/`o` zoom about the cursor, `[` `]`
|
|
136
136
|
pan, `w` whole range, `a` autoscale, `h` home. The matplotlib toolbar
|
|
137
|
-
works too and stays in sync.
|
|
137
|
+
works too and stays in sync. As in PGPLOT the cursor works over the
|
|
138
|
+
whole window — press `x`/`y`/`e` just outside the axis to select a
|
|
139
|
+
range flush with the plot edge.
|
|
138
140
|
- **Analyse**: `b` bin, `s` smooth, `_` iterative continuum fit,
|
|
139
141
|
`m` equivalent width and line flux, `B` zap artefacts, `p` print to PDF.
|
|
140
142
|
- **Quit**: `q` — the final redshift is reported on the terminal.
|
|
@@ -100,7 +100,9 @@ short guide in separate tabs. The essentials:
|
|
|
100
100
|
- **Navigate**: drag the mouse for a rubber-band zoom (a purely horizontal
|
|
101
101
|
drag zooms X only), `z`/`u` and `i`/`o` zoom about the cursor, `[` `]`
|
|
102
102
|
pan, `w` whole range, `a` autoscale, `h` home. The matplotlib toolbar
|
|
103
|
-
works too and stays in sync.
|
|
103
|
+
works too and stays in sync. As in PGPLOT the cursor works over the
|
|
104
|
+
whole window — press `x`/`y`/`e` just outside the axis to select a
|
|
105
|
+
range flush with the plot edge.
|
|
104
106
|
- **Analyse**: `b` bin, `s` smooth, `_` iterative continuum fit,
|
|
105
107
|
`m` equivalent width and line flux, `B` zap artefacts, `p` print to PDF.
|
|
106
108
|
- **Quit**: `q` — the final redshift is reported on the terminal.
|
|
@@ -13,7 +13,7 @@ from setuptools import setup
|
|
|
13
13
|
|
|
14
14
|
setup(
|
|
15
15
|
name="pyredshift",
|
|
16
|
-
version="1.
|
|
16
|
+
version="1.10",
|
|
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(),
|
|
@@ -57,6 +57,11 @@ redshift at that position (same as ESC + shortcut key)</td></tr>
|
|
|
57
57
|
<tr><td>d</td><td>display again</td></tr>
|
|
58
58
|
</table>
|
|
59
59
|
|
|
60
|
+
<p>The cursor works over the whole window, as in PGPLOT: keys and clicks
|
|
61
|
+
outside the axes box extrapolate their coordinates, so <code>x</code>,
|
|
62
|
+
<code>y</code> and <code>e</code> can be pressed just outside the axis to
|
|
63
|
+
select a range flush with (or beyond) the plot edge.</p>
|
|
64
|
+
|
|
60
65
|
<h2>Analysis</h2>
|
|
61
66
|
<table>
|
|
62
67
|
<tr><th>Key</th><th>Action</th></tr>
|
|
@@ -44,6 +44,11 @@ V1.8 - Right-click pops up the quick line list as a menu: pick a line
|
|
|
44
44
|
lines are now goldenrod on white, yellow on the retro background.
|
|
45
45
|
V1.9 - First PyPI release. --microns flag (keeps micron wavelengths so
|
|
46
46
|
micron-mode display is reachable from files); packaging metadata.
|
|
47
|
+
V1.10 - The cursor works over the whole window, as PGPLOT's did: keys and
|
|
48
|
+
clicks outside the axes box extrapolate their coordinates (so
|
|
49
|
+
'x'/'y'/'e' can be pressed just outside the axis, pdlredshift
|
|
50
|
+
style), the crosshair and the readout follow into the margins,
|
|
51
|
+
and rubber-band drags may extend past the plot edge.
|
|
47
52
|
"""
|
|
48
53
|
|
|
49
54
|
import ctypes
|
|
@@ -83,7 +88,7 @@ try:
|
|
|
83
88
|
except AttributeError:
|
|
84
89
|
pass
|
|
85
90
|
|
|
86
|
-
__version__ = "1.
|
|
91
|
+
__version__ = "1.10"
|
|
87
92
|
|
|
88
93
|
C_LIGHT = 2.99792458e8 # m/s
|
|
89
94
|
|
|
@@ -260,6 +265,19 @@ norm = 1.0
|
|
|
260
265
|
# ---------------------------------------------------------------------------
|
|
261
266
|
# Cursor and blocking input - the pgband() replacement
|
|
262
267
|
# ---------------------------------------------------------------------------
|
|
268
|
+
def surface_xy(ax_, ev):
|
|
269
|
+
"""Data coords for an event anywhere on the figure surface.
|
|
270
|
+
|
|
271
|
+
PGPLOT's cursor was not confined to the axes box - outside it (margins,
|
|
272
|
+
over widgets) extrapolate from the pixel position."""
|
|
273
|
+
if ev.inaxes is ax_:
|
|
274
|
+
return ev.xdata, ev.ydata
|
|
275
|
+
if ev.x is None or ev.y is None:
|
|
276
|
+
return None, None
|
|
277
|
+
xd, yd = ax_.transData.inverted().transform((ev.x, ev.y))
|
|
278
|
+
return float(xd), float(yd)
|
|
279
|
+
|
|
280
|
+
|
|
263
281
|
class StickyCursor(Cursor):
|
|
264
282
|
"""Cursor that survives full canvas repaints and toolbar pan/zoom.
|
|
265
283
|
|
|
@@ -268,19 +286,37 @@ class StickyCursor(Cursor):
|
|
|
268
286
|
after every repaint. Also reimplements onmove() without the base class's
|
|
269
287
|
widgetlock check, so the crosshair stays live while the toolbar pan/zoom
|
|
270
288
|
mode is switched on.
|
|
289
|
+
|
|
290
|
+
The crosshair spans the whole window like PGPLOT's, not just the axes
|
|
291
|
+
box, so the background snapshot and blit cover the full figure - and the
|
|
292
|
+
cursor re-draws the (animated) readout text as part of its pass, since a
|
|
293
|
+
full-figure restore would otherwise erase it.
|
|
271
294
|
"""
|
|
272
295
|
|
|
273
296
|
def __init__(self, ax_, **kwargs):
|
|
274
297
|
self._last_event = None
|
|
275
298
|
super().__init__(ax_, **kwargs)
|
|
299
|
+
self.linev.set_clip_on(False) # let the crosshair escape the box
|
|
300
|
+
self.lineh.set_clip_on(False)
|
|
276
301
|
self.connect_event("draw_event", self._redraw)
|
|
277
302
|
|
|
303
|
+
def clear(self, event):
|
|
304
|
+
# As Cursor.clear (mpl 3.9), but snapshot the whole figure: the
|
|
305
|
+
# crosshair now extends into the margins. Runs on draw_event while
|
|
306
|
+
# animated artists are excluded, so the snapshot is clean.
|
|
307
|
+
if self.ignore(event) or self.canvas.is_saving():
|
|
308
|
+
return
|
|
309
|
+
if self.useblit:
|
|
310
|
+
self.background = self.canvas.copy_from_bbox(self.canvas.figure.bbox)
|
|
311
|
+
|
|
278
312
|
def onmove(self, event):
|
|
279
313
|
# Copy of Cursor.onmove from matplotlib 3.9, minus the widgetlock
|
|
280
|
-
# check (version sensitive - revisit if matplotlib is upgraded)
|
|
314
|
+
# check (version sensitive - revisit if matplotlib is upgraded),
|
|
315
|
+
# with whole-window coords and full-figure blitting.
|
|
281
316
|
if self.ignore(event):
|
|
282
317
|
return
|
|
283
|
-
|
|
318
|
+
xdata, ydata = surface_xy(self.ax, event)
|
|
319
|
+
if xdata is None:
|
|
284
320
|
self._last_event = None # or _redraw() would resurrect it
|
|
285
321
|
self.linev.set_visible(False)
|
|
286
322
|
self.lineh.set_visible(False)
|
|
@@ -290,10 +326,16 @@ class StickyCursor(Cursor):
|
|
|
290
326
|
return
|
|
291
327
|
self._last_event = event
|
|
292
328
|
self.needclear = True
|
|
293
|
-
|
|
294
|
-
self.
|
|
329
|
+
# Span the full window: line extents are in axes-fraction coords
|
|
330
|
+
figbb = self.canvas.figure.bbox
|
|
331
|
+
axbb = self.ax.bbox
|
|
332
|
+
self.linev.set_data((xdata, xdata),
|
|
333
|
+
((figbb.y0 - axbb.y0) / axbb.height,
|
|
334
|
+
(figbb.y1 - axbb.y0) / axbb.height))
|
|
295
335
|
self.linev.set_visible(self.visible and self.vertOn)
|
|
296
|
-
self.lineh.
|
|
336
|
+
self.lineh.set_data(((figbb.x0 - axbb.x0) / axbb.width,
|
|
337
|
+
(figbb.x1 - axbb.x0) / axbb.width),
|
|
338
|
+
(ydata, ydata))
|
|
297
339
|
self.lineh.set_visible(self.visible and self.horizOn)
|
|
298
340
|
if not (self.visible and (self.vertOn or self.horizOn)):
|
|
299
341
|
return
|
|
@@ -303,13 +345,21 @@ class StickyCursor(Cursor):
|
|
|
303
345
|
self.canvas.restore_region(self.background)
|
|
304
346
|
self.ax.draw_artist(self.linev)
|
|
305
347
|
self.ax.draw_artist(self.lineh)
|
|
306
|
-
|
|
348
|
+
if readout_artist is not None:
|
|
349
|
+
set_readout_text(event) # restore wiped the corner -
|
|
350
|
+
fig.draw_artist(readout_artist) # redraw with fresh values
|
|
351
|
+
self.canvas.blit(figbb)
|
|
307
352
|
else:
|
|
308
353
|
self.canvas.draw_idle()
|
|
309
354
|
|
|
310
355
|
def _redraw(self, event):
|
|
311
|
-
if self._last_event is not None:
|
|
356
|
+
if self.active and self._last_event is not None:
|
|
312
357
|
self.onmove(self._last_event)
|
|
358
|
+
elif readout_lastev is not None:
|
|
359
|
+
# No crosshair to re-draw (fresh cursor after draw_plot, or
|
|
360
|
+
# deactivated while the line menu is up) - the readout must
|
|
361
|
+
# still survive the repaint
|
|
362
|
+
update_readout(readout_lastev)
|
|
313
363
|
|
|
314
364
|
|
|
315
365
|
def normkey(ch):
|
|
@@ -325,6 +375,11 @@ def pgband(allow_drag=False):
|
|
|
325
375
|
Mouse button gives ch='A', as PGPLOT did. Returns ch='q' if the window
|
|
326
376
|
is closed.
|
|
327
377
|
|
|
378
|
+
Like the PGPLOT cursor, key presses and left clicks work over the whole
|
|
379
|
+
window, not just inside the axes box - coordinates are extrapolated from
|
|
380
|
+
the pixel position (handy for 'x'/'y'/'e' just outside the axis).
|
|
381
|
+
Clicks on widgets (the ? button) are still ignored.
|
|
382
|
+
|
|
328
383
|
With allow_drag=True a left-button drag rubber-band zooms (like 'e') and
|
|
329
384
|
returns ch='drag' after updating the view state; a purely horizontal drag
|
|
330
385
|
zooms X only, a purely vertical one Y only. Short drags (<5 pixels)
|
|
@@ -343,31 +398,40 @@ def pgband(allow_drag=False):
|
|
|
343
398
|
toolbar = getattr(fig.canvas.manager, "toolbar", None)
|
|
344
399
|
return getattr(toolbar, "mode", "") if toolbar is not None else ""
|
|
345
400
|
|
|
401
|
+
def data_xy(ev):
|
|
402
|
+
# PGPLOT-style whole-surface cursor read (see surface_xy)
|
|
403
|
+
return surface_xy(ax, ev)
|
|
404
|
+
|
|
346
405
|
def on_key(ev):
|
|
347
|
-
|
|
406
|
+
xd, yd = data_xy(ev)
|
|
407
|
+
done(xd, yd, normkey(ev.key))
|
|
348
408
|
|
|
349
409
|
def on_press(ev):
|
|
350
|
-
if ev.inaxes is not ax:
|
|
351
|
-
return # clicks
|
|
352
|
-
if allow_drag and ev.button == 3:
|
|
410
|
+
if ev.inaxes is not ax and ev.inaxes is not None:
|
|
411
|
+
return # clicks on widgets (the ? button) aren't cursor reads
|
|
412
|
+
if allow_drag and ev.button == 3 and ev.inaxes is ax:
|
|
353
413
|
done(ev.xdata, ev.ydata, "menu") # right-click: quick line menu
|
|
354
414
|
return
|
|
355
|
-
|
|
415
|
+
xd, yd = data_xy(ev)
|
|
416
|
+
if allow_drag and ev.button == 1 and ev.inaxes is ax and not toolbar_mode():
|
|
356
417
|
drag["xpx"], drag["ypx"] = ev.x, ev.y # pixels, for threshold
|
|
357
|
-
drag["x0"], drag["y0"] =
|
|
358
|
-
drag["x1"], drag["y1"] =
|
|
418
|
+
drag["x0"], drag["y0"] = xd, yd
|
|
419
|
+
drag["x1"], drag["y1"] = xd, yd
|
|
359
420
|
drag["rect"] = ax.add_patch(Rectangle(
|
|
360
|
-
(
|
|
421
|
+
(xd, yd), 0, 0, fill=False,
|
|
361
422
|
edgecolor="red", lw=0.8, ls="--"))
|
|
362
423
|
else:
|
|
363
|
-
done(
|
|
424
|
+
done(xd, yd, "A")
|
|
364
425
|
|
|
365
426
|
def on_motion(ev):
|
|
366
|
-
if "rect" not in drag or ev.inaxes is not ax:
|
|
427
|
+
if "rect" not in drag or (ev.inaxes is not ax and ev.inaxes is not None):
|
|
367
428
|
return
|
|
368
|
-
|
|
429
|
+
xd, yd = data_xy(ev)
|
|
430
|
+
if xd is None:
|
|
431
|
+
return
|
|
432
|
+
drag["x1"], drag["y1"] = xd, yd
|
|
369
433
|
drag["rect"].set_bounds(drag["x0"], drag["y0"],
|
|
370
|
-
|
|
434
|
+
xd - drag["x0"], yd - drag["y0"])
|
|
371
435
|
fig.canvas.draw_idle()
|
|
372
436
|
|
|
373
437
|
def on_release(ev):
|
|
@@ -547,31 +611,40 @@ def make_readout():
|
|
|
547
611
|
|
|
548
612
|
def snapshot_readout(ev):
|
|
549
613
|
"""Cache the bottom-right corner after every full draw (the readout
|
|
550
|
-
artist is animated, so it is never part of the cached image)
|
|
551
|
-
re-
|
|
552
|
-
|
|
614
|
+
artist is animated, so it is never part of the cached image). Only a
|
|
615
|
+
snapshot: re-rendering here would bake the text into the buffer before
|
|
616
|
+
the cursor takes ITS (full-figure) snapshot; the cursor's _redraw
|
|
617
|
+
re-renders the readout after every repaint instead."""
|
|
553
618
|
global readout_bg
|
|
554
619
|
W, H = fig.bbox.width, fig.bbox.height
|
|
555
620
|
box = Bbox([[0.40 * W, 0.0], [W, 0.055 * H]])
|
|
556
621
|
readout_bg = (fig.canvas.copy_from_bbox(box), box)
|
|
557
|
-
if readout_lastev is not None:
|
|
558
|
-
update_readout(readout_lastev)
|
|
559
622
|
|
|
560
623
|
|
|
561
|
-
def
|
|
624
|
+
def set_readout_text(ev):
|
|
625
|
+
"""Recompute the readout for an event - separate from the blit so the
|
|
626
|
+
cursor can refresh the text mid-pass (a new redshift must update the
|
|
627
|
+
rest wavelength immediately, not on the next mouse move)."""
|
|
562
628
|
global readout_lastev
|
|
563
|
-
if readout_artist is None or
|
|
629
|
+
if readout_artist is None or f is None:
|
|
564
630
|
return
|
|
565
631
|
readout_lastev = ev
|
|
566
|
-
|
|
567
|
-
|
|
632
|
+
xd, yd = surface_xy(ax, ev)
|
|
633
|
+
if xd is not None: # whole window, like the crosshair (pix clamps at ends)
|
|
634
|
+
i = int(np.argmin(np.abs(w - xd)))
|
|
568
635
|
wfmt = "%.5f" if micron_mode else "%.2f"
|
|
569
|
-
rest = wfmt % (
|
|
636
|
+
rest = wfmt % (xd / (1 + zshift)) if found else "-"
|
|
570
637
|
text = ("pix %d y %.4g λ %s rest %s flux %.4g"
|
|
571
|
-
% (i,
|
|
638
|
+
% (i, yd, wfmt % xd, rest, f[i]))
|
|
572
639
|
else:
|
|
573
640
|
text = ""
|
|
574
641
|
readout_artist.set_text(text)
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
def update_readout(ev):
|
|
645
|
+
if readout_artist is None or readout_bg is None or f is None:
|
|
646
|
+
return
|
|
647
|
+
set_readout_text(ev)
|
|
575
648
|
bg, box = readout_bg
|
|
576
649
|
fig.canvas.restore_region(bg)
|
|
577
650
|
fig.draw_artist(readout_artist)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyredshift
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10
|
|
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
|
|
@@ -134,7 +134,9 @@ short guide in separate tabs. The essentials:
|
|
|
134
134
|
- **Navigate**: drag the mouse for a rubber-band zoom (a purely horizontal
|
|
135
135
|
drag zooms X only), `z`/`u` and `i`/`o` zoom about the cursor, `[` `]`
|
|
136
136
|
pan, `w` whole range, `a` autoscale, `h` home. The matplotlib toolbar
|
|
137
|
-
works too and stays in sync.
|
|
137
|
+
works too and stays in sync. As in PGPLOT the cursor works over the
|
|
138
|
+
whole window — press `x`/`y`/`e` just outside the axis to select a
|
|
139
|
+
range flush with the plot edge.
|
|
138
140
|
- **Analyse**: `b` bin, `s` smooth, `_` iterative continuum fit,
|
|
139
141
|
`m` equivalent width and line flux, `B` zap artefacts, `p` print to PDF.
|
|
140
142
|
- **Quit**: `q` — the final redshift is reported on the terminal.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|