From a97be91e2b595ef635c7093c355d445526beac92 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:24:02 +0000 Subject: [PATCH 01/17] #98 Update figures in README --- docs/_static/lst-axis.svg | 511 +++++++------- docs/_static/multiple-objects.svg | 1072 ++++++++++++++--------------- docs/_static/one-liner.svg | 343 +++++---- scripts/figures | 82 +-- 4 files changed, 960 insertions(+), 1048 deletions(-) diff --git a/docs/_static/lst-axis.svg b/docs/_static/lst-axis.svg index a65284a..52a311e 100644 --- a/docs/_static/lst-axis.svg +++ b/docs/_static/lst-axis.svg @@ -6,7 +6,7 @@ - 2025-06-21T07:45:17.102355 + 2025-06-26T11:23:16.014747 image/svg+xml @@ -42,16 +42,16 @@ z +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -235,52 +235,33 @@ z +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - - - - - - - - - - - - - - - - - - - + - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -455,18 +436,18 @@ L 448.885 39.8 - + - + - + - + - + - + - + - + - + - + - + - + @@ -587,7 +568,7 @@ L 752.12125 39.8 - + @@ -740,19 +721,19 @@ z +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + - + @@ -763,14 +744,14 @@ L -3.5 0 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -782,14 +763,14 @@ L 853.2 202.388444 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -801,14 +782,14 @@ L 853.2 182.064889 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -820,14 +801,14 @@ L 853.2 161.741333 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -860,14 +841,14 @@ z +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -879,14 +860,14 @@ L 853.2 121.094222 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -898,14 +879,14 @@ L 853.2 100.770667 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -929,14 +910,14 @@ z +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -948,14 +929,14 @@ L 853.2 60.123556 +" clip-path="url(#p69e18f5e35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -963,7 +944,7 @@ L 853.2 39.8 - + @@ -1152,64 +1133,64 @@ z - + - + @@ -1321,17 +1302,17 @@ z - - + - + - + @@ -1343,12 +1324,12 @@ L 0 -3.5 - + - + - + @@ -1360,12 +1341,12 @@ L 0 -3.5 - + - + - + @@ -1377,12 +1358,12 @@ L 0 -3.5 - + - + - + @@ -1394,12 +1375,12 @@ L 0 -3.5 - + - + - + @@ -1411,12 +1392,12 @@ L 0 -3.5 - + - + - + @@ -1428,12 +1409,12 @@ L 0 -3.5 - + - + - + @@ -1445,12 +1426,12 @@ L 0 -3.5 - + - + - + @@ -1459,7 +1440,7 @@ L 0 -3.5 - + @@ -1483,10 +1464,10 @@ z - + - + @@ -1496,10 +1477,10 @@ z - + - + @@ -1510,10 +1491,10 @@ z - + - + @@ -1524,10 +1505,10 @@ z - + - + @@ -1538,10 +1519,10 @@ z - + - + @@ -1552,10 +1533,10 @@ z - + - + @@ -1566,10 +1547,10 @@ z - + - + @@ -1580,10 +1561,10 @@ z - + - + @@ -1594,10 +1575,10 @@ z - + - + @@ -1608,10 +1589,10 @@ z - + - + @@ -1621,64 +1602,64 @@ z - + + diff --git a/docs/_static/multiple-objects.svg b/docs/_static/multiple-objects.svg index 59bfa06..1ec8ad0 100644 --- a/docs/_static/multiple-objects.svg +++ b/docs/_static/multiple-objects.svg @@ -6,7 +6,7 @@ - 2025-06-21T07:45:16.973716 + 2025-06-26T11:23:15.816349 image/svg+xml @@ -31,8 +31,8 @@ z @@ -42,16 +42,16 @@ z +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -194,80 +194,35 @@ z - + - - - - - - - - - - - - - - - - - - - - - - - + - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + @@ -442,18 +423,18 @@ L 440.5375 26.88 - + - + - + - + - + - + - + - + - + - + - + - + @@ -574,9 +555,9 @@ L 737.513125 26.88 - + - + +L 853.2 234.376 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + - + @@ -661,15 +642,15 @@ L -3.5 0 +L 853.2 211.320889 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -680,15 +661,15 @@ L 836.505 211.320889 +L 853.2 188.265778 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -699,15 +680,15 @@ L 836.505 188.265778 +L 853.2 165.210667 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -718,15 +699,15 @@ L 836.505 165.210667 +L 853.2 142.155556 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -758,15 +739,15 @@ z +L 853.2 119.100444 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -777,15 +758,15 @@ L 836.505 119.100444 +L 853.2 96.045333 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -796,15 +777,15 @@ L 836.505 96.045333 +L 853.2 72.990222 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -827,15 +808,15 @@ z +L 853.2 49.935111 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -846,15 +827,15 @@ L 836.505 49.935111 +L 853.2 26.88 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -862,7 +843,7 @@ L 836.505 26.88 - + @@ -1138,295 +1119,294 @@ z +L 45.277153 289 +M 351.688017 289 +L 400.81958 243.045999 +L 423.438601 222.131704 +L 446.057622 201.525183 +L 463.021888 186.366663 +L 479.986154 171.565193 +L 491.295664 161.959199 +L 502.605175 152.621831 +L 513.914685 143.619988 +L 525.224196 135.039685 +L 530.878951 130.941016 +L 536.533706 126.991369 +L 542.188462 123.209281 +L 547.843217 119.615448 +L 553.497972 116.232767 +L 559.152727 113.086265 +L 564.807483 110.202855 +L 570.462238 107.610869 +L 576.116993 105.339318 +L 581.771748 103.416842 +L 587.426503 101.870382 +L 593.081259 100.723637 +L 598.736014 99.995469 +L 604.390769 99.698469 +L 610.045524 99.83792 +L 615.70028 100.411334 +L 621.355035 101.408673 +L 627.00979 102.813197 +L 632.664545 104.602777 +L 638.319301 106.751465 +L 643.974056 109.231069 +L 649.628811 112.012577 +L 655.283566 115.067312 +L 660.938322 118.367783 +L 666.593077 121.888245 +L 672.247832 125.605014 +L 677.902587 129.496602 +L 683.557343 133.543702 +L 694.866853 142.03752 +L 706.176364 150.971019 +L 717.485874 160.254197 +L 728.795385 169.817084 +L 745.75965 184.569735 +L 762.723916 199.693698 +L 779.688182 215.090542 +L 802.307203 235.921304 +L 830.580979 262.270395 +L 853.2 283.47752 +L 853.2 283.47752 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +L 55.87951 278.520378 +L 67.189021 270.786117 +L 78.498531 262.700074 +L 89.808042 254.308982 +L 101.117552 245.653321 +L 112.427063 236.76804 +L 129.391329 223.074406 +L 146.355594 209.016122 +L 163.31986 194.662033 +L 185.938881 175.15927 +L 208.557902 155.339606 +L 236.831678 130.259934 +L 299.033986 74.88368 +L 310.343497 65.087706 +L 321.653007 55.669544 +L 327.307762 51.246591 +L 332.962517 47.186172 +L 338.617273 43.754094 +L 344.272028 41.404514 +L 349.926783 40.701986 +L 355.581538 41.879993 +L 361.236294 44.566334 +L 366.891049 48.197474 +L 372.545804 52.371801 +L 378.200559 56.862081 +L 389.51007 66.349025 +L 400.81958 76.1757 +L 423.438601 96.226379 +L 485.640909 151.649016 +L 508.25993 171.516844 +L 530.878951 191.085826 +L 547.843217 205.503778 +L 564.807483 219.640851 +L 581.771748 233.431585 +L 593.081259 242.393901 +L 604.390769 251.138264 +L 615.70028 259.631579 +L 627.00979 267.835497 +L 638.319301 275.705678 +L 649.628811 283.191101 +L 658.923448 289 +M 851.519288 289 +L 853.2 287.98383 +L 853.2 287.98383 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +L 55.87951 168.333896 +L 67.189021 159.253236 +L 78.498531 150.536209 +L 89.808042 142.266723 +L 95.462797 138.331562 +L 101.117552 134.549272 +L 106.772308 130.936659 +L 112.427063 127.512129 +L 118.081818 124.295637 +L 123.736573 121.308556 +L 129.391329 118.573408 +L 135.046084 116.113456 +L 140.700839 113.952108 +L 146.355594 112.112152 +L 152.01035 110.614838 +L 157.665105 109.478848 +L 163.31986 108.719265 +L 168.974615 108.346643 +L 174.629371 108.366302 +L 180.284126 108.777959 +L 185.938881 109.575747 +L 191.593636 110.748625 +L 197.248392 112.281103 +L 202.903147 114.154197 +L 208.557902 116.346457 +L 214.212657 118.834995 +L 219.867413 121.596383 +L 225.522168 124.607413 +L 231.176923 127.845659 +L 236.831678 131.289881 +L 242.486434 134.920273 +L 248.141189 138.718592 +L 253.795944 142.668187 +L 265.105455 150.96237 +L 276.414965 159.699441 +L 287.724476 168.796426 +L 299.033986 178.1871 +L 310.343497 187.818607 +L 327.307762 202.62708 +L 344.272028 217.773761 +L 366.891049 238.357495 +L 389.51007 259.257712 +L 421.333046 289 +M 733.765908 289 +L 762.723916 261.92241 +L 785.342937 240.990228 +L 807.961958 220.35957 +L 824.926224 205.164484 +L 841.89049 190.292107 +L 853.2 180.606687 +L 853.2 180.606687 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +L 84.153287 120.488721 +L 101.117552 104.844254 +L 112.427063 94.604253 +L 123.736573 84.622707 +L 135.046084 75.070447 +L 140.700839 70.546692 +L 146.355594 66.270598 +L 152.01035 62.33279 +L 157.665105 58.8593 +L 163.31986 56.017369 +L 168.974615 54.006788 +L 174.629371 53.020474 +L 180.284126 53.174119 +L 185.938881 54.448644 +L 191.593636 56.700477 +L 197.248392 59.728902 +L 202.903147 63.340463 +L 208.557902 67.378911 +L 214.212657 71.728462 +L 219.867413 76.306379 +L 231.176923 85.929859 +L 242.486434 95.953467 +L 259.450699 111.413705 +L 282.06972 132.437146 +L 327.307762 174.934863 +L 366.891049 211.978951 +L 389.51007 232.891436 +L 412.129091 253.488223 +L 429.093357 268.643491 +L 446.057622 283.457356 +L 452.537959 289 +M 712.931963 289 +L 723.140629 280.236875 +L 740.104895 265.339531 +L 757.069161 250.121317 +L 779.688182 229.463863 +L 807.961958 203.238393 +L 847.545245 166.112994 +L 853.2 160.793898 +L 853.2 160.793898 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #d62728; stroke-width: 1.5; stroke-linecap: square"/> +L 95.462797 127.828211 +L 112.427063 115.60733 +L 123.736573 107.731508 +L 135.046084 100.184602 +L 140.700839 96.575121 +L 146.355594 93.102404 +L 152.01035 89.791483 +L 157.665105 86.671484 +L 163.31986 83.775908 +L 168.974615 81.142601 +L 174.629371 78.813187 +L 180.284126 76.831692 +L 185.938881 75.242148 +L 191.593636 74.085154 +L 197.248392 73.393704 +L 202.903147 73.18907 +L 208.557902 73.477787 +L 214.212657 74.250667 +L 219.867413 75.484178 +L 225.522168 77.14372 +L 231.176923 79.187826 +L 236.831678 81.572247 +L 242.486434 84.253229 +L 248.141189 87.189721 +L 253.795944 90.344598 +L 259.450699 93.685115 +L 265.105455 97.182873 +L 276.414965 104.55618 +L 287.724476 112.30949 +L 299.033986 120.330041 +L 315.998252 132.686116 +L 344.272028 153.693946 +L 378.200559 178.888102 +L 395.164825 191.263608 +L 412.129091 203.381894 +L 429.093357 215.159316 +L 440.402867 222.777512 +L 451.712378 230.175558 +L 463.021888 237.322336 +L 474.331399 244.184214 +L 485.640909 250.724869 +L 496.95042 256.905227 +L 508.25993 262.683594 +L 519.569441 268.015999 +L 525.224196 270.500753 +L 530.878951 272.856831 +L 536.533706 275.078435 +L 542.188462 277.159803 +L 547.843217 279.095262 +L 553.497972 280.87928 +L 559.152727 282.506526 +L 564.807483 283.971934 +L 570.462238 285.270767 +L 576.116993 286.398677 +L 581.771748 287.351777 +L 587.426503 288.126691 +L 593.081259 288.720615 +L 596.927532 289 +M 620.024647 289 +L 621.355035 288.922269 +L 627.00979 288.407952 +L 632.664545 287.711615 +L 638.319301 286.835797 +L 643.974056 285.783631 +L 649.628811 284.558789 +L 655.283566 283.165424 +L 660.938322 281.608113 +L 666.593077 279.891787 +L 672.247832 278.021668 +L 677.902587 276.003209 +L 683.557343 273.842027 +L 689.212098 271.543852 +L 694.866853 269.114474 +L 706.176364 263.88528 +L 717.485874 258.200298 +L 728.795385 252.10392 +L 740.104895 245.638378 +L 751.414406 238.84333 +L 762.723916 231.755702 +L 774.033427 224.409699 +L 785.342937 216.836968 +L 802.307203 205.116391 +L 819.271469 193.04236 +L 836.235734 180.699203 +L 853.2 168.168341 +L 853.2 168.168341 +" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #9467bd; stroke-width: 1.5; stroke-linecap: square"/> - - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - - + - + - - + - + - - + - + @@ -1813,14 +1759,14 @@ L 787.678437 84.012812 - - + - + @@ -1832,8 +1778,8 @@ L 787.678437 98.690937 - - + + diff --git a/docs/_static/one-liner.svg b/docs/_static/one-liner.svg index c1edae3..2e5790f 100644 --- a/docs/_static/one-liner.svg +++ b/docs/_static/one-liner.svg @@ -6,7 +6,7 @@ - 2025-06-21T07:45:16.790376 + 2025-06-26T11:23:15.327910 image/svg+xml @@ -31,8 +31,8 @@ z @@ -41,12 +41,12 @@ z - - + @@ -94,7 +94,7 @@ z - + - - + @@ -209,43 +225,24 @@ z - - - - - - - - - - - - - - - - - - - - + - - + - + - + - + - + - - - - + @@ -340,12 +305,12 @@ z - + - + - + - + - + - + + + + @@ -406,12 +387,12 @@ z - + - + - + - + - + - + - + - + - + @@ -522,9 +503,9 @@ z - + - + - - + - + @@ -725,10 +706,10 @@ L -3.5 0 - + - + @@ -739,10 +720,10 @@ L -3.5 0 - + - + @@ -753,10 +734,10 @@ L -3.5 0 - + - + @@ -767,10 +748,10 @@ L -3.5 0 - + - + @@ -802,10 +783,10 @@ z - + - + @@ -816,10 +797,10 @@ z - + - + @@ -830,10 +811,10 @@ z - + - + @@ -856,10 +837,10 @@ z - + - + @@ -870,10 +851,10 @@ z - + - + @@ -883,65 +864,65 @@ z - + - - - + + diff --git a/scripts/figures b/scripts/figures index 8110c47..381ea31 100755 --- a/scripts/figures +++ b/scripts/figures @@ -7,59 +7,63 @@ import matplotlib.dates as mdates import matplotlib.pyplot as plt -# matplotlib global settings -plt.rcParams["figure.figsize"] = 12, 4 +def plot_one_liner() -> None: + """Plot an example of one-liner.""" + fig, ax = plt.subplots(figsize=(12, 4)) + azely.calc("Sun", "Tokyo").el.plot(ax=ax, ylim=(0, 90)) -# example of one-liner -fig, ax = plt.subplots() + fig.tight_layout() + fig.savefig("docs/_static/one-liner.svg") -df = azely.compute("Sun", "Tokyo").el.plot(ax=ax, ylim=(0, 90)) -fig.tight_layout() -fig.savefig("docs/_static/one-liner.svg") +def plot_multiple_objects() -> None: + """Plot an example of multiple objects.""" + fig, ax = plt.subplots(figsize=(12, 4)) + location = "ALMA AOS" + time = "2017 Apr 11th in UTC" -# example of blackhole candidates -fig, ax = plt.subplots() + for obj in ("Sun", "Sgr A*", "M87", "M104", "Cen A"): + df = azely.calc(obj, location, time) + df.el.plot(ax=ax, label=obj) -site = "ALMA AOS" -time = "Apr. 11th 2017" -view = "UTC" + ax.set_title(f"Location: {location}, Time: {time}") + ax.set_ylabel("Elevation (deg)") + ax.set_ylim(0, 90) + ax.grid(which="both") + ax.legend() -for obj in ("Sun", "Sgr A*", "M87", "M104", "Cen A"): - df = azely.compute(obj, site, time, view) - df.el.plot(ax=ax, label=obj) + fig.tight_layout() + fig.savefig("docs/_static/multiple-objects.svg") -ax.set_title(f"site: {site}, view: {view}, time: {time}") -ax.set_ylabel("Elevation (deg)") -ax.set_ylim(0, 90) -ax.grid(which="both") -ax.legend() -fig.tight_layout() -fig.savefig("docs/_static/multiple-objects.svg") +def plot_lst_axis() -> None: + """Plot an example of lst axis.""" + fig, ax = plt.subplots(figsize=(12, 4)) + twin = ax.twiny() + df = azely.calc("Sun", "Tokyo", "2020-01-01") + df.el.plot(ax=ax, label=df.object.name) + df.in_lst().el.plot(ax=twin, alpha=0) -# example of lst axis -fig, ax = plt.subplots(figsize=(12, 4)) -twin = ax.twiny() + ax.set_ylabel("Elevation (deg)") + ax.set_ylim(0, 90) + ax.grid(which="both") + ax.legend() -df = azely.compute("Sun", "Tokyo", "2020-01-01") -df.el.plot(ax=ax, label=df.object.name) -df.in_lst.el.plot(ax=twin, alpha=0) + formatter = mdates.DateFormatter("%H:%M") + twin.xaxis.set_major_formatter(formatter) + fig.autofmt_xdate(rotation=0) -ax.set_ylabel("Elevation (deg)") -ax.set_ylim(0, 90) -ax.grid(which="both") -ax.legend() + ax.margins(0) + twin.margins(0) -formatter = mdates.DateFormatter("%H:%M") -twin.xaxis.set_major_formatter(formatter) -fig.autofmt_xdate(rotation=0) + fig.tight_layout() + fig.savefig("docs/_static/lst-axis.svg") -ax.margins(0) -twin.margins(0) -fig.tight_layout() -fig.savefig("docs/_static/lst-axis.svg") +if __name__ == "__main__": + plot_one_liner() + plot_multiple_objects() + plot_lst_axis() From 3a1295c06b1d439273f68987eb6a2368f7486005 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:25:33 +0000 Subject: [PATCH 02/17] =?UTF-8?q?#98=20Update=20package=20version=20(0.7.0?= =?UTF-8?q?=20=E2=86=92=201.0.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CITATION.cff | 2 +- README.md | 8 ++++---- azely/__init__.py | 2 +- pyproject.toml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index d612074..ede92c7 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -27,5 +27,5 @@ keywords: - sidereal-time - visibility license: MIT -version: 0.7.0 +version: 1.0.0 date-released: '2022-11-03' diff --git a/README.md b/README.md index 435fc0f..add1dfa 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ In fact azely offers one-liner to compute and plot, for example, one-day elevati >>> azely.compute('Sun', 'Tokyo').el.plot(ylim=(0, 90)) ``` -![one-liner.svg](https://raw.githubusercontent.com/astropenguin/azely/v0.7.0/docs/_static/one-liner.svg) +![one-liner.svg](https://raw.githubusercontent.com/astropenguin/azely/v1.0.0/docs/_static/one-liner.svg) ## Features @@ -30,7 +30,7 @@ In fact azely offers one-liner to compute and plot, for example, one-day elevati ## Requirements - **Python:** 3.7, 3.8, 3.9, and 3.10 (tested by author) -- **Dependencies:** See [pyproject.toml](https://github.com/astropenguin/azely/blob/v0.7.0/pyproject.toml) +- **Dependencies:** See [pyproject.toml](https://github.com/astropenguin/azely/blob/v1.0.0/pyproject.toml) ## Installation @@ -127,7 +127,7 @@ ax.grid(which="both") ax.legend() ``` -![multiple-objects.svg](https://raw.githubusercontent.com/astropenguin/azely/v0.7.0/docs/_static/multiple-objects.svg) +![multiple-objects.svg](https://raw.githubusercontent.com/astropenguin/azely/v1.0.0/docs/_static/multiple-objects.svg) ## Advanced usage @@ -172,7 +172,7 @@ ax.margins(0) twin.margins(0) ``` -![lst-axis.svg](https://raw.githubusercontent.com/astropenguin/azely/v0.7.0/docs/_static/lst-axis.svg) +![lst-axis.svg](https://raw.githubusercontent.com/astropenguin/azely/v1.0.0/docs/_static/lst-axis.svg) ### User-defined information diff --git a/azely/__init__.py b/azely/__init__.py index 07b84ed..30bba9c 100644 --- a/azely/__init__.py +++ b/azely/__init__.py @@ -14,7 +14,7 @@ "time", "utils", ] -__version__ = "0.7.0" +__version__ = "1.0.0" # dependencies diff --git a/pyproject.toml b/pyproject.toml index 90d5e9a..519b5c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "azely" -version = "0.7.0" +version = "1.0.0" description = "Azimuth/elevation visualization for astronomy" readme = "README.md" keywords = [ From 03d993c4c09739d0e1510ea7d0a25a5487fa8905 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:26:28 +0000 Subject: [PATCH 03/17] #98 Update project description --- CITATION.cff | 2 +- README.md | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index ede92c7..8959556 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -17,7 +17,7 @@ identifiers: value: 10.5281/zenodo.3680060 repository-code: 'https://github.com/astropenguin/azely' url: 'https://astropenguin.github.io/azely' -abstract: Azimuth/elevation visualization for astronomy +abstract: Azimuth/elevation calculator for astronomy keywords: - python - astronomy diff --git a/README.md b/README.md index add1dfa..57f6a0a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.3680060-cornflowerblue?style=flat-square)](https://doi.org/10.5281/zenodo.3680060) [![Tests](https://img.shields.io/github/workflow/status/astropenguin/azely/Tests?label=Tests&style=flat-square)](https://github.com/astropenguin/azely/actions) -Azimuth/elevation visualization for astronomy +Azimuth/elevation calculator for astronomy ## TL;DR diff --git a/pyproject.toml b/pyproject.toml index 519b5c5..e8fcba5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "azely" version = "1.0.0" -description = "Azimuth/elevation visualization for astronomy" +description = "Azimuth/elevation calculator for astronomy" readme = "README.md" keywords = [ "astronomy", From cb0bec8c5e4551511fdefcac5081c8c1edd539d4 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:35:49 +0000 Subject: [PATCH 04/17] #98 Update test budge in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57f6a0a..e3f4320 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Python](https://img.shields.io/pypi/pyversions/azely?label=Python&color=cornflowerblue&style=flat-square)](https://pypi.org/project/azely/) [![Downloads](https://img.shields.io/pypi/dm/azely?label=Downloads&color=cornflowerblue&style=flat-square)](https://pepy.tech/project/azely) [![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.3680060-cornflowerblue?style=flat-square)](https://doi.org/10.5281/zenodo.3680060) -[![Tests](https://img.shields.io/github/workflow/status/astropenguin/azely/Tests?label=Tests&style=flat-square)](https://github.com/astropenguin/azely/actions) +[![Tests](https://img.shields.io/github/actions/workflow/status/astropenguin/azely/tests.yaml?label=Tests&style=flat-square)](https://github.com/astropenguin/azely/actions) Azimuth/elevation calculator for astronomy From e903ea73d73c6d5c54966f005b9c3d3de20a1d7b Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:41:04 +0000 Subject: [PATCH 05/17] #98 Update workflows --- .github/workflows/docs.yaml | 10 ++++++---- .github/workflows/tests.yaml | 2 -- CITATION.cff | 2 +- pyproject.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 2c32c4d..c6110cd 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -7,19 +7,21 @@ on: jobs: job: - name: GitHub Pages + name: Docs runs-on: ubuntu-latest container: ghcr.io/astral-sh/uv:python3.12-bookworm env: UV_PROJECT_ENVIRONMENT: /usr/local + permissions: + contents: write steps: - uses: actions/checkout@v4 - with: - submodules: true + - run: echo "tag=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT + id: tag - run: uv sync --frozen - run: docs/build - uses: peaceiris/actions-gh-pages@v4 with: - force_orphan: true + destination_dir: ${{ steps.tag.outputs.tag }} github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./docs/_build diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4d91c2a..3ba04f1 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -26,8 +26,6 @@ jobs: - python3.13-bookworm steps: - uses: actions/checkout@v4 - with: - submodules: true - run: uv sync --frozen - run: black --check ${PYTHON_DIRS} - run: pyright ${PYTHON_DIRS} diff --git a/CITATION.cff b/CITATION.cff index 8959556..17dfeb7 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -16,7 +16,7 @@ identifiers: - type: doi value: 10.5281/zenodo.3680060 repository-code: 'https://github.com/astropenguin/azely' -url: 'https://astropenguin.github.io/azely' +url: 'https://astropenguin.github.io/azely/1.0.0' abstract: Azimuth/elevation calculator for astronomy keywords: - python diff --git a/pyproject.toml b/pyproject.toml index e8fcba5..d16c21e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ email = "taniguchi.akio@gmail.com" file = "LICENSE" [project.urls] -homepage = "https://astropenguin.github.io/azely" +homepage = "https://astropenguin.github.io/azely/1.0.0" repository = "https://github.com/astropenguin/azely" [build-system] From 38ed9f2c172054407a63829ff9abd52ba5f87358 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:44:21 +0000 Subject: [PATCH 06/17] #98 Remove unnecessary file (tests/__init__.py) --- tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 From 3f727221d78ebb54fa189b03e2858c46f16dae42 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:44:29 +0000 Subject: [PATCH 07/17] #98 Update .gitignore --- .gitignore | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 5d99a78..eefac9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -### Azely ### -.azely/ +# Created by https://www.toptal.com/developers/gitignore/api/python +# Edit at https://www.toptal.com/developers/gitignore?templates=python ### Python ### # Byte-compiled / optimized / DLL files @@ -74,7 +74,7 @@ instance/ # Sphinx documentation docs/readme.rst -docs/_apidoc +docs/_apidoc/ docs/_build/ # PyBuilder @@ -174,3 +174,5 @@ poetry.toml # LSP config files pyrightconfig.json + +# End of https://www.toptal.com/developers/gitignore/api/python From dadb26149c8951e995454b1fdfeaca4c8de8436c Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sat, 5 Jul 2025 17:08:47 +0000 Subject: [PATCH 08/17] #98 Add method for calculating separation angle --- azely/api.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/azely/api.py b/azely/api.py index ed583d3..34d18d2 100644 --- a/azely/api.py +++ b/azely/api.py @@ -83,6 +83,18 @@ def in_utc(self) -> Self: """Convert its index to UTC.""" return self.set_index(self.index.tz_convert("UTC").rename("UTC")) + def separation(self, other: Self, /) -> pd.Series: + """Calculate the separation angle with other object in degrees.""" + joined = self.join(other, how="outer", lsuffix="_l", rsuffix="_r") + left = SkyCoord(joined.az_l, joined.el_l, unit="deg", frame="altaz") + right = SkyCoord(joined.az_r, joined.el_r, unit="deg", frame="altaz") + + return pd.Series( + left.separation(right).value, + index=joined.index.tz_convert(self.index.tz), + name="separation", + ) + def calc( object: Object | ObjectDict | str, From 897b51689a3d40b27cad58fe08f44e1483a31ae3 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sat, 5 Jul 2025 17:12:13 +0000 Subject: [PATCH 09/17] #98 Update docstrings --- azely/api.py | 42 ++++++++++++++++++++++++++++-------------- azely/consts.py | 4 ++-- azely/location.py | 2 +- azely/object.py | 2 +- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/azely/api.py b/azely/api.py index 34d18d2..b05ac15 100644 --- a/azely/api.py +++ b/azely/api.py @@ -8,6 +8,7 @@ # dependent packages import pandas as pd +from astropy.coordinates import SkyCoord from astropy.time import Time as ObsTime from typing_extensions import NotRequired, Self, TypedDict from .consts import AZELY_CACHE @@ -47,23 +48,31 @@ class SourceDict(TypedDict): class AzEl(pd.DataFrame): - """Azely's custom DataFrame.""" + """Calculated azimuth and elevation of the object in degrees.""" - alt: pd.Series az: pd.Series + """Azimuth of the object in degrees.""" + el: pd.Series + """Elevation of the object in degrees.""" + index: pd.DatetimeIndex + """Timezone-aware time index (timezone-naive for local sidereal time).""" + location: Location + """Location information used for the azimuth/elevation calculation.""" + object: Object + """Object information used for the azimuth/elevation calculation.""" + time: Time - _metadata: ClassVar = ["location", "object", "time"] + """Time information used for the azimuth/elevation calculation.""" - @property - def _constructor(self) -> type[Self]: - return type(self) + _metadata: ClassVar = ["location", "object", "time"] + """Ensure the location/object/time information as normal properties.""" def in_lst(self) -> Self: - """Convert its index to LST.""" + """Convert its time index to the local sidereal time (LST).""" lst_0days = pd.to_timedelta( ObsTime(self.index.tz_convert(None), location=self.location.earthlocation) .sidereal_time("mean") @@ -80,7 +89,7 @@ def in_lst(self) -> Self: return self.set_index((origin + lst_ndays).rename("LST")) def in_utc(self) -> Self: - """Convert its index to UTC.""" + """Convert its time index to the coordinated universal time (UTC).""" return self.set_index(self.index.tz_convert("UTC").rename("UTC")) def separation(self, other: Self, /) -> pd.Series: @@ -95,6 +104,11 @@ def separation(self, other: Self, /) -> pd.Series: name="separation", ) + @property + def _constructor(self) -> type[Self]: + """Ensure an AzEl DataFrame as the result of DataFrame manipulation.""" + return type(self) + def calc( object: Object | ObjectDict | str, @@ -109,7 +123,7 @@ def calc( # options for cache append: AppendDict | bool = True, overwrite: OverwriteDict | bool = False, - source: SourceDict | StrPath | None = AZELY_CACHE, + source: SourceDict | (StrPath | None) = AZELY_CACHE, ) -> AzEl: """Calculate azimuth/elevation of given object in given location at give time. @@ -117,10 +131,10 @@ def calc( object: Object information, or query dictionary or string for it. location: Location information, or query dictionary or string for it. time: Time information, or query dictionary or string for it. - google_api: Optional Google API key. - ipinfo_api: Optional IPinfo API key. - sep: Separator string for splitting the query. - timeout: Timeout length in units of seconds. + google_api: Optional Google API key for the location information. + ipinfo_api: Optional IPinfo API key for the location information. + sep: Separator string for splitting the location/object/time queries. + timeout: Timeout length in seconds for the location/object information. append: Whether to append the location/object/time information to the source TOML file if it does not exist. An option dictionary for each information is also accepted. @@ -131,7 +145,7 @@ def calc( An option dictionary for each information is also accepted. Returns: - DataFrame of the calculated azimuth/elevation. + Calculated azimuth and elevation of the object in degrees. """ if not isinstance(append, dict): diff --git a/azely/consts.py b/azely/consts.py index 533d4ab..114b39a 100644 --- a/azely/consts.py +++ b/azely/consts.py @@ -8,10 +8,10 @@ # constants AZELY_CACHE: Path -"""Azely's default cache TOML file.""" +"""Azely's default source TOML file.""" AZELY_DIR: Path -"""Azely's directory for the cache TOML file.""" +"""Azely's directory for the default source TOML file.""" if (env := getenv("AZELY_DIR")) is not None: diff --git a/azely/location.py b/azely/location.py index 9aee4f9..d6472e4 100644 --- a/azely/location.py +++ b/azely/location.py @@ -101,7 +101,7 @@ def get_location( google_api: Optional Google API key. ipinfo_api: Optional IPinfo API key. sep: Separator string for splitting the query. - timeout: Timeout length in units of seconds. + timeout: Timeout length in seconds. append: Whether to append the location information to the source TOML file if it does not exist. overwrite: Whether to overwrite the location information diff --git a/azely/object.py b/azely/object.py index a757a19..d8a14bf 100644 --- a/azely/object.py +++ b/azely/object.py @@ -92,7 +92,7 @@ def get_object( Args: query: Query string for the object information. sep: Separator string for splitting the query. - timeout: Timeout length in units of seconds. + timeout: Timeout length in seconds. append: Whether to append the object information to the source TOML file if it does not exist. overwrite: Whether to overwrite the object information From 4d9b49a07421c15c977ea3bcb9e0ccd0624ad9aa Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sat, 5 Jul 2025 17:25:01 +0000 Subject: [PATCH 10/17] #98 Refactor api module --- azely/api.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/azely/api.py b/azely/api.py index b05ac15..189253c 100644 --- a/azely/api.py +++ b/azely/api.py @@ -74,14 +74,20 @@ class AzEl(pd.DataFrame): def in_lst(self) -> Self: """Convert its time index to the local sidereal time (LST).""" lst_0days = pd.to_timedelta( - ObsTime(self.index.tz_convert(None), location=self.location.earthlocation) + ObsTime( + self.index.tz_convert(None), + location=self.location.earthlocation, + ) .sidereal_time("mean") .value, - "hr", + unit="hr", ) lst_ndays = lst_0days + ( lst_0days[0] - + pd.TimedeltaIndex(self.index - self.index[0], freq=None) # type: ignore + + pd.TimedeltaIndex( + self.index - self.index[0], + freq=None, # type: ignore + ) * SOLAR_TO_SIDEREAL ).floor("D") @@ -195,17 +201,18 @@ def calc( ) time = replace(time, timezone=str(location.timezone)) - obstime = ObsTime( - time.index.tz_convert(None), - location=location.earthlocation, - ) - skycoord = object.skycoord(obstime).altaz + altaz = object.skycoord( + ObsTime( + time.index.tz_convert(None), + location=location.earthlocation, + ) + ).altaz azel = AzEl( index=time.index, data={ - "az": skycoord.az, # type: ignore - "el": skycoord.alt, # type: ignore + "az": altaz.az, # type: ignore + "el": altaz.alt, # type: ignore }, ) azel.location = location From fb0b2eb9b5e63445f372e03a4d411e4cedd5d44f Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sun, 6 Jul 2025 10:10:32 +0000 Subject: [PATCH 11/17] #98 Update README --- README.md | 290 ++++++++++++++++++++++++++---------------------------- 1 file changed, 137 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index e3f4320..61c5ef7 100644 --- a/README.md +++ b/README.md @@ -6,227 +6,211 @@ [![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.3680060-cornflowerblue?style=flat-square)](https://doi.org/10.5281/zenodo.3680060) [![Tests](https://img.shields.io/github/actions/workflow/status/astropenguin/azely/tests.yaml?label=Tests&style=flat-square)](https://github.com/astropenguin/azely/actions) -Azimuth/elevation calculator for astronomy +Azimuth/elevation calculator for astronomical objects -## TL;DR +## Overview -Azely (pronounced as "as-elie") is a Python package for computation and plotting of horizontal coordinates (azimuth and elevation; az/el, hereafter) of astronomical objects at given location and time. -While computation and plotting are realized by [Astropy] and [Matplotlib], what azely provides is high-level API to use them easily. -In fact azely offers one-liner to compute and plot, for example, one-day elevation of the Sun in Tokyo: +**Azely** (pronounced "as-elie") is a Python package for calculation and plotting of horizontal coordinates (azimuth and elevation) of astronomical objects at given location and time. +While the core calculation and plotting are handled by [Astropy](https://astropy.org) and [Matplotlib](https://matplotlib.org), Azely provides a simple API for easier and more intuitive use. +For example, calculating and plotting the elevation of the Sun in Tokyo for today can be done in a single line: ```python ->>> azely.compute('Sun', 'Tokyo').el.plot(ylim=(0, 90)) +import azely + +azely.calc('Sun', 'Tokyo').el.plot(ylim=(0, 90)) ``` -![one-liner.svg](https://raw.githubusercontent.com/astropenguin/azely/v1.0.0/docs/_static/one-liner.svg) +![one-liner.svg](https://raw.githubusercontent.com/astropenguin/azely/1.0.0/docs/_static/one-liner.svg) ## Features -- **High-level API:** azely provides a simple yet powerful `compute()` function. Users can complete most of operation with it (e.g., information acquisition and computation). -- **Handy output:** azely's output (from `compute()`) is [pandas] DataFrame, a de facto standard data structure of Python. Users can convert it to other formats like CSV and plot it by [Matplotlib] using builtin methods. -- **Web information acquisition:** azely can automatically acquire object and location information (i.e., longitude and latitude) from online services (e.g., catalogues or maps). Obtained information is cached in a local [TOML] file for an offline use. -- **User-defined information:** azely also offers to use user-defined object and location information written in a [TOML] file. - -## Requirements - -- **Python:** 3.7, 3.8, 3.9, and 3.10 (tested by author) -- **Dependencies:** See [pyproject.toml](https://github.com/astropenguin/azely/blob/v1.0.0/pyproject.toml) +- **Simple API:** Just pass query strings for the object, location, and time information to the `azely.calc()` function. The output is a [pandas](https://pandas.pydata.org) DataFrame of the calculated azimuth and elevation, which makes it easy to convert to other formats like CSV or plot with Matplotlib. +- **Information Retrieval and Cache:** Azely automatically fetches object coordinates and location details from online services. The fetched information is cached in a local TOML file for offline use. ## Installation ```shell -$ pip install azely +pip install azely ``` -## Basic usage - -This section describes basic az/el computation using `compute()` function. - -### Compute function +## Basic Usage -Azely's `compute()` function receives the following parameters and returns [pandas] DataFrame (`df`): +The easiest way to use Azely is to pass query strings for the object, location, and time information to the `azely.calc()` function to get the azimuth/elevation DataFrame: ```python ->>> import azely ->>> df = azely.compute(object, site, time, view, **options) -``` - -This means that `azely` will `compute` az/el of `object` observed from `site` at (on) `time` in `view`. -For example, the following code will compute az/el of Sun observed from ALMA AOS on Jan. 1st 2020 in Tokyo. +import azely -```python ->>> df = azely.compute('Sun', 'ALMA AOS', '2020-01-01', 'Tokyo') +df = azely.calc(object, location, time) ``` -Acceptable formats of each parameter and examples are as follows. - -| Parameter | Acceptable format | Description | Examples | -| --- | --- | --- | --- | -| `object` | `` | name of object to be searched | `'Sun'`, `'NGC1068'` | -| | `:` | user-defined object to be loaded (see below) | `'user.toml:M42'`, `'user:M42'` (also valid) | -| `site` | `'here'` (default) | current location (guess by IP address) | | -| | `` | name of location to be searched | `'ALMA AOS'`, `'Tokyo'` | -| | `:` | user-defined location to be loaded (see below) | `'user.toml:ASTE'`, `'user:ASTE'` (also valid) | -| `time` | `'today'` (default) | get one-day time range of today | | -| | `'now'` | get current time | | -| | ` - - + - - + - + - + - + - + - + - + - - + - + - + - + - + - + - + - + - + - + - + @@ -436,18 +436,18 @@ L 451.712378 39.8 - + - + - + - + - + - + - + - + - + @@ -570,7 +570,7 @@ L 757.069161 39.8 - + - + - - + - + - + - + - - - + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + - + - + - + - + - - - - - - - - - - - - - - - - - - + - + - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - + - + - - + - + - + @@ -1322,14 +1263,14 @@ L 0 -3.5 - + - + - + - + @@ -1339,14 +1280,14 @@ L 0 -3.5 - + - + - + - + @@ -1356,14 +1297,14 @@ L 0 -3.5 - + - + - + - + @@ -1373,14 +1314,14 @@ L 0 -3.5 - + - + - + - + @@ -1390,14 +1331,14 @@ L 0 -3.5 - + - + - + - + @@ -1407,14 +1348,14 @@ L 0 -3.5 - + - + - + - + @@ -1424,14 +1365,14 @@ L 0 -3.5 - + - + - + - + @@ -1440,20 +1381,9 @@ L 0 -3.5 - + - - - - + @@ -1461,231 +1391,157 @@ z - - + + - + - + - + - - - - - - - - - - - - - - - - + + - + - + - + - - - - - - - - - - - - - - - - + + - + - + - + - - - - - - - - - - - - - - - - + + - + - + - + - - - - - - - - - - - - - - - - + + - + - + - + - - - - - - - - - - - - - - - - + + - - - - - - + + diff --git a/docs/_static/multiple-objects.svg b/docs/_static/multiple-objects.svg index 1ec8ad0..764e584 100644 --- a/docs/_static/multiple-objects.svg +++ b/docs/_static/multiple-objects.svg @@ -6,7 +6,7 @@ - 2025-06-26T11:23:15.816349 + 2025-07-06T10:14:02.890938 image/svg+xml @@ -42,16 +42,16 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -196,11 +196,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -208,16 +208,16 @@ L 853.2 26.88 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -269,11 +269,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -323,11 +323,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -377,11 +377,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -425,11 +425,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -474,11 +474,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -537,11 +537,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -620,16 +620,16 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -643,11 +643,11 @@ L -3.5 0 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -662,11 +662,11 @@ L 853.2 211.320889 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -681,11 +681,11 @@ L 853.2 188.265778 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -700,11 +700,11 @@ L 853.2 165.210667 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -740,11 +740,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -759,11 +759,11 @@ L 853.2 119.100444 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -778,11 +778,11 @@ L 853.2 96.045333 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -809,11 +809,11 @@ z +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -828,11 +828,11 @@ L 853.2 49.935111 +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1169,7 +1169,7 @@ L 802.307203 235.921304 L 830.580979 262.270395 L 853.2 283.47752 L 853.2 283.47752 -" clip-path="url(#pc0d51471d3)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #2ca02c; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #d62728; stroke-width: 1.5; stroke-linecap: square"/> +" clip-path="url(#peb87d0cea0)" style="fill: none; stroke: #9467bd; stroke-width: 1.5; stroke-linecap: square"/> - - + + - - - @@ -1607,34 +1549,6 @@ z - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1778,7 +1692,7 @@ L 804.373438 98.690937 - + diff --git a/docs/_static/one-liner.svg b/docs/_static/one-liner.svg index 2e5790f..63e4252 100644 --- a/docs/_static/one-liner.svg +++ b/docs/_static/one-liner.svg @@ -6,7 +6,7 @@ - 2025-06-26T11:23:15.327910 + 2025-07-06T10:14:02.248445 image/svg+xml @@ -41,12 +41,12 @@ z - - + @@ -94,33 +94,9 @@ z - - + + - - - + - + - + - - + @@ -288,7 +252,7 @@ z - + @@ -305,7 +269,7 @@ z - + @@ -354,7 +318,7 @@ z - + @@ -374,6 +338,30 @@ L 3481 0 L 794 0 L 794 531 z +" transform="scale(0.015625)"/> + @@ -387,7 +375,7 @@ z - + @@ -431,7 +419,7 @@ z - + @@ -489,7 +477,7 @@ z - + @@ -688,12 +676,12 @@ z - - + @@ -706,7 +694,7 @@ L -3.5 0 - + @@ -720,7 +708,7 @@ L -3.5 0 - + @@ -734,7 +722,7 @@ L -3.5 0 - + @@ -748,7 +736,7 @@ L -3.5 0 - + @@ -783,7 +771,7 @@ z - + @@ -797,7 +785,7 @@ z - + @@ -811,7 +799,7 @@ z - + @@ -837,7 +825,7 @@ z - + @@ -851,7 +839,7 @@ z - + @@ -864,65 +852,64 @@ z - + + diff --git a/docs/build b/docs/build index 250de88..36e70b3 100755 --- a/docs/build +++ b/docs/build @@ -2,3 +2,4 @@ sphinx-apidoc -efT -o docs/_apidoc azely sphinx-build -a docs docs/_build +python docs/plot.py diff --git a/scripts/figures b/docs/plot.py old mode 100755 new mode 100644 similarity index 58% rename from scripts/figures rename to docs/plot.py index 381ea31..c792f49 --- a/scripts/figures +++ b/docs/plot.py @@ -1,10 +1,7 @@ -#!/usr/bin/env python - - # dependencies import azely -import matplotlib.dates as mdates import matplotlib.pyplot as plt +from matplotlib.dates import DateFormatter def plot_one_liner() -> None: @@ -21,14 +18,11 @@ def plot_multiple_objects() -> None: """Plot an example of multiple objects.""" fig, ax = plt.subplots(figsize=(12, 4)) - location = "ALMA AOS" - time = "2017 Apr 11th in UTC" - for obj in ("Sun", "Sgr A*", "M87", "M104", "Cen A"): - df = azely.calc(obj, location, time) - df.el.plot(ax=ax, label=obj) + df = azely.calc(obj, "ALMA AOS", "2017 Apr 11th in UTC") + df.el.plot(ax=ax, label=df.object.name) - ax.set_title(f"Location: {location}, Time: {time}") + ax.set_title(f"Location: {df.location.name}") ax.set_ylabel("Elevation (deg)") ax.set_ylim(0, 90) ax.grid(which="both") @@ -40,26 +34,25 @@ def plot_multiple_objects() -> None: def plot_lst_axis() -> None: """Plot an example of lst axis.""" - fig, ax = plt.subplots(figsize=(12, 4)) - twin = ax.twiny() + fig, ax_jst = plt.subplots(figsize=(12, 4)) + ax_lst = ax_jst.twiny() df = azely.calc("Sun", "Tokyo", "2020-01-01") - df.el.plot(ax=ax, label=df.object.name) - df.in_lst().el.plot(ax=twin, alpha=0) - - ax.set_ylabel("Elevation (deg)") - ax.set_ylim(0, 90) - ax.grid(which="both") - ax.legend() - - formatter = mdates.DateFormatter("%H:%M") - twin.xaxis.set_major_formatter(formatter) - fig.autofmt_xdate(rotation=0) - - ax.margins(0) - twin.margins(0) + df.el.plot(ax=ax_jst, label=df.object.name) + ax_jst.set_title(f"Location: {df.location.name}") + ax_jst.set_ylabel("Elevation (deg)") + ax_jst.set_ylim(0, 90) + ax_jst.grid(which="both") + ax_jst.legend() + + # plot invisible elevation for the LST axis + df.in_lst().el.plot(ax=ax_lst, alpha=0) + ax_lst.xaxis.set_major_formatter(DateFormatter("%H:%M")) + ax_jst.margins(0) + ax_lst.margins(0) fig.tight_layout() + fig.autofmt_xdate(rotation=0) fig.savefig("docs/_static/lst-axis.svg") From 804d7b96a32e40610c8448e485b0469324c1ee52 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sun, 6 Jul 2025 11:33:43 +0000 Subject: [PATCH 14/17] #98 Fix missing units in get_location --- azely/location.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azely/location.py b/azely/location.py index d6472e4..2a73c9c 100644 --- a/azely/location.py +++ b/azely/location.py @@ -116,10 +116,11 @@ def get_location( handler = getHandler(ipinfo_api) response = handler.getDetails(timeout=timeout) + # requiring double-str may be an astropy's issue return Location( name=response.city, - longitude=response.longitude, - latitude=response.latitude, + longitude=str(str(Longitude(response.longitude, "deg"))), + latitude=str(str(Latitude(response.latitude, "deg"))), altitude=DEFAULT_ALTITUDE, ) From b36af6cdedae513733b0079b14bd694072d3c211 Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sun, 6 Jul 2025 11:54:51 +0000 Subject: [PATCH 15/17] #98 Do not cache full object/location/time information --- README.md | 10 +++++----- azely/api.py | 32 ++++++++++++++++---------------- azely/utils.py | 6 ++++-- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e290181..ff8821d 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,13 @@ df = azely.calc(object, location, time) Parameter | Format & Description | Examples --- | --- | --- -`location`| **`''`** (default): Current location inferred from your IP address. | `''` +`location`| **`''`**: Current location inferred from your IP address (default; not cached). | `''` `location`| **`''`**: Name of the location to be searched online. | `'ALMA AOS'`, `'Tokyo'` -`location`| **`';;[;altitude]'`**: Full location information. | `'ASTE; -67.70d; -22.97d; 4860m'` +`location`| **`';;[;altitude]'`**: Full location information (not cached). A dictionary is also accepted. | `'ASTE; -67.70d; -22.97d; 4860m'`, `{'name': 'ASTE', 'longitude': '-67.70d', 'latitude': '-22.97d', 'altitude': '4860m'}` `object` | **`''`**: Name of the object to be searched online. | `'Sun'`, `'3C 273'` -`object` | **`';;[;]'`**: Full object information. Frame defaults to `'icrs'`. | `'M42; 5h35m; -5d23m'` -`time` | **`''`** (default): 00:00 today to 00:00 tomorrow at a 10-minute step. Timezone follows given location. | `''` -`time` | **`'[][;][;][;]'`**: Full time information. Omitted parts fall back to defaults (`'00:00 today'`, `'00:00 tomorrow'`, `'10min'`, `''`). Timezone follows given location unless not specified. | `'2025-01-01'`, `'09:00 JST today; in 2 days; 1h'`. +`object` | **`';;[;]'`**: Full object information (not cached). A dictionary is also accepted. Frame defaults to `'icrs'`. | `'M42; 5h35m; -5d23m'`, `{'name': 'M42', 'longitude': '5h35m', 'latitude': '-5d23m'}` +`time` | **`''`**: 00:00 today to 00:00 tomorrow at a 10-minute step (default; not cached). Timezone follows given location. | `''` +`time` | **`'[][;][;][;]'`**: Full time information (not cached). A dictionary is also accepted. Omitted parts fall back to defaults (`'00:00 today'`, `'00:00 tomorrow'`, `'10min'`, `''`). Timezone follows given location unless not specified. | `'2025-01-01'`, `'09:00 JST today; in 2 days; 1h'`, `{'start': '09:00 JST today', 'stop': 'in 2 days', 'step': '1h'}` ### DataFrame Example diff --git a/azely/api.py b/azely/api.py index 189253c..9e70382 100644 --- a/azely/api.py +++ b/azely/api.py @@ -164,9 +164,9 @@ def calc( source = {"location": source, "object": source, "time": source} if isinstance(location, dict): - location = Location(**location) + location_ = Location(**location) elif isinstance(location, str): - location = get_location( + location_ = get_location( location, google_api=google_api, ipinfo_api=ipinfo_api, @@ -178,9 +178,9 @@ def calc( ) if isinstance(object, dict): - object = Object(**object) + object_ = Object(**object) elif isinstance(object, str): - object = get_object( + object_ = get_object( object, sep=sep, timeout=timeout, @@ -190,32 +190,32 @@ def calc( ) if isinstance(time, dict): - time = Time(**time) + time_ = Time(**time) elif isinstance(time, str): - time = get_time( + time_ = get_time( time, sep=sep, append=append.get("time", True), overwrite=overwrite.get("time", False), source=source.get("time", AZELY_CACHE), ) + time_ = replace(time_, timezone=str(location_.timezone)) - time = replace(time, timezone=str(location.timezone)) - altaz = object.skycoord( + skycoord = object_.skycoord( ObsTime( - time.index.tz_convert(None), - location=location.earthlocation, + time_.index.tz_convert(None), + location=location_.earthlocation, ) ).altaz azel = AzEl( - index=time.index, + index=time_.index, data={ - "az": altaz.az, # type: ignore - "el": altaz.alt, # type: ignore + "az": skycoord.az, # type: ignore + "el": skycoord.alt, # type: ignore }, ) - azel.location = location - azel.object = object - azel.time = time + azel.location = location_ + azel.object = object_ + azel.time = time_ return azel diff --git a/azely/utils.py b/azely/utils.py index a59cbbc..38f0e0c 100644 --- a/azely/utils.py +++ b/azely/utils.py @@ -3,10 +3,11 @@ # standard library from contextlib import contextmanager -from dataclasses import asdict, replace +from dataclasses import asdict from functools import wraps from inspect import Signature from os import PathLike +from re import search from typing import Any, Callable, Iterator, TypeVar, Union @@ -37,10 +38,11 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: append = bound.arguments.get("append", True) overwrite = bound.arguments.get("overwrite", False) + sep = bound.arguments.get("sep", r"\s*;\s*") source = bound.arguments.get("source", None) query = bound.arguments.get("query", None) - if source is None: + if source is None or query is None or search(sep, query): return func(*args, **kwargs) with sync_toml(source) as doc: From a2271a16ba49e8dd6eba736e6bf3cd5649f7a53f Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sun, 6 Jul 2025 12:06:20 +0000 Subject: [PATCH 16/17] #98 Update release date --- CITATION.cff | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index a8bbb20..d9130fa 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,7 +4,8 @@ cff-version: 1.2.0 title: azely message: >- - If you use this software, please cite it using the metadata from this file. + If you use this software, please cite it using the + metadata from this file. type: software authors: - given-names: Akio @@ -28,4 +29,4 @@ keywords: - visibility license: MIT version: 1.0.0 -date-released: '2022-11-03' +date-released: '2025-07-07' From 3ada84cfba3593d18b8b2aedf9f222dacc2d858c Mon Sep 17 00:00:00 2001 From: Akio Taniguchi <13254278+astropenguin@users.noreply.github.com> Date: Sun, 6 Jul 2025 14:15:06 +0000 Subject: [PATCH 17/17] #98 Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff8821d..fc48777 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ ax.legend() ## Advanced Usage -### Local Sidereal Time +### Handling Local Sidereal Time Using the `in_lst()` method of the output DataFrame, you can convert its time index to the local sidereal time (LST). Here is a example script that shows JST on the bottom axis and LST on the top axis: @@ -205,7 +205,7 @@ If you are migrating from Azely version 0.7.0, please check the following change - The `view` option has been removed. The timezone is inferred from the `location` or can be specified within the `time`. - The default value settings via `config.toml` has been removed. -### The `in_lst` property of the output DataFrame has become a method. +### The `in_lst` property of the output DataFrame has become a method. - **0.7.0:** `df.in_lst` (and `df.in_utc`) - **1.0.0:** `df.in_lst()` (and `df.in_utc()`)