Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
btupper committed Sep 30, 2024
0 parents commit 9f006d9
Show file tree
Hide file tree
Showing 65 changed files with 9,459 additions and 0 deletions.
Empty file added .nojekyll
Empty file.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# tandy-blog
Data blog for [Tandy Center for Ocean Forecasting](https://www.bigelow.org/services/ocean-forecasting/)

## General guidelines

Follow this [general guide](https://quarto.org/docs/websites/website-blog.html) New posts should follow [this guide](https://quarto.org/docs/websites/website-blog.html) which explains about making sub-directories in the `post/` directory.

### Post naming

Please use the `YYYY-mm-dd_my_post_name` format.

### To code or not to code?

To keep things light weight please do **not** include code in your `index.qmd` unless it is pseudo-code. If you want to have some code that will generate output to be inlcuded in you post, then please make a separate un-rendered file (like `script.R` or `script.py`).


### An example post directory

```
<tandy-blog>/
posts/
2024-09-30_my_cool_post/
index.qmd
script.R
some_small_data.csv.gz
some_image.png
another_image.png
```


## Categories

Let's be judicious in our use of categories (tags really) to facilitate searching by keywords.


## Programming examples vs tutorials

Tutorials probably belong elsewhere - like [here](https://github.com/BigelowLab/handytandy) - but brief examples are good for here.
14 changes: 14 additions & 0 deletions _freeze/posts/cefi-intro/index/execute-results/html.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hash": "8e88a5e5941a44008b9d2358243e0acf",
"result": {
"markdown": "---\ntitle: \"Intro to cefi\"\nformat: html\ndescription: \"Introduction to the cefi package\"\nauthor: \"Ben Tupper\"\ndate: \"2024-09-27\"\n---\n\n\nRecently we started investigating the relatively new [CEFI data portal](https://psl.noaa.gov/cefi_portal/) which looks to be a promising source of modeled environmental covariates suitable for ecological forecasting. The services and datasets are not fully implemented yet, but we are looking ahead to when we might be able to roll these into our workflows. To that end we have created the [cefi](https://github.com/BigelowLab/cefi) R package. \n\nCEFI data is served via a [THREDDS](https://docs.unidata.ucar.edu/tds/current/userguide/index.html) and provides dynamic data access using [OPeNDAP](https://www.opendap.org/). We have always leveraged the [ncdf4 R package](https://CRAN.R-project.org/package=ncdf4), but this time we decided to try our hand at Michael Sumner's [tidync R package](https://CRAN.R-project.org/package=tidync). CEFI data elements are arrayed outputs from model runs (historical and forecast); to cast these as geospatial raster data we access a second \"static\" data element (also OPeNDAP). \n\nHere we show a single forecasted data product for the temperature of the sea floor in the Northwest Atlantic region in 1995.\n\n\n::: {.cell}\n\n:::\n\n\nHere we show the temperature of the bottom (C) for one month. Then we extract the values for the complete forecast (12 months) at the location shown using the blue circle. Then we plot the forecasted temperatures at that location. We are still learning the finer details of how to work with this data, but it looks promising.\n\n~[map](tob-map.png)\n~[timeseries](tob-timeseries.png)\n\n",
"supporting": [],
"filters": [
"rmarkdown/pagebreak.lua"
],
"includes": {},
"engineDependencies": {},
"preserve": {},
"postProcess": true
}
}
14 changes: 14 additions & 0 deletions _freeze/posts/post-with-code/index/execute-results/html.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hash": "642ea65437e65466944030df23b5d2fb",
"result": {
"markdown": "---\ntitle: \"Post With Code\"\nauthor: \"Harlow Malloc\"\ndate: \"2024-09-20\"\ncategories: [news, code, analysis]\nimage: \"image.jpg\"\n---\n\n\nThis is a post with executable code.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n1 + 1\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[1] 2\n```\n:::\n:::\n",
"supporting": [],
"filters": [
"rmarkdown/pagebreak.lua"
],
"includes": {},
"engineDependencies": {},
"preserve": {},
"postProcess": true
}
}
7 changes: 7 additions & 0 deletions _freeze/site_libs/clipboard/clipboard.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions _freeze/site_libs/quarto-listing/list.min.js

Large diffs are not rendered by default.

243 changes: 243 additions & 0 deletions _freeze/site_libs/quarto-listing/quarto-listing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
const kProgressiveAttr = "data-src";
let categoriesLoaded = false;

window.quartoListingCategory = (category) => {
if (categoriesLoaded) {
activateCategory(category);
setCategoryHash(category);
}
};

window["quarto-listing-loaded"] = () => {
// Process any existing hash
const hash = getHash();

if (hash) {
// If there is a category, switch to that
if (hash.category) {
activateCategory(hash.category);
}
// Paginate a specific listing
const listingIds = Object.keys(window["quarto-listings"]);
for (const listingId of listingIds) {
const page = hash[getListingPageKey(listingId)];
if (page) {
showPage(listingId, page);
}
}
}

const listingIds = Object.keys(window["quarto-listings"]);
for (const listingId of listingIds) {
// The actual list
const list = window["quarto-listings"][listingId];

// Update the handlers for pagination events
refreshPaginationHandlers(listingId);

// Render any visible items that need it
renderVisibleProgressiveImages(list);

// Whenever the list is updated, we also need to
// attach handlers to the new pagination elements
// and refresh any newly visible items.
list.on("updated", function () {
renderVisibleProgressiveImages(list);
setTimeout(() => refreshPaginationHandlers(listingId));

// Show or hide the no matching message
toggleNoMatchingMessage(list);
});
}
};

window.document.addEventListener("DOMContentLoaded", function (_event) {
// Attach click handlers to categories
const categoryEls = window.document.querySelectorAll(
".quarto-listing-category .category"
);

for (const categoryEl of categoryEls) {
const category = categoryEl.getAttribute("data-category");
categoryEl.onclick = () => {
activateCategory(category);
setCategoryHash(category);
};
}

// Attach a click handler to the category title
// (there should be only one, but since it is a class name, handle N)
const categoryTitleEls = window.document.querySelectorAll(
".quarto-listing-category-title"
);
for (const categoryTitleEl of categoryTitleEls) {
categoryTitleEl.onclick = () => {
activateCategory("");
setCategoryHash("");
};
}

categoriesLoaded = true;
});

function toggleNoMatchingMessage(list) {
const selector = `#${list.listContainer.id} .listing-no-matching`;
const noMatchingEl = window.document.querySelector(selector);
if (noMatchingEl) {
if (list.visibleItems.length === 0) {
noMatchingEl.classList.remove("d-none");
} else {
if (!noMatchingEl.classList.contains("d-none")) {
noMatchingEl.classList.add("d-none");
}
}
}
}

function setCategoryHash(category) {
setHash({ category });
}

function setPageHash(listingId, page) {
const currentHash = getHash() || {};
currentHash[getListingPageKey(listingId)] = page;
setHash(currentHash);
}

function getListingPageKey(listingId) {
return `${listingId}-page`;
}

function refreshPaginationHandlers(listingId) {
const listingEl = window.document.getElementById(listingId);
const paginationEls = listingEl.querySelectorAll(
".pagination li.page-item:not(.disabled) .page.page-link"
);
for (const paginationEl of paginationEls) {
paginationEl.onclick = (sender) => {
setPageHash(listingId, sender.target.getAttribute("data-i"));
showPage(listingId, sender.target.getAttribute("data-i"));
return false;
};
}
}

function renderVisibleProgressiveImages(list) {
// Run through the visible items and render any progressive images
for (const item of list.visibleItems) {
const itemEl = item.elm;
if (itemEl) {
const progressiveImgs = itemEl.querySelectorAll(
`img[${kProgressiveAttr}]`
);
for (const progressiveImg of progressiveImgs) {
const srcValue = progressiveImg.getAttribute(kProgressiveAttr);
if (srcValue) {
progressiveImg.setAttribute("src", srcValue);
}
progressiveImg.removeAttribute(kProgressiveAttr);
}
}
}
}

function getHash() {
// Hashes are of the form
// #name:value|name1:value1|name2:value2
const currentUrl = new URL(window.location);
const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined;
return parseHash(hashRaw);
}

const kAnd = "&";
const kEquals = "=";

function parseHash(hash) {
if (!hash) {
return undefined;
}
const hasValuesStrs = hash.split(kAnd);
const hashValues = hasValuesStrs
.map((hashValueStr) => {
const vals = hashValueStr.split(kEquals);
if (vals.length === 2) {
return { name: vals[0], value: vals[1] };
} else {
return undefined;
}
})
.filter((value) => {
return value !== undefined;
});

const hashObj = {};
hashValues.forEach((hashValue) => {
hashObj[hashValue.name] = decodeURIComponent(hashValue.value);
});
return hashObj;
}

function makeHash(obj) {
return Object.keys(obj)
.map((key) => {
return `${key}${kEquals}${obj[key]}`;
})
.join(kAnd);
}

function setHash(obj) {
const hash = makeHash(obj);
window.history.pushState(null, null, `#${hash}`);
}

function showPage(listingId, page) {
const list = window["quarto-listings"][listingId];
if (list) {
list.show((page - 1) * list.page + 1, list.page);
}
}

function activateCategory(category) {
// Deactivate existing categories
const activeEls = window.document.querySelectorAll(
".quarto-listing-category .category.active"
);
for (const activeEl of activeEls) {
activeEl.classList.remove("active");
}

// Activate this category
const categoryEl = window.document.querySelector(
`.quarto-listing-category .category[data-category='${category}'`
);
if (categoryEl) {
categoryEl.classList.add("active");
}

// Filter the listings to this category
filterListingCategory(category);
}

function filterListingCategory(category) {
const listingIds = Object.keys(window["quarto-listings"]);
for (const listingId of listingIds) {
const list = window["quarto-listings"][listingId];
if (list) {
if (category === "") {
// resets the filter
list.filter();
} else {
// filter to this category
list.filter(function (item) {
const itemValues = item.values();
if (itemValues.categories !== null) {
const categories = itemValues.categories.split(",");
return categories.includes(category);
} else {
return false;
}
});
}
}
}
}
14 changes: 14 additions & 0 deletions _quarto.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
project:
type: website

website:
title: "Tandy Center for Ocean Forecasting"
description: "Data science blog for the Tandy Center"
navbar:
right:
- about.qmd
- icon: github
href: https://github.com/bigelowlab/tandy-blog
html:
theme: cosmo
css: styles.css
Empty file added _site/.nojekyll
Empty file.
Loading

0 comments on commit 9f006d9

Please sign in to comment.