Skip to content

[MVP-1] Geodesy Notebook 1 - #3

Open
eshntmshra wants to merge 6 commits into
EarthScope:mainfrom
eshntmshra:tutorials/mvp-1-geodesy
Open

[MVP-1] Geodesy Notebook 1#3
eshntmshra wants to merge 6 commits into
EarthScope:mainfrom
eshntmshra:tutorials/mvp-1-geodesy

Conversation

@eshntmshra

Copy link
Copy Markdown
Contributor

Draft PR for the first geodesy notebook.

Based on Alex's comments on slack, this might not be as useful or the recommended way of accessing EarthScope GNSS data. We can discard this notebook if not required.

@eshntmshra eshntmshra changed the title [MVP-1] Geodesy Notebook 1 DRAFT. [MVP-1] Geodesy Notebook 1 Jul 1, 2026
@eshntmshra

Copy link
Copy Markdown
Contributor Author

Added a new notebook that uses the EarthScope SDK for data retrieval. This is an introductory notebook that gives a brief introduction of GNSS data and teaches the users how to access it.

"id": "35320cb4-aed2-4420-8f9c-b3deb365e792",
"metadata": {},
"source": [
"**Version:** 1.0 | **Last updated:** 2026-07-09 | **Author:** Eshanta Mishra"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add affiliation: EarthScope Consortium, maintainer: EarthScope OnRamp Team, maintainer contact: help@earthscope.org

"id": "811fc68e-1e81-482c-82dd-5efa2a89d715",
"metadata": {},
"source": [
"## Learning Objectives\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this meant to repeat what is in the introduction/what you will accomplish section?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea is that the introduction/what you will accomplish section is like a summary of the sections/areas that the notebook demonstrates. Learning objective is what the user is expected to learn after completing this notebook. I agree that there is overlap here. I'm happy to merge them if needed.

"\n",
"**Raw Observations vs. derived products**\n",
"\n",
"The data we retrieve in this notebook are raw observations. The geodetic results you may ultimately want such a station's position, displacement over time, etc. are derived products. These derived products are computed by processing many observations together. "

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor text edits:

  • such as
  • etc.,

"id": "52c5e185-8dca-42ff-8a9d-89c23297a761",
"metadata": {},
"source": [
"Since you use your EarthScope account to log into GeoLab, your EarthScope credentials are always available inside it. So, the client authenticates automatically. This removes the step of logging in or passing tokens manually, as you would do in a non GeoLab Environment."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tkbravo - How much authentication content is remaining in Cloud Foundations?

@eshntmshra I think we whould we add a note here, "if you are running this notebook outside geolab, you will need to follow steps (link) to add your authentication here"

"id": "421226b8-42bc-4d91-a517-469c29fa6e85",
"metadata": {},
"source": [
"`AsyncEarthScopeClient` is the asynchronous client. Async lets the SDK process a large query into many concurrent sub-requests, making large quantity of data retrieval more efficient. The SDK also comes with a synchronous `EarthScopeClient` if you prefer."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add hyperlink to sdk documentation where this is discussed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did, but the sdk documentation discussion is not very informative.

"\n",
"**Why it matters**: Some requests such as an entire network for a week will not fit in memory at once. Query plans also limit how many requests hit the API at the same time. Each group's sub-requests run in parallel and are collected into a single table you can process before moving on.\n",
"\n",
"The expected output is a summary for each group (row count, time span, and stations), rather than one huge dataframe."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I ran this, all that printed was "AsyncGnssObservationsQueryPlan(unplanned)" - is this expected?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be getting: AsyncGnssObservationsQueryPlan(requests=40, groups=40)
I reran and got the correct output as above.

"\n",
"\n",
"def summarize(table):\n",
" # Print a quick summary of one group's table.\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps add a commented out line or two of code that would calculate something more exciting, or call out exactly where someone would add their processing steps

"id": "8e88b724-65ec-4ef7-9e19-fb6bbf8c895b",
"metadata": {},
"source": [
"### A rough guide for choosing a strategy"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent

"\n",
"2. **Isolate one signal:** In Section 5, request a single `obs_code` (e.g. `\"5Q\"`) with `field=\"snr\"`. How much smaller is the result?\n",
"\n",
"3. **Save your results:** Write a fetched dataframe to the scratch directory (*Hint: Use `os.environ[\"SCRATCH_BUCKET\"]`*) as Parquet with `df.write_parquet(...)`, then read it back. Parquet preserves types and is far smaller than CSV."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please write an example for this in one of the earlier steps, and maybe have them repeat it for a different dataframe here as an exercise. Writing to scratch and understanding different storage locations is critical. I know it doesn't show up in the plan until MVP2, but it makes sense to introduce here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this meant to be a duplicate file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main file actually. The other file was a hidden checkpoint file that got pushed alongside this one. Since they are identical, I will make changes according to the comments on this file and delete the checkpoint file during next commit.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please go ahead and remove the checkpoint file so we are all reviewing the same file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@hamilton-earthscope hamilton-earthscope left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks good. Some nitpicking on wording.

"\n",
"**What this notebook does:** It instantiates the EarthScope SDK and allows you to retrieve GNSS observations for your station of interest.\n",
"\n",
"**Why it is useful:** This notebook provides a hands-on on how to use the SDK to retrieve GNSS observations from the cloud and load it into a dataframe. It provides the users an insight into how cloud based workflows can be more efficient compared to traditional methods of downloading and accessing GNSS observations as RINEX files.\n",

@hamilton-earthscope hamilton-earthscope Aug 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SDK does not require the user to be in the cloud. Only the part about saving to scratch is really Geolab-specific. But they could just as easily write parquet out to local disk if running outside Geolab.

Suggested change
"**Why it is useful:** This notebook provides a hands-on on how to use the SDK to retrieve GNSS observations from the cloud and load it into a dataframe. It provides the users an insight into how cloud based workflows can be more efficient compared to traditional methods of downloading and accessing GNSS observations as RINEX files.\n",
"**Why it is useful:** This notebook provides a hands-on on how to use the SDK to retrieve GNSS observations from the cloud and load it into a dataframe. It provides the users an insight into how modern workflows can be more efficient compared to traditional methods of downloading and accessing GNSS observations as RINEX files.\n",

Comment on lines +66 to +71
"## Learning Objectives\n",
"\n",
"By the end of this notebook, you will be able to:\n",
"\n",
"1. Instantiate EarthScope SDK client\n",
"2. Retrieve and filter GNSS data from EarthScope"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feels like a repeat of the What you will accomplish: section above

"id": "9e03f7ee-00b4-4501-bd77-551d49ca52a6",
"metadata": {},
"source": [
"A GNSS (Global Navigation Satellite System) is a constellation of satellites that broadcast timing signals. GNSS includes constellations such as GPS (United States), GLONASS (Russia), BeiDou (China) etc. A ground station (receiver plus antenna) records the data transmitted by these satellites several times per minute.\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"A GNSS (Global Navigation Satellite System) is a constellation of satellites that broadcast timing signals. GNSS includes constellations such as GPS (United States), GLONASS (Russia), BeiDou (China) etc. A ground station (receiver plus antenna) records the data transmitted by these satellites several times per minute.\n",
"A Global Navigation Satellite System (GNSS) is a constellation of satellites that broadcast timing signals. GNSS includes constellations such as GPS (United States), GLONASS (Russia), BeiDou (China) etc. A ground station (receiver plus antenna) records the data transmitted by these satellites several times per minute.\n",

"id": "52c5e185-8dca-42ff-8a9d-89c23297a761",
"metadata": {},
"source": [
"Since you use your EarthScope account to log into GeoLab, your EarthScope credentials are always available inside it. So, the client authenticates automatically. This removes the step of logging in or passing tokens manually, as you would do in a non GeoLab Environment. However, if you are running this notebook outside geolab, you will need to authenticate manually using your EarthScope account credentials through the EarthScope CLI (Detailed instructions for doing this can be found [here](https://gitlab.com/earthscope/public/earthscope-cli))."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Since you use your EarthScope account to log into GeoLab, your EarthScope credentials are always available inside it. So, the client authenticates automatically. This removes the step of logging in or passing tokens manually, as you would do in a non GeoLab Environment. However, if you are running this notebook outside geolab, you will need to authenticate manually using your EarthScope account credentials through the EarthScope CLI (Detailed instructions for doing this can be found [here](https://gitlab.com/earthscope/public/earthscope-cli))."
"Since you use your EarthScope account to log into GeoLab, your EarthScope credentials are already available inside it. The client finds your credentials automatically. This removes the step of logging in again using the CLI or passing tokens manually, as you would do in a non-GeoLab Environment. If you are running this notebook outside geolab, you will need to authenticate using the EarthScope CLI (detailed instructions for doing this can be found [here](https://gitlab.com/earthscope/public/earthscope-cli))."

"id": "421226b8-42bc-4d91-a517-469c29fa6e85",
"metadata": {},
"source": [
"`AsyncEarthScopeClient` is the asynchronous client. [Async](https://docs.earthscope.org/sdk/usage#async-usage) lets the SDK process a large query into many concurrent sub-requests, making large quantity of data retrieval more efficient. The SDK also comes with a synchronous `EarthScopeClient` if you prefer."

@hamilton-earthscope hamilton-earthscope Aug 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"`AsyncEarthScopeClient` is the asynchronous client. [Async](https://docs.earthscope.org/sdk/usage#async-usage) lets the SDK process a large query into many concurrent sub-requests, making large quantity of data retrieval more efficient. The SDK also comes with a synchronous `EarthScopeClient` if you prefer."
"`AsyncEarthScopeClient` is the asynchronous client. [Async](https://docs.earthscope.org/sdk/usage#async-usage) lets the SDK process a large query into many concurrent sub-requests, making large quantity of data retrieval more efficient. The SDK also comes with a synchronous `EarthScopeClient` if you prefer. The methods used below are identical on the synchronous client, just remove the `async` / `await` keywords."

Suggest also linking to some other resource (not one we maintain) explaining the difference between python sync/async programming.

"| `obs_code` | str | Which signal was measured, e.g. `1C`, `2W`, `2L` (decoded below). |\n",
"| `range` | float | Pseudorange in meters. It is the apparent satellite to receiver distance. |\n",
"| `phase` | float | Carrier phase in cycles. It is a precise but ambiguous range measurement. |\n",
"| `snr` | float | Signal strength as carrier-to-noise density ($C/N_0$), roughly in dB-Hz. Higher is cleaner. |\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"| `snr` | float | Signal strength as carrier-to-noise density ($C/N_0$), roughly in dB-Hz. Higher is cleaner. |\n",
"| `snr` | float | Signal strength as carrier-to-noise density ($C/N_0$), in dB-Hz. Higher values correspond to stronger signal. |\n",

"id": "c0a4e066-7b6b-4161-9260-a4a825637f2a",
"metadata": {},
"source": [
"When you are working with RINEX files, the files hand you everything, all fields, constellations, satellites etc. Most analyses only need a small slice of these data. Passing filters to `gnss_observations()` in the SDK pushes that selection to the server, so only the data that you asked for is transferred.\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"When you are working with RINEX files, the files hand you everything, all fields, constellations, satellites etc. Most analyses only need a small slice of these data. Passing filters to `gnss_observations()` in the SDK pushes that selection to the server, so only the data that you asked for is transferred.\n",
"When you are working with RINEX files, the files include everything: all fields, constellations, satellites etc. Many analyses only need a small slice of these data. Passing filters to `gnss_observations()` in the SDK pushes that selection to the server, so only the data that you asked for is transferred.\n",

"source": [
"When you are working with RINEX files, the files hand you everything, all fields, constellations, satellites etc. Most analyses only need a small slice of these data. Passing filters to `gnss_observations()` in the SDK pushes that selection to the server, so only the data that you asked for is transferred.\n",
"\n",
"The payoff is immediate: requesting a single signal from a single satellite over two months returns in a fraction of the time and requires smaller memory size, where full RINEX for the same window would be orders of magnitude larger and mostly discarded. You also skip RINEX parsing entirely because the results arrive as an Arrow table ready to load straight into a dataframe, rather than a set of daily text files you have to decode first.\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"The payoff is immediate: requesting a single signal from a single satellite over two months returns in a fraction of the time and requires smaller memory size, where full RINEX for the same window would be orders of magnitude larger and mostly discarded. You also skip RINEX parsing entirely because the results arrive as an Arrow table ready to load straight into a dataframe, rather than a set of daily text files you have to decode first.\n",
"The payoff is immediate: requesting a single signal from a single satellite over two months returns in a fraction of the time and requires less memory, where full RINEX for the same window would be orders of magnitude larger and mostly discarded. You also skip RINEX parsing entirely because the results arrive as an Arrow table, rather than a set of daily text files you have to decode first.\n",

"| Location | Path | Persistence | Use it for |\n",
"|---|---|---|---|\n",
"| **Home** | `/home/jovyan/` | Private, persistent, 50 GB limit | Notebooks, scripts, and results you want to keep while working on your project |\n",
"| **Shared** | `/home/jovyan/shared/` | Read-only | Datasets and starter notebooks placed there by instructors. You can copy files out, but not modify them |\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"| **Shared** | `/home/jovyan/shared/` | Read-only | Datasets and starter notebooks placed there by instructors. You can copy files out, but not modify them |\n",
"| **Shared** | `/home/jovyan/shared/` | Read-only | Datasets and starter notebooks placed there by instructors. You can copy files out, but not modify the original |\n",

"\n",
"**Try these modifications:**\n",
"\n",
"1. **Change the station:** Set `STATION` in the Configuration section to a different 4-character station ID and re-run Section 3. Does the station report the same constellations?\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"1. **Change the station:** Set `STATION` in the Configuration section to a different 4-character station ID and re-run Section 3. Does the station report the same constellations?\n",
"1. **Change the station:** Set `STATION` in the Configuration section to a different 9-character station ID and re-run Section 3. Does the station report the same constellations?\n",

@eshntmshra
eshntmshra marked this pull request as ready for review August 6, 2026 17:40
@eshntmshra eshntmshra changed the title DRAFT. [MVP-1] Geodesy Notebook 1 [MVP-1] Geodesy Notebook 1 Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants