Using
a Different Area for Some Phrases
Range
Adjustment Questions/Answers
Using Lat/Lon Edit Areas in a Product
USING A
DIFFERENT EDIT AREA FOR SOME PHRASES
Question:
For the ZFP, I want
to
use a smaller edit area in each zone for temperature to capture the
populated areas, but use the entire edit area for all other elements. I
heard it can be done with "intersectAreas" but all references that I've
found in the Text Formatter Reference Guide tie intersectAreas with
local effects. I want to make it clear, I don't want local effects. I
just want the text to say, "HIGHS IN THE MID 50S" and not "HIGHS IN THE
MID 40S EXCEPT MID 50S IN THE POPULATED AREAS"
Answer:
There are several ways to
accomplish this -- you can use
"intersectAreas" or "additionalAreas". Perhaps the simplest
is using "intersectAreas".
1) Define an edit area, say PopulatedAreas, that is the union of all
your populated smaller areas.
2) Make this an "intersectArea" for MaxT and MinT in the product
component definition.
3) Override the "highs_setUp" and "lows_setUp" methods from
ScalarPhrases with the following additional code:
I would like to set up a varDict to allow the user to enter in a given latitude and longitude and have a given product run off that lat/lon pair as the default edit area.
def highs_setUp(self, tree, node):
# This code re-sets the
node's areaLabel to that for the
# intersection of the
current area and the smaller populated areas
# After this is set, the
phrase will work with the smaller area
areaLabel =
node.getAreaLabel()
intersectName =
self.getIntersectName(areaLabel, "PopulatedAreas")
node.set("areaLabel",
intersectName)
elementInfoList =
[self.ElementInfo("MaxT", "List")]
self.subPhraseSetUp(tree,
node, elementInfoList, self.scalarConnector)
return self.DONE()
RANGE ADJUSTMENT
QUESTIONS/ANSWERS
The following is a condensation of a
listserver discussion involving Range
Adjustment:
Kyle: In our grids for today,
we have no wind speeds greater than 13 knots, but our formatters went
with 15 to 25 mph during the afternoon. Same wording problem for the
evening with the same wind speeds. Is there something in the set-up
that I have incorrect? The Overrides file is attached.
Tracy: The range for your winds
is set to have a minimum of 10. I suspect this is why you are getting
the 15-25 mph range.
def minimum_range_nlValue_dict(self, tree, node):
# This threshold is the
"smallest" min/max difference allowed between values reported.
# For example, if threshold
is set to 5 for "MaxT", and the min value is 45
# and the max value is 46,
the range will be adjusted to at least a 5 degree
I would like to set up a varDict to allow the user to enter in a given latitude and longitude and have a given product run off that lat/lon pair as the default edit area.
# range e.g. 43-48.
These are the values that are then submitted for phrasing
# such as:
# HIGHS IN THE
MID 40S
dict =
TextRules.TextRules.minimum_range_nlValue_dict(self, tree, node)
dict["MaxT"] = 1 #defualt 5
dict["MinT"] = 1 #default 5
dict["Wind"] = {
(0,5):0,
(5,15):5,
(15,40):10,
"default":15,
}
return dict
Kyle: I
changed it to 5 and it mostly worked. Instead of 15 to 25 it gave me 15
to 20. The only problem is we do not have a single grid over 15
mph...so it is kind of ignoring the fact that we have some winds less
than 15 mph...and no winds above 15 mph.
Does it just take the
highest wind at any one time, and use that
as the lower end of the range? That's what it seems like it is doing,
at least today.
This may be easier said
than done, but would it be better to
basically go +- 5 mph from the average wind? That way, if you average
wind is 15 mph, you would be given 10-20. Maybe like this...
0 to 3 mph - light or
variable or calm
4 to 7 mph could be around
5
8 to 12 = 5 to 15 or 10 to
15
13 to 17 = 10 to 20
18 to 23 = 15 to 25
24 to 27 = 20 to 30
28 to 33 = 25 to 35
34 to 37 = 30 to 40
38+ could have a range of
15, like 35 to 50.
Dave:
Ahhhhhhh, we are now seeing the "Catch 22" when
forcing ranges(wind, temperature, etc). When we try to stick with the
standard(oldtime) NWS "ranges", you will end up with text forecasts
that don't match what is in the grids.
Jay:
In your local file, try changing the Wind entry in
the
maximum_range_bias_nlValue_dict from "Min" to "Max". I think you'll
want to do the same thing for
the minimum_range_bias_nlValue_dict, as
well. I think this will solve
your problem and give you wind text of
10 to 15 mph instead of 15 to
20 mph.
Dave:
Once again, it is about rounding and ranges in the
BASE level infrastructure. If you truly want accuracy, then there first
should be no rounding and return literal values(i.e. 13 mph, 11 mph,
etc). So, if you have 13kts, then you
will get 15 mph. Add a 5 mph
range, and you will get 15 to 20 mph.
The infrastructure is nearly
wide open, so you can change what you like.
Kyle:
Thanks Jay,
Was
wondering, by doing this what, what would happen if my average wind was
17 mph? Would it round to 15 mph, then go 10 to 15 mph?
I'm mainly curious about the
logic of how these winds are calculated for each time block to see if
there is a problem.
Wade: Here in PDT, we have
primarily eliminated this problem by
using the overrides below. As Dave mentioned, this is mainly a problem
due to rounding. It's not only the round of the internal grid values,
but it's also the rounding of ranges too, especially if you use
Average. For example, let's say I have defined wind values between 5
and 15 mph as having a 5 mph range as a minimum and maximum range.
Let's say all my values within a zone are 10 mph. Since 5 mph can't be
divided evenly, the resulting range ends up being 10-15 mph (i.e., 10
minus 2.5 rounds to 10, and 10 plus 2.5 rounds to 15). This is probably
why you are getting maximum values that don't exist in your grids. An
excellent way to avoid this particular rounding problem is to use only
even values in the maximum and minumum range value dictionaries.
def
maximum_range_nlValue_dict(self, tree, node):
# Maximum range to be reported within
a phrase
I would like to set up a varDict to allow the user to enter in a given latitude and longitude and have a given product run off that lat/lon pair as the default edit area.
# e.g. 5 to 10 mph
# Units depend on the product
dict = TextRules.TextRules.maximum_range_nlValue_dict(self, tree, node)
dict["MaxT"] = 15
dict["MinT"] = 15
dict["WindChill"] = 15
dict["HeatIndex"] = 15
dict["Wind"] = {
(0, 5) : 0,
(5, 100) : 10,
'default': 10,
}
return dict
def minimum_range_nlValue_dict(self, tree, node):
# This threshold is the "smallest"
min/max difference allowed between values reported.
# For example, if threshold is set to 5 for "MaxT", and the min value
is 45
# and the max value is 46, the range will be adjusted to at least a 5
degree
# range e.g. 43-48. These are the values that are then submitted for
phrasing
# such as:
# HIGHS IN THE MID 40S
dict = TextRules.TextRules.minimum_range_nlValue_dict(self, tree, node)
dict["MaxT"] = 5
dict["MinT"] = 5
dict["WindChill"] = 10
dict["HeatIndex"] = 10
dict["Wind"] = {
(0, 5) : 0,
(5,100) : 10,
'default': 10,
}
return dict
def maximum_range_bias_nlValue_dict(self, tree, node):
# "Min", "Average", "Max"
# Should the maximum_range be taken from the "min" "average" or "max"
# value of the current range?
return {
# changed Max to Average
"MaxT": "Min",
"MinT": "Min",
"Wind": "Average",
"otherwise": "Average",
}
def minimum_range_bias_nlValue_dict(self, tree, node):
# "Min", "Average", "Max"
# Should the minimum_range be taken from the "min" "average" or "max"
# value of the current range?
return {
# changed Max to Average
"MaxT": "Min",
"MinT": "Min",
"Wind": "Average",
"otherwise": "Average",
}
Jay:
Every time I deal
with this, my head spins. There's a lot going on behind the scenes with
the rounding and the ranges.
It's been my experience that the vast majority of unexpected words
comes when values are rounded to some value other than the unit value,
e.g., 5 mph instead of 1 mph. The other key points are that rounding
and ranges are applied essentially any time the data are needed. This
means there's a lot of rounding and range application happening in the
background.
There is a hierarchy of methods for determining ranges. Each range type
as two configuration methods: an nlValue_dict and a bias_nlValue_dict.
In the order they are applied, these are: range_nlValue_dict and
range_bias_nlValue_dict minimum_range_nlValue_dict and
minimum_range_bias_nlValue_dict maximum_range_nlValue_dict and
maximum_range_bias_nlValue_dict
The range logic is used to force single value phrasing with the word
"around". For example, if you set "Wind" to 5 in the
range_nlValue_dict, then any wind range in the grids of less than 5 mph
will generate a phrase like "AROUND 10 MPH". The bias value determines
what part of the range is used for the value. If the range logic
"fires", then neither the minimum_range nor the maximum_range logic
"fires".
If the range logic does not "fire", then both the minimum_range and
maximum range logic, in that order, runs. The minimum range ensures the
range is a least the value in the nlValue_dict while the maximum range
ensures the range is no more than the value in the nlValue_dict. The
bias_nlValue_dict entries set which part of the existing range is used
to create the new range. It's worth re-emphasizing that the minumum
range and maximum range logic only applies if the range logic does not
"fire". The only way to always guarantee a minimum range and a maximum
range is to set the range_nlValue_dict entry to a value that will never
trigger the range logic.
Let's use the winds you listed below and walk through the logic. The
minimum wind is 12 and the maximum wind is 15. Before the range logic
is applied, the values are rounded. So, this gives a range of 10 to 15
mph. I think the range_nlValue_dict entry for "Wind" defaults to 0.
Since our range is not less than 0 mph, the range logic does not "fire".
The minimum range logic runs. Since the minimum range for "Wind" is 5
mph, nothing further happens because the existing range is not less
than 5 mph.
The maximum range logic runs. Since the maximum range is 10 mph,
nothing further happens because the existing range is not more that 10
mph.
For the sake of argument, let's say you have a wind range from the
grids of 12 to 28 mph. Rounding is applied and the range becomes 10 to
30 mph. This is more than the range_nlValue_dict threshold, so the
range logic does not "fire", allowing the minimum and maximum range
logic to run. The range is also more the the mimimum_range_nlValue_dict
threshold, so the minimum range logic does not "fire". At this point, I
have to admit I don't know which entry in the
maximum_range_nlValue_dict applies in this case, which is why I made
the range 20. Let's say it's 15 mph. Anyway, the existing range exceeds
the maximum range. Now, here's where the bias comes into play. If the
bias were "Min", the new range would be 10 to 25 mph. The minimum of
the existing range becomes the minimum of the new range and the desired
spread is added to get the new max. If the bias were "Max", the new
range would be 15 to 30 mph. The max of the existing range becomes the
max of the new range and the desired spread is subtracted to get the
new min. Note: the desired range value was rounded before being used to
create the new range. Since it was already a multiple of 5, nothing
unexpected happened. If the bias were "Average", the new range becomes
15 to 30 mph. Very interesting. The average of the existing range
becomes the center point of the new range. Then half the desired range
value is subtracted from/added to that average to get the new min and
max (12.5 and 27.5). Finally, the new min and max are rounded. In this
case, the rounding gave us values we might not have expected.
Your question of what would happen if the average of the wind range was
17 mph has no meaning unless the corresponding bias is "Average".
My guess for what happened to you originally is as follows. The minimum
and maximum values passed to the formatter were in the range 12.5 mph
<= Wind < 17.5 mph. Keep in mind that what the GFE displays for a
value may not be exactly what the value is in the database. Plus, as
data come into the formatters from the grids, they are both converted
and rounded. I think your formatter got a wind range tuple of (15, 15).
With the range_bias value 0, the range logic doesn't fire because 0 is
not less than 0. Then we get to the minimum range logic. You originally
had the value as 10 mph and the bias as minimum. The existing mimimum
was 15, add 10 to get 25, and you end up with text of 15 to 25 mph,
even though that's not in the grids. However, the formatter did exactly
what it was told to do, even if it wasn't what you expected/wanted.
If you want to look at the range code yourself, look at the
applyRangeValues and applyBias methods in TextUtils.
Using Lat/Lon Edit Areas in a Product
Question: I would like to set up a
varDict to allow the user to enter in a given latitude and longitude
and have a given product run off that lat/lon pair as the default edit
area.
Answer:
1. Set up the VariableList so the suer can enter lat/lon values. For
example:
VariableList = [
(("forecast point latitude", "lat"), 20.0, "alphaNumeric"),
(("forecast point longitude", "lon"), -160.0, "alphaNumeric"),
]
2. You can set the Definition["defaultEditAreas"] = [] since it will not
be used at all.
3. In your formatter "generateForecast" method, replace this:
self._areaList = self.getAreaList(argDict)
with something this:
self._areaList = self._getLatLonAreaList(argDict)
4. Finally, include the following method:
def _getLatLonAreaList(self, argDict):
area = self.createLatLonArea(float(self._lat), float(self._lon), 10)
# OPTIONAL SET UP IF YOU WANT THIS AREA SAMPLED FOR HAZARDS
# Save to server
self.saveEditAreas([area])
# Create Hazards Table for this area
hazards = HazardsTable.HazardsTable(
argDict["ifpClient"], [[area.id().name()]], "FWS",
self.filterMethod, argDict["databaseID"],
self._fullStationID)
argDict["hazards"] = hazards
# Remove from server
self.deleteEditAreas([area])
return [(area, "areaName")]