Skip to content

Commit

Permalink
Merge pull request #589 from akrherz/231116
Browse files Browse the repository at this point in the history
Omnibus
  • Loading branch information
akrherz authored Nov 17, 2023
2 parents 41861dc + b5750e4 commit e086772
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 188 deletions.
12 changes: 6 additions & 6 deletions htdocs/json/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,8 @@
"example" => array(
"{latitude}" => "42.5",
"{longitude}" => "-95.0",
"{sdate}" => "2015/06/01",
"{edate}" => "2015/07/01",
"{sdate}" => "2015-06-01",
"{edate}" => "2015-07-01",
)
);

Expand Down Expand Up @@ -587,14 +587,14 @@
of product issuance is used for the date filtering.",
"vars" => array(
"ugc" => "Five character UGC identifier used by the NWS",
"sdate" => "YYYY/mm/dd Start Date (UTC)",
"edate" => "YYYY/mm/dd End Date (UTC)",
"sdate" => "YYYY-mm-dd Start Date (UTC)",
"edate" => "YYYY-mm-dd End Date (UTC)",
"fmt" => "(optional) Format to download as: json (default) or xlsx"
),
"example" => array(
"{ugc}" => "IAC001",
"{sdate}" => "1990/06/01",
"{edate}" => "1990/07/01",
"{sdate}" => "1990-06-01",
"{edate}" => "1990-07-01",
)
);
$services[] = array(
Expand Down
18 changes: 12 additions & 6 deletions htdocs/json/vtec_events_bypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from io import BytesIO, StringIO

import pandas as pd
from pyiem.exceptions import IncompleteWebRequest
from pyiem.nws.vtec import VTEC_PHENOMENA, VTEC_SIGNIFICANCE, get_ps_string
from pyiem.util import get_sqlalchemy_conn, html_escape
from pyiem.webutil import iemapp
Expand Down Expand Up @@ -88,17 +89,22 @@ def to_json(df):
return json.dumps(res)


def parse_date(val):
"""convert string to date."""
fmt = "%Y/%m/%d" if "/" in val else "%Y-%m-%d"
return datetime.datetime.strptime(val, fmt)


@iemapp()
def application(environ, start_response):
"""Answer request."""
lat = float(environ.get("lat", 42.5))
lon = float(environ.get("lon", -95.5))
sdate = datetime.datetime.strptime(
environ.get("sdate", "1986/1/1"), "%Y/%m/%d"
)
edate = datetime.datetime.strptime(
environ.get("edate", "2099/1/1"), "%Y/%m/%d"
)
try:
sdate = parse_date(environ.get("sdate", "1986-01-01"))
edate = parse_date(environ.get("edate", "2099-01-01"))
except Exception as exp:
raise IncompleteWebRequest(str(exp))
cb = environ.get("callback", None)
fmt = environ.get("fmt", "json")

Expand Down
7 changes: 4 additions & 3 deletions htdocs/json/vtec_events_byugc.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,17 @@ def as_json(df):

def parse_date(val):
"""convert string to date."""
return datetime.datetime.strptime(val, "%Y/%m/%d")
fmt = "%Y/%m/%d" if "/" in val else "%Y-%m-%d"
return datetime.datetime.strptime(val, fmt)


@iemapp()
def application(environ, start_response):
"""Answer request."""
ugc = environ.get("ugc", "IAC001")[:6]
try:
sdate = parse_date(environ.get("sdate", "1986/1/1"))
edate = parse_date(environ.get("edate", "2099/1/1"))
sdate = parse_date(environ.get("sdate", "1986-01-01"))
edate = parse_date(environ.get("edate", "2099-01-01"))
except Exception as exp:
raise IncompleteWebRequest(str(exp))
cb = environ.get("callback", None)
Expand Down
8 changes: 8 additions & 0 deletions htdocs/nws/snowfall_6hour.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
$wfo = isset($_REQUEST["wfo"]) ? xssafe($_REQUEST["wfo"]) : "DMX";
$w = isset($_REQUEST["w"]) ? xssafe($_REQUEST["w"]) : "all";
$state = isset($_REQUEST["state"]) ? xssafe($_REQUEST["state"]) : "IA";
// side logic for when $w is not set
if (!isset($_REQUEST["w"])){
if (isset($_REQUEST["wfo"])){
$w = "wfo";
} else if (isset($_REQUEST["state"])){
$w = "state";
}
}

$t->title = "NWS Six Hour Snowfall Reports";
$t->refresh = 360;
Expand Down
54 changes: 38 additions & 16 deletions htdocs/plotting/auto/scripts100/p152.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""
This map produces an analysis of change in
the number of days for the growing season.
the number of days for the growing season. This is defined by the period
between the last spring low temperature below 32 degrees and the first fall
date below 32 degrees. This analysis tends to be very noisy, so picking
longer periods of time for each period will help some.
"""

import pandas as pd
from pyiem.exceptions import NoDataFound
from pyiem.plot import MapPlot, centered_bins, get_cmap
from pyiem.reference import SECTORS_NAME
from pyiem.util import get_autoplot_context, get_sqlalchemy_conn
from sqlalchemy import text

PDICT = {"state": "State Level Maps (select state)"}
PDICT.update(SECTORS_NAME)
Expand Down Expand Up @@ -100,38 +104,56 @@ def plotter(fdict):
table = f"alldata_{state}"
with get_sqlalchemy_conn("coop") as conn:
df = pd.read_sql(
f"""
text(
f"""
WITH season1 as (
SELECT station, year,
min(case when month > 7 and low < 32 then
extract(doy from day) else 366 end) as first_freeze,
max(case when month < 7 and low < 32 then
extract(doy from day) else 0 end) as last_freeze
from {table} WHERE
year >= %s and year <= %s GROUP by station, year),
year >= :p1syear and year <= :p1eyear GROUP by station, year),
season2 as (
SELECT station, year,
min(case when month > 7 and low < 32 then
extract(doy from day) else 366 end) as first_freeze,
max(case when month < 7 and low < 32 then
extract(doy from day) else 0 end) as last_freeze
from {table} WHERE
year >= %s and year <= %s GROUP by station, year),
year >= :p2syear and year <= :p2eyear GROUP by station, year),
agg1 as (
SELECT station as p1station, avg(first_freeze) as p1_first_fall,
avg(last_freeze) as p1_last_spring,
count(first_freeze) as p1_count
from season1 GROUP by station),
agg2 as (
SELECT station as p2station, avg(first_freeze) as p2_first_fall,
avg(last_freeze) as p2_last_spring,
count(first_freeze) as p2_count
from season2 GROUP by station),
agg as (
SELECT p1.station, avg(p1.first_freeze) as p1_first_fall,
avg(p1.last_freeze) as p1_last_spring,
avg(p2.first_freeze) as p2_first_fall,
avg(p2.last_freeze) as p2_last_spring
from season1 as p1 JOIN season2 as p2 on (p1.station = p2.station)
GROUP by p1.station)
SELECT station, ST_X(geom) as lon, ST_Y(geom) as lat,
SELECT a.p1station as station, p1_first_fall, p1_last_spring,
p2_first_fall, p2_last_spring, p1_count, p2_count
from agg1 a JOIN agg2 b on (a.p1station = b.p2station) WHERE
p1_count > :p1quorum and p2_count > :p2quorum
)
SELECT ST_X(geom) as lon, ST_Y(geom) as lat,
d.* from agg d JOIN stations t ON (d.station = t.id)
WHERE t.network ~* 'CLIMATE'
and substr(station, 3, 1) != 'C' and substr(station, 3, 4) != '0000'
""",
and substr(station, 3, 1) not in ('C', 'D')
and substr(station, 3, 4) != '0000'
"""
),
conn,
params=(p1syear, p1eyear, p2syear, p2eyear),
params={
"p1syear": p1syear,
"p1eyear": p1eyear,
"p2syear": p2syear,
"p2eyear": p2eyear,
"p1quorum": (p1eyear - p1syear) - 2,
"p2quorum": (p2eyear - p2syear) - 2,
},
index_col="station",
)
if df.empty:
Expand All @@ -143,7 +165,7 @@ def plotter(fdict):
df["fall_delta"] = df["p2_first_fall"] - df["p1_first_fall"]
# Reindex so that most extreme values are first
df = df.reindex(
df[varname + "_delta"].abs().sort_values(ascending=False).index
df[f"{varname}_delta"].abs().sort_values(ascending=False).index
)

title = PDICT3[varname]
Expand Down
29 changes: 15 additions & 14 deletions htdocs/vtec/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const BACKEND_EVENTS_BYUGC = '/json/vtec_events_byugc.py';
const BACKEND_SBW_BYPOINT = '/json/sbw_by_point.py';
const BACKEND_EVENTS = "/json/vtec_events.py";
const BACKEND_EVENTS_BYSTATE = "/json/vtec_events_bystate.py";
const DATE_FMT = "yy-mm-dd";

const states = [["AL", "Alabama"], ["AK", "Alaska"], ["AZ", "Arizona"],
["AR", "Arkansas"], ["CA", "California"], ["CO", "Colorado"],
Expand Down Expand Up @@ -89,8 +90,8 @@ function updateTable(){
data: {
lat: $("#lat").val(),
lon: $("#lon").val(),
sdate: $.datepicker.formatDate("yy/mm/dd", sdate1.datepicker("getDate")),
edate: $.datepicker.formatDate("yy/mm/dd", edate1.datepicker("getDate"))
sdate: $.datepicker.formatDate(DATE_FMT, sdate1.datepicker("getDate")),
edate: $.datepicker.formatDate(DATE_FMT, edate1.datepicker("getDate"))
},
url: BACKEND_SBW_BYPOINT,
dataType: "json",
Expand All @@ -116,8 +117,8 @@ function updateTable2ByUGC(){
$.ajax({
data: {
ugc: ugcSelect.val(),
sdate: $.datepicker.formatDate("yy/mm/dd", sdate.datepicker("getDate")),
edate: $.datepicker.formatDate("yy/mm/dd", edate.datepicker("getDate"))
sdate: $.datepicker.formatDate(DATE_FMT, sdate.datepicker("getDate")),
edate: $.datepicker.formatDate(DATE_FMT, edate.datepicker("getDate"))
},
url: BACKEND_EVENTS_BYUGC,
dataType: "json",
Expand All @@ -142,8 +143,8 @@ function updateTable2ByPoint(){
data: {
lat: $("#lat2").val(),
lon: $("#lon2").val(),
sdate: $.datepicker.formatDate("yy/mm/dd", sdate.datepicker("getDate")),
edate: $.datepicker.formatDate("yy/mm/dd", edate.datepicker("getDate"))
sdate: $.datepicker.formatDate(DATE_FMT, sdate.datepicker("getDate")),
edate: $.datepicker.formatDate(DATE_FMT, edate.datepicker("getDate"))
},
url: BACKEND_EVENTS_BYPOINT,
dataType: "json",
Expand Down Expand Up @@ -203,14 +204,14 @@ function buildUI(){
fmt: (btn.data("opt") == "csv") ? "csv" : "xlsx",
lat: $("#lat").val(),
lon: $("#lon").val(),
sdate: $.datepicker.formatDate("yy/mm/dd", sdate1.datepicker("getDate")),
edate: $.datepicker.formatDate("yy/mm/dd", edate1.datepicker("getDate"))
sdate: $.datepicker.formatDate(DATE_FMT, sdate1.datepicker("getDate")),
edate: $.datepicker.formatDate(DATE_FMT, edate1.datepicker("getDate"))
};
if (btn.data("table") == "2"){
url = BACKEND_EVENTS_BYUGC;
params.ugc = ugcSelect.val();
params.sdate = $.datepicker.formatDate("yy/mm/dd", sdate.datepicker("getDate"));
params.edate = $.datepicker.formatDate("yy/mm/dd", edate.datepicker("getDate"));
params.sdate = $.datepicker.formatDate(DATE_FMT, sdate.datepicker("getDate"));
params.edate = $.datepicker.formatDate(DATE_FMT, edate.datepicker("getDate"));
if (table2IsByPoint) {
url = BACKEND_EVENTS_BYPOINT;
params.lon = $("#lon2").val();
Expand Down Expand Up @@ -250,7 +251,7 @@ function buildUI(){
// Date pickers
sdate = $("input[name='sdate']").datepicker({
dateFormat:"mm/dd/yy",
altFormat:"yy/mm/dd",
altFormat:DATE_FMT,
minDate: new Date(1986, 0, 1),
maxDate: new Date(),
onClose: () => {
Expand All @@ -260,7 +261,7 @@ function buildUI(){
sdate.datepicker("setDate", new Date(1986, 0, 1));
edate = $("input[name='edate']").datepicker({
dateFormat:"mm/dd/yy",
altFormat:"yy/mm/dd",
altFormat:DATE_FMT,
minDate: new Date(1986, 0, 1),
defaultDate: +1,
onClose: () => {
Expand All @@ -270,7 +271,7 @@ function buildUI(){
edate.datepicker("setDate", +1);
sdate1 = $("input[name='sdate1']").datepicker({
dateFormat:"mm/dd/yy",
altFormat:"yy/mm/dd",
altFormat:DATE_FMT,
minDate: new Date(2002, 0, 1),
maxDate: new Date(),
onClose: () => {
Expand All @@ -280,7 +281,7 @@ function buildUI(){
sdate1.datepicker("setDate", new Date(2002, 0, 1));
edate1 = $("input[name='edate1']").datepicker({
dateFormat:"mm/dd/yy",
altFormat:"yy/mm/dd",
altFormat:DATE_FMT,
minDate: new Date(2002, 0, 1),
defaultDate: +1,
onClose: () => {
Expand Down
Loading

0 comments on commit e086772

Please sign in to comment.