USHCN

package climate.investigation.ushcn;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import climate.util.*;
import climate.graphics.*;
import climate.graphics.animation.*;

import climate.types.*;

import java.text.DecimalFormat;

// ftp://ftp.ncdc.noaa.gov/pub/data/ushcn/v2.5/
// ftp://ftp.ncdc.noaa.gov/pub/data/ushcn/v2.5/ushcn-v2.5-stations.txt
//
public class USHCN{
public static final climate.util.Time TIME = climate.util.Time.get();
public static final climate.util.File FILE = new climate.util.File();
public static final DecimalFormat ONE=new DecimalFormat(“####.0”);
public static final DecimalFormat NONE=new DecimalFormat(“####”);

private static final int FRAME_DELAY = 200;
private static final int FRAME_DWELL = 3000;

//##############################################################################################################################

public static final int FIRST_YEAR  = StringVal.getInt( System.getProperty( “FIRST_YEAR”, “1895” ), 1895 );
public static final int LAST_YEAR   = StringVal.getInt( System.getProperty( “LAST_YEAR”, “2014” ), 2014 );
public static final int NUM_YEARS = LAST_YEAR-FIRST_YEAR+1;

public static final int DURATION = NUM_YEARS/2;

public static final int FIRST_END   = FIRST_YEAR + DURATION – 1;
public static final int LAST_START  = FIRST_END + 1;

public static final int FIRST50_START  = 1962;
public static final int FIRST50_END    = 1986;
public static final int LAST50_START  = 1987;
public static final int LAST50_END    = 2011;

public static final int MAX_SUMMER_MISSES = 15;
String DESCRIPTION = “CONUS USHCN Adjusted TMAX [“+FIRST_YEAR+” thru “+LAST_YEAR+”], excld sta mssng >2 cnsctv yrs, excld yrs mssng >”+MAX_SUMMER_MISSES + ” JJA days”;

public static final String NCDC_CONUS_PRECIP_URL = “http://www.ncdc.noaa.gov/cag/time-series/us/110/00/pcp/3/08/”+FIRST_YEAR+”-“+LAST_YEAR+”.csv”;
public static final String NCDC_GLOBAL_TEMPERATURE_URL = “http://www.ncdc.noaa.gov/cag/time-series/global/globe/land_ocean/ytd/12/1895-2014.csv”;
//##############################################################################################################################

public static final String DATA_SET = “USHCN”;
public static final String DATA_TYPE = “TMAX”;
public static final String AREA = “CONUS”;

public static final String DATA = System.getProperty(“user.home”,””)+”/Climate/data/USHCN”;
public static final String STATIONS_PATH = DATA+”/ushcn-stations.txt”;

public static final String MAX_PATH = DATA+”/US_TMAX”;

public static final String GRAPHICS_BASE = System.getProperty(“user.home”,””)+”/Climate/analysis/HOT_DAYS”;
public static final String GRAPHICS_ROOT = DATA_SET+”_”+AREA+”_”+DATA_TYPE+”_”+FIRST_YEAR+”_”+LAST_YEAR;
public static final String GRAPHICS_DIR = GRAPHICS_BASE+”/”+GRAPHICS_ROOT;
public static final String MAP_GRAPHICS_DIR = GRAPHICS_DIR+”/map”;

public static final int WIDTH = 600;
public static final int LENGTH = 400;

public static final int MAP_WIDTH = WIDTH;
public static final int MAP_LENGTH = LENGTH;

public static final int MISSING = -9999;

public static final int T110     = 1095; // Considering tenths of a degree F
public static final int T100     = 995; // Considering tenths of a degree F
public static final int T95      = 945; // Considering tenths of a degree F
public static final int T90      = 895; // Considering tenths of a degree F
public static final int T80      = 795; // Considering tenths of a degree F

// #####################################################################################################

public int NUM_POSSIBLE_OBS = getNumPossibleObs(FIRST_YEAR,LAST_YEAR);

public float NUM_GOOD[] = new float[NUM_YEARS];

public float DAYS_100_RAW[] = new float[NUM_YEARS];
public float DAYS_100_ADJ[] = new float[NUM_YEARS];

public float DAYS_90_RAW[] = new float[NUM_YEARS];
public float DAYS_90_ADJ[] = new float[NUM_YEARS];

public float DAYS_95_RAW[] = new float[NUM_YEARS];
public float DAYS_95_ADJ[] = new float[NUM_YEARS];

public float PERCENT100_ADJ[] = new float[NUM_YEARS];
public float ALL_TIME_HIGH_ADJ[] = new float[NUM_YEARS];

public float PERCENT_MISSING_DOW[] = new float[7];
public float PERCENT_MISSING_MOY[] = new float[12];

//##############################################################################################################################

public static final int getNumPossibleObs(int first,int last){
int num = 0;
for(int year = first; year<=last; year++){
num += 365;

if(TIME.isLeapYear(year)){
num++;
}
}
return num;
}

public boolean expected(int year,int month,int day){
if(day<=TIME.getDaysInMonth(month)){
return true;
}

if(TIME.isLeapYear(year)&&month==2&&day==29){
return true;
}
return false;
}

// 0         1         2         3         4         5         6         7
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
// AEM00041194  25.2550   55.3640   10.4    DUBAI INTL                             41194
// AEM00041217  24.4330   54.6510   26.8    ABU DHABI INTL                         41217

private class COMPARE_STATION implements Comparator{
public int compare(Object g,Object station){
return ((STATION)g).ID.compareTo(((STATION)station).ID);
}
}
private COMPARE_STATION STATION_COMPARATOR = new COMPARE_STATION();

public class STATION{
public String ID = “”;
public float LAT = MISSING;
public float LON = MISSING;
public float ELV = MISSING;
public String NAME = “”;

public boolean GOOD_YEAR[] = new boolean[NUM_YEARS];
public boolean TRANSIENT = false;

public int YEAR_OF_ALL_TIME_HIGH = MISSING;
public int ALL_TIME_HIGH = MISSING;
public int HIGH_FOR_YEAR_ADJ[] = new int[NUM_YEARS];

public int DAYS_100_RAW[] = new int[NUM_YEARS];
public int DAYS_100_ADJ[] = new int[NUM_YEARS];

public int DAYS_95_RAW[] = new int[NUM_YEARS];
public int DAYS_95_ADJ[] = new int[NUM_YEARS];

public int DAYS_90_RAW[] = new int[NUM_YEARS];
public int DAYS_90_ADJ[] = new int[NUM_YEARS];

public int MRAW[][] = new int[NUM_YEARS][12];
public int MADJ[][] = new int[NUM_YEARS][12];

public int RAW[][][] = new int[NUM_YEARS][12][31];
public int ADJ[][][] = new int[NUM_YEARS][12][31];

public STATION(String id,float lat,float lon){
ID = id;
LAT = lat;
LON = lon;

for(int Y = 0; Y<NUM_YEARS; Y++){
GOOD_YEAR[Y] = true;

HIGH_FOR_YEAR_ADJ[Y] = MISSING;

DAYS_100_RAW[Y] = MISSING;
DAYS_100_ADJ[Y] = MISSING;

DAYS_90_RAW[Y] = MISSING;
DAYS_90_ADJ[Y] = MISSING;

for(int M = 0; M<12; M++){
MRAW[Y][M] = MISSING;
MADJ[Y][M] = MISSING;

for(int D = 0; D<31; D++){
RAW[Y][M][D] = MISSING;
ADJ[Y][M][D] = MISSING;
}
}
}
}

public void print(){
// —System.out.println( ID+”\t”+( int )LAT+”,”+( int )LON+”\t”+NAME );
}

public void analyze(){
// If fewer than xxx missing days, it’s a good year…
for(int Y = 0; Y<NUM_YEARS; Y++){
int NUM_SUMMER_DAYS_MISSING = 0;
for(int M=0; M<12; M++){
int MONTH = M + 1;
if( MONTH==6  ||  MONTH==7  ||  MONTH==8 ){
for(int D=0; D<31; D++){
if( expected( Y,M,D ) ){
if( ADJ[Y][M][D] <= MISSING ){
NUM_SUMMER_DAYS_MISSING++;
}
}
}
}
}

if( NUM_SUMMER_DAYS_MISSING > MAX_SUMMER_MISSES ){
GOOD_YEAR[Y] = false;
}
}

int CONSECUTIVE_BAD_YEARS = 0;
int MAX_CONSECUTIVE_BAD_YEARS = 0;
for( int YEAR=FIRST_YEAR; YEAR<=LAST_YEAR; YEAR++){
int Y = YEAR – FIRST_YEAR;
if( ! GOOD_YEAR[Y] ){
CONSECUTIVE_BAD_YEARS++;
if( CONSECUTIVE_BAD_YEARS > MAX_CONSECUTIVE_BAD_YEARS ){
MAX_CONSECUTIVE_BAD_YEARS = CONSECUTIVE_BAD_YEARS;
}
}
else{
CONSECUTIVE_BAD_YEARS = 0;
}
}

if( MAX_CONSECUTIVE_BAD_YEARS > 2 ){
TRANSIENT = true;
}
}
}

public STATION STATIONS[] = null;

//##############################################################################################################################
//##############################################################################################################################
//##############################################################################################################################

public void readStations(){
// 0         1         2         3         4         5         6         7         8
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
// 011084  31.0581  -87.0547   25.9 AL BREWTON 3 SSE                  —— —— —— +6

ArrayList al = new ArrayList();
String lines[] = FILE.readList(STATIONS_PATH);

for(int l = 0; l<lines.length; l++){
if(lines[l]==null){
continue;
}

String s[] = StringSplit.split(lines[l]);
if(s.length>3){
String id = s[0];
float lat = StringVal.getFloat(s[1],MISSING);
float lon = StringVal.getFloat(s[2],MISSING);
al.add(new STATION(id,lat,lon));
}
}

STATIONS = (STATION[])al.toArray(new STATION[0]);

Arrays.sort( STATIONS, STATION_COMPARATOR);

for(int s = 0; s<STATIONS.length; s++){
STATIONS[s].print();
}
System.out.println(“Added[“+STATIONS.length+”] stations!”);
}

public void readData(){
System.out.println(“Reading Data…”);
long start = TIME.getTime();

FileReader fr = null;
BufferedReader br = null;

try{
fr = new FileReader(MAX_PATH);
br = new BufferedReader(fr);
}
catch(FileNotFoundException e){
e.printStackTrace();
System.exit(0);
}
catch(SecurityException e){
e.printStackTrace();
System.exit(0);
}

// 0         1         2         3         4         5         6         7         8
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
// 011084192712TMAX-9999   -9999   -9999
String prevId = “”;
int Y=0, M=0, D=0;
try{
for(;;){
String str = br.readLine();
if(str==null){
break;
}

String id = str.substring(0,6);
int year = StringVal.getInt(str.substring(6,10),MISSING);
int month = StringVal.getInt(str.substring(10,12),MISSING);

if( id.compareTo(prevId) != 0 ){
prevId = id;
}

if(year<FIRST_YEAR||year>LAST_YEAR){
continue;
}
Y = year – FIRST_YEAR;

if( month<1 || month>12 ){
continue;
}
M = month – 1;

for(int s=0; s<STATIONS.length; s++){
if(STATIONS[s].ID.compareTo(id)==0){
for(int day = 1; day<=31; day++){
D = day – 1;
int n = 16+(day-1)*8;
STATIONS[s].RAW[Y][M][D] = StringVal.getInt(str.substring(n,n+5).trim(),MISSING);
if( STATIONS[s].RAW[Y][M][D] > MISSING ){
STATIONS[s].RAW[Y][M][D] *= 10;
}
}
}
}

}
}
catch(IOException ioe){
ioe.printStackTrace();
System.exit(0);
}

// Close…
try{
br.close();
fr.close();
br = null;
fr = null;
}
catch(IOException ioe){
ioe.printStackTrace();
}

// ———————————————————————————————————–
// Apply the monthly adjustments to the daily data…

int ADJ = 0;

for(int s=0; s<STATIONS.length; s++){
for(Y=0; Y<NUM_YEARS; Y++){
for(M=0; M<12; M++){
// if either adjustment factor is missing, leave adjusted daily temperatures missing…
if( STATIONS[s].MRAW[Y][M]<=MISSING ||  STATIONS[s].MADJ[Y][M]<=MISSING ){
continue;
}

ADJ = STATIONS[s].MADJ[Y][M] – STATIONS[s].MRAW[Y][M];

for(D=0; D<31; D++){
// if the raw daily data is missing, then no adjustment is possible either…
if( STATIONS[s].RAW[Y][M][D] <= MISSING ){
continue;
}
STATIONS[s].ADJ[Y][M][D] = STATIONS[s].RAW[Y][M][D] + ADJ;
}
}
}
}

for(int s=0; s<STATIONS.length; s++){
for(Y=0; Y<NUM_YEARS; Y++){
int YEAR = FIRST_YEAR + Y;

for(M=0; M<12; M++){
for(D=0; D<31; D++){
if( STATIONS[s].RAW[Y][M][D] <= MISSING ){
continue;
}

if( STATIONS[s].ADJ[Y][M][D]  >  STATIONS[s].HIGH_FOR_YEAR_ADJ[Y] ){
STATIONS[s].HIGH_FOR_YEAR_ADJ[Y] = STATIONS[s].ADJ[Y][M][D];
}

if( STATIONS[s].ADJ[Y][M][D]  >  STATIONS[s].ALL_TIME_HIGH ){
STATIONS[s].ALL_TIME_HIGH = STATIONS[s].ADJ[Y][M][D];
STATIONS[s].YEAR_OF_ALL_TIME_HIGH = FIRST_YEAR + Y;
}
}
}
}
}

// ———————————————————————————————————–
// Analy ze ( counts missing stations and some limits… )
ArrayList al = new ArrayList();

for(int s=0; s<STATIONS.length; s++){
STATIONS[s].analyze();
if( !  STATIONS[s].TRANSIENT ){
al.add( STATIONS[s] );
}
}
STATIONS = (STATION[])al.toArray(new STATION[0]);

System.out.println(“\nAfter selection, [“+STATIONS.length+”] stations.\n\n… done.”);
System.out.println(“Time to read and ana lyze[“+TIME.getDurationString(TIME.getTime()-start)+”]\n\n”);
}

// ###############################################################################################################
// ###############################################################################################################
// ###############################################################################################################

public void readAdjustments(){
//USH00011084 1895 -9999      150  2   400  2   400  2   400  2   400  2   300  2 -9999    -9999      200  2 -9999      300  2 -9999
//    STAID         1-11   Character
//    YEAR         13-16   Integer
//    VALUE1       18-22   Integer
//    DMFLAG1      23      Character
//    QCFLAG1      24      Character
//    DSFLAG1      25      Character
//    VALUE2       27-31   Integer
//    DMFLAG2      32      Character
//    QCFLAG2      33      Character
//    DSFLAG2      34      Character
//      .           .          .
//      .           .          .
//      .           .          .
//    VALUE13     126-130   Integer
//    DMFLAG13    131      Character
//    QCFLAG13    132      Character
//    DSFLAG13    133      Character

int year    = 0;
int index   = 0;
int Y=0;

String path = DATA + “/CDIAC2014/ushcn2014_raw_tmax.txt”;
System.out.println( “reading USHCN Monthly Raw Data [“+ path + “]…” );
String list[]  = FILE.readList( path );
for(int l=0; l<list.length; l++){
if( list[l]==null  ||  list[l].length()<133 ){
continue;
}

index    = Arrays.binarySearch( STATIONS, new STATION( list[l].substring(5,11), 0f, 0f ), STATION_COMPARATOR);
year     = StringVal.getInt(     list[l].substring(12,16), 0 );

if( index>=0  &&  index<STATIONS.length  &&  year>=FIRST_YEAR  &&  year<=LAST_YEAR ){
Y = year – FIRST_YEAR;
for(int M=0; M<12; M++){
STATIONS[index].MRAW[Y][M] = StringVal.getInt( list[l].substring( 17+M*9, 17+M*9+5 ).trim(), -99998 );
if(STATIONS[index].MADJ[Y][M] == -99998 ){
System.out.println(“[“+list[l].substring( 17+M*9, 17+M*9+5 )+”]” );
}
}
}
}

path = DATA + “/CDIAC2014/ushcn2014_FLs_52i_tmax.txt”;
System.out.println( “reading USHCN Monthly Adjusted Data [“+ path + “]…” );
list  = FILE.readList( path );
for(int l=0; l<list.length; l++){
if( list[l]==null  ||  list[l].length()<133 ){
continue;
}

index    = Arrays.binarySearch( STATIONS, new STATION( list[l].substring(5,11), 0f, 0f ), STATION_COMPARATOR);
year     = StringVal.getInt(     list[l].substring(12,16), 0 );

if( index>=0  &&  index<STATIONS.length  &&  year>=FIRST_YEAR  &&  year<=LAST_YEAR ){
Y = year – FIRST_YEAR;
for(int M=0; M<12; M++){
STATIONS[index].MADJ[Y][M] = StringVal.getInt( list[l].substring( 17+M*9, 17+M*9+5 ).trim(), -99998 );
if(STATIONS[index].MADJ[Y][M] == -99998 ){
System.out.println(“[“+list[l].substring( 17+M*9, 17+M*9+5 )+”]” );
}
}
}
}
}

// ##########################################################################################################################################
// ##########################################################################################################################################
// ##########################################################################################################################################

public void analyze(){
float YEARS[] = new float[NUM_YEARS];

for(int Y=0; Y<NUM_YEARS; Y++){
int YEAR = FIRST_YEAR + Y;
YEARS[Y] = (float)YEAR + 0.5f;

float NUM_STATIONS = 0f;

float SUM_100_RAW = 0f;
float SUM_100_ADJ = 0f;

float SUM_95_RAW = 0f;
float SUM_95_ADJ = 0f;

float SUM_90_RAW = 0f;
float SUM_90_ADJ = 0f;

for(int s=0; s<STATIONS.length; s++){
if(! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

NUM_STATIONS += 1f;

for(int M=0; M<12; M++){
for(int D=0; D<31; D++){
if( STATIONS[s].RAW[Y][M][D] >= T100 ){
SUM_100_RAW += 1f;
}
for(int N=0; N<10; N++){
if( ( STATIONS[s].ADJ[Y][M][D] – 5 + N ) >= T100 ){ SUM_100_ADJ += 1f; }
}

if( STATIONS[s].RAW[Y][M][D] >= T95 ){
SUM_95_RAW += 1f;
}
for(int N=0; N<10; N++){
if( ( STATIONS[s].ADJ[Y][M][D] – 5 + N ) >= T95 ){ SUM_95_ADJ += 1f; }
}

if( STATIONS[s].RAW[Y][M][D] >= T90 ){
SUM_90_RAW += 1f;
}
for(int N=0; N<10; N++){
if( ( STATIONS[s].ADJ[Y][M][D] – 5 + N ) >= T90 ){ SUM_90_ADJ += 1f; }
}
}
}

DAYS_100_RAW[Y] = SUM_100_RAW / NUM_STATIONS;
DAYS_100_ADJ[Y] = SUM_100_ADJ / NUM_STATIONS / 10f;

DAYS_95_RAW[Y] = SUM_95_RAW / NUM_STATIONS;
DAYS_95_ADJ[Y] = SUM_95_ADJ / NUM_STATIONS / 10f;

DAYS_90_RAW[Y] = SUM_90_RAW / NUM_STATIONS;
DAYS_90_ADJ[Y] = SUM_90_ADJ / NUM_STATIONS / 10f;
}
}

float NUM_ATH_FIRST_HALF   = 0f;
float PERCENT_ATH_FIRST_HALF = 0f;
for(int Y=0; Y<NUM_YEARS; Y++){
int YEAR = FIRST_YEAR + Y;

PERCENT100_ADJ[Y]                = 0f;
ALL_TIME_HIGH_ADJ[Y]            = 0f;

float NUM_STATIONS            = 0f;

for(int s=0; s<STATIONS.length; s++){
if(! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

NUM_STATIONS += 1f;

if( STATIONS[s].HIGH_FOR_YEAR_ADJ[Y]  >  T100 ){
PERCENT100_ADJ[Y] += 1f;
}

if( YEAR == STATIONS[s].YEAR_OF_ALL_TIME_HIGH ){
ALL_TIME_HIGH_ADJ[Y] += 1f;

if( YEAR <= FIRST_END ){
NUM_ATH_FIRST_HALF += 1f;
}
}
}

PERCENT100_ADJ[Y] = PERCENT100_ADJ[Y] * 100f / NUM_STATIONS ;
}

PERCENT_ATH_FIRST_HALF = 100f * NUM_ATH_FIRST_HALF / STATIONS.length;

float FIRSTPERCENT100_ADJ = 0f;
for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
FIRSTPERCENT100_ADJ += PERCENT100_ADJ[Y];
}
FIRSTPERCENT100_ADJ /= DURATION;

float LASTPERCENT100_ADJ = 0f;
for(int YEAR=LAST_START; YEAR<=LAST_YEAR; YEAR++){
int Y = YEAR – FIRST_YEAR;
LASTPERCENT100_ADJ += PERCENT100_ADJ[Y];
}
LASTPERCENT100_ADJ /= DURATION;

// ———————————————————————————————–

float FIRST90_ADJ = 0f;
float FIRST95_ADJ = 0f;
float FIRST100_ADJ = 0f;
float FIRST100_RAW = 0f;
for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
FIRST90_ADJ += DAYS_90_ADJ[Y];
FIRST95_ADJ += DAYS_95_ADJ[Y];
FIRST100_ADJ += DAYS_100_ADJ[Y];
FIRST100_RAW += DAYS_100_RAW[Y];
}
FIRST90_ADJ /= DURATION;
FIRST95_ADJ /= DURATION;
FIRST100_ADJ /= DURATION;
FIRST100_RAW /= DURATION;

float LAST90_ADJ = 0f;
float LAST95_ADJ = 0f;
float LAST100_ADJ = 0f;
float LAST100_RAW = 0f;
for(int YEAR=LAST_START; YEAR<=LAST_YEAR; YEAR++){
int Y = YEAR – FIRST_YEAR;
LAST90_ADJ += DAYS_90_ADJ[Y];
LAST95_ADJ += DAYS_95_ADJ[Y];
LAST100_ADJ += DAYS_100_ADJ[Y];
LAST100_RAW += DAYS_100_RAW[Y];
}
LAST90_ADJ /= DURATION;
LAST95_ADJ /= DURATION;
LAST100_ADJ /= DURATION;
LAST100_RAW /= DURATION;

int ALPHA = 255;
Color RAW_COLOR = Color.RED;
Color ADJ_COLOR = Palettes.Gold;

// ———————————————————————————————–
float mean = Stats.mean(DAYS_100_ADJ);
float std = Stats.standardDeviation(DAYS_100_ADJ);

MountainPlot heat = new MountainPlot( WIDTH,LENGTH,”Average # Days that USHCN TMAX (raw & adjusted) Reached or Exceeded 100F”, 1894,TIME.getYear(), “Year”,0f,20f,”#days”);

heat.plotData( Palettes.applyAlpha( RAW_COLOR,ALPHA ), YEARS, DAYS_100_RAW,  “”,   6 );
heat.drawLine( RAW_COLOR.darker(), 3, FIRST_YEAR+0.5f,FIRST100_RAW, FIRST_END+0.5f,FIRST100_RAW );
heat.drawLine( RAW_COLOR.darker(), 3, LAST_START+0.5f,LAST100_RAW,  LAST_YEAR+0.5f,LAST100_RAW );
heat.plotLabel( “Mean(raw)[“+FIRST_YEAR+”thru” + FIRST_END + “] “+ONE.format( FIRST100_RAW ),0);
heat.plotLabel( “Mean(raw)[“+LAST_START+”thru” + LAST_YEAR + “] “+ONE.format( LAST100_RAW ),3);

heat.plotData( Palettes.applyAlpha( ADJ_COLOR, ALPHA ), YEARS, DAYS_100_ADJ, “”, 7);
heat.drawLine( ADJ_COLOR.darker(), 3, FIRST_YEAR+0.5f,FIRST100_ADJ, FIRST_END+0.5f,FIRST100_ADJ );
heat.drawLine( ADJ_COLOR.darker(), 3, LAST_START+0.5f,LAST100_ADJ,  LAST_YEAR+0.5f,LAST100_ADJ );
heat.plotLabel( “Mean(adjusted)[“+FIRST_YEAR+”thru” + FIRST_END + “] “+ONE.format( FIRST100_ADJ ),1);
heat.plotLabel( “Mean(adjusted)[“+LAST_START+”thru” + LAST_YEAR + “] “+ONE.format( LAST100_ADJ ),4);

heat.plotLabel( “POR STD[“+ONE.format(std)+”] is  “+NONE.format(100*std/mean)+”%  of MEAN[“+ONE.format(mean)+”]”, 7 );

heat.plotSource( DESCRIPTION, 1 );
heat.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_DAYS100.png” );

if( FIRST_YEAR <= 1950 ){
float FIRST_COMPARE = 0f;
for(int YEAR=FIRST50_START; YEAR<=FIRST50_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
FIRST_COMPARE += DAYS_100_ADJ[Y];
}
FIRST_COMPARE /= ( FIRST50_END – FIRST50_START + 1 );

float LAST_COMPARE = 0f;
for(int YEAR=LAST50_START; YEAR<=LAST50_END; YEAR++){
int Y = YEAR – FIRST_YEAR;
LAST_COMPARE += DAYS_100_ADJ[Y];
}
LAST_COMPARE /= ( LAST50_END – LAST50_START + 1);

heat = new MountainPlot( WIDTH,LENGTH,”Average # Days that USHCN Adjusted TMAX Reached or Exceeded 100F”, 1894,TIME.getYear(), “Year”,0f,19f,”#days”);
heat.plotData( Palettes.applyAlpha( ADJ_COLOR, ALPHA ), YEARS, DAYS_100_ADJ, “”, 7);

heat.drawLine( ADJ_COLOR.darker(), 3, FIRST_YEAR+0.5f,FIRST100_ADJ, FIRST_END+0.5f,FIRST100_ADJ );
heat.drawLine( ADJ_COLOR.darker(), 3, LAST_START+0.5f,LAST100_ADJ,  LAST_YEAR+0.5f,LAST100_ADJ );
heat.plotLabel( “Mean(adjusted)[“+FIRST_YEAR+” thru ” + FIRST_END + “] “+ONE.format( FIRST100_ADJ ),1);
heat.plotLabel( “Mean(adjusted)[“+LAST_START+” thru ” + LAST_YEAR + “] “+ONE.format( LAST100_ADJ ),4);

heat.drawLine( Color.BLUE, 3, FIRST50_START,FIRST_COMPARE, FIRST50_END+1,FIRST_COMPARE );
heat.drawLine( Color.BLUE, 3, LAST50_START,LAST_COMPARE,  LAST50_END+1,LAST_COMPARE );
heat.plotLabel( “Mean(adj)[“+FIRST50_START+” thru “+FIRST50_END+ “] “+ONE.format( FIRST_COMPARE ),8);
heat.plotLabel( “Mean(adj)[“+LAST50_START+”  thru ” +LAST50_END+ “] “+ONE.format( LAST_COMPARE ),5);

heat.plotSource( DESCRIPTION, 1 );
heat.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_DAYS100_FIFTY.png” );
}

// ————————————————————————————————————————–

MountainPlot ninetyfive = new MountainPlot( WIDTH,LENGTH, “Average # Days that USHCN TMAX (raw & adjusted) Reached or Exceeded 95F”, 1894,TIME.getYear(), “Year”,0f,40f,”#days”);
ninetyfive.plotData( Palettes.applyAlpha( RAW_COLOR,ALPHA ), YEARS, DAYS_95_RAW, “”,   6 );
ninetyfive.plotData( Palettes.applyAlpha( ADJ_COLOR, ALPHA ), YEARS, DAYS_95_ADJ, “”, 7);
ninetyfive.setColor( ADJ_COLOR.darker() );
ninetyfive.drawLine( ADJ_COLOR.darker(), 3, FIRST_YEAR+0.5f,FIRST95_ADJ, FIRST_END+0.5f,FIRST95_ADJ );
ninetyfive.drawLine( ADJ_COLOR.darker(), 3, LAST_START+0.5f,LAST95_ADJ,  LAST_YEAR+0.5f,LAST95_ADJ );
ninetyfive.plotLabel( “Mean(adj)[“+FIRST_YEAR+”thru” + FIRST_END + “] “+ONE.format( FIRST95_ADJ ),2);
ninetyfive.plotLabel( “Mean(adj)[“+LAST_START+”thru” + LAST_YEAR + “] “+ONE.format( LAST95_ADJ ),5);
ninetyfive.plotSource( DESCRIPTION, 1 );
ninetyfive.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_DAYS95.png” );

// ————————————————————————————————————————–

MountainPlot nineties = new MountainPlot( WIDTH,LENGTH, “Average # Days that USHCN TMAX (raw & adjusted) Reached or Exceeded 90F”, 1894,TIME.getYear(), “Year”,0f,70f,”#days”);
nineties.plotData( Palettes.applyAlpha( RAW_COLOR,ALPHA ), YEARS, DAYS_90_RAW, “”,   6 );
nineties.plotData( Palettes.applyAlpha( ADJ_COLOR, ALPHA ), YEARS, DAYS_90_ADJ, “”, 7);
nineties.setColor( ADJ_COLOR.darker() );
nineties.drawLine( ADJ_COLOR.darker(), 3, FIRST_YEAR+0.5f,FIRST90_ADJ, FIRST_END+0.5f,FIRST90_ADJ );
nineties.drawLine( ADJ_COLOR.darker(), 3, LAST_START+0.5f,LAST90_ADJ,  LAST_YEAR+0.5f,LAST90_ADJ );
nineties.plotLabel( “Mean(adj)[“+FIRST_YEAR+”thru” + FIRST_END + “] “+ONE.format( FIRST90_ADJ ),2);
nineties.plotLabel( “Mean(adj)[“+LAST_START+”thru” + LAST_YEAR + “] “+ONE.format( LAST90_ADJ ),5);
nineties.plotSource( DESCRIPTION, 1 );
nineties.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_DAYS90.png” );

// ————————————————————————————————————————–
// Plot station history of ALL….
BufferedImage bi = new BufferedImage(5*NUM_YEARS+100,STATIONS.length+40+20,BufferedImage.TYPE_INT_RGB);
Graphics2D G = (Graphics2D)bi.getGraphics();
G.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

G.setColor(Color.WHITE);
G.fillRect(0,0,bi.getWidth(),bi.getHeight());

for(int s=0; s<STATIONS.length; s++){
for(int y = 0; y<NUM_YEARS; y++){
if(STATIONS[s].GOOD_YEAR[y]){
G.setColor(Color.GREEN);
}
else {
G.setColor(Color.GRAY);
}

G.drawLine(100+5*y,40+s,100+5*(y+1),40+s);
}
}

G.setColor(Color.BLACK);

for(int s=0; s<STATIONS.length; s++){
if((s%150)==0){
G.setColor(Color.BLACK);
G.drawString(STATIONS[s].ID,100-2-G.getFontMetrics().stringWidth(STATIONS[s].ID),40+s);
}
}

for(int y = 0; y<NUM_YEARS; y++){
int YEAR = FIRST_YEAR+y;
if((YEAR%50)==0){
G.drawString(“”+YEAR,100+5*y,40+STATIONS.length+16);
}
}

G.drawString(“Station”,2,40+STATIONS.length/2+16);

G.setColor(Color.BLACK);
G.drawString( “Status for USHCN TMAX, (xcld missing >2 consecutive years), [“+STATIONS.length+” stations]”,10,10);
G.drawString( “Green: available, Grey: bad year(mssng mnth JJA, or mssng > 10 dys JJA)”,10,24);
FILE.createDirIfNecessary(GRAPHICS_DIR);
FILE.writeBufferedImage(bi,GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_STATION_TIMELINES.png”);

// ———————————————————————
DataPlot plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm(“% Stations TMAX reaching 100F at least once”, “Year”, “%”, 1894,TIME.getYear(), 0, 100f );

for(int y=0; y<NUM_YEARS; y++){
float YEAR=(float)(FIRST_YEAR+y)+0.5f;
plot.plotBar( (float)YEAR, (int)PERCENT100_ADJ[y], Palettes.applyAlpha(Color.RED, ALPHA), 1 );
}

plot.drawLine( Color.RED.darker(), 3, FIRST_YEAR, FIRSTPERCENT100_ADJ, FIRST_END, FIRSTPERCENT100_ADJ);
plot.drawLine( Color.RED.darker(), 3, LAST_START, LASTPERCENT100_ADJ, LAST_YEAR, LASTPERCENT100_ADJ);

plot.plotDataLabel( ONE.format(FIRSTPERCENT100_ADJ)+”% Stations 100F at least once [“+FIRST_YEAR+” thru “+FIRST_END+”]”,  Color.RED.darker(), DataPlot.LEFT, DataPlot.TOP);
plot.plotDataLabel( ONE.format(LASTPERCENT100_ADJ)+”% Stations 100F at least once [“+LAST_START+” thru “+LAST_YEAR+”]”,  Color.RED.darker(), DataPlot.RIGHT, DataPlot.TOP);
plot.plotSource( DESCRIPTION, 1 );
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_PERCENT_100F.png”);

// ———————————————————————

float MAX = 0f;
for(int y=0; y<NUM_YEARS; y++){
if( ALL_TIME_HIGH_ADJ[y] > MAX ){
MAX = ALL_TIME_HIGH_ADJ[y];
}
}

plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm(“# Stations with POR Highest Daily TMAX in Year”, “Year”, “#Sta”, 1894, 2016, 0, 1.1f*MAX );
String s=”[“+(int)(PERCENT_ATH_FIRST_HALF)+”% of All Time High TMAX occurred before “+LAST_START+”]”;
plot.plotDataLabel(s, Color.BLACK, 0, 0);
plot.plotYear(LAST_START, Color.BLACK);
for(int y=0; y<NUM_YEARS; y++){
float YEAR=(float)(FIRST_YEAR+y)+0.5f;
plot.plotBar( YEAR, ALL_TIME_HIGH_ADJ[y], Palettes.applyAlpha(Color.RED, ALPHA), 1 );
}
plot.plotSource( DESCRIPTION, 1 );
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_POR_HIGH_TMAX.png”);

}

// #######################################################################################################
// #######################################################################################################
// #######################################################################################################

public void plotCorrelations(){
String globalt_path = DATA + “/GLOBALT_1895-2014.csv”;
float GMAT[][] = new float[NUM_YEARS][2];
String lines[] = FILE.readList(globalt_path);
for(int l = 0; l<lines.length; l++){
if(lines[l]==null){
continue;
}
String s[] = StringSplit.split(lines[l], “,”);
if( s==null  ||  s.length!=2 ){
continue;
}

int year = StringVal.getInt(s[0],-999);
if( year<FIRST_YEAR  ||  year>LAST_YEAR){
continue;
}
int Y = year – FIRST_YEAR;
GMAT[Y][0] = (float)year+0.5f;
GMAT[Y][1] = StringVal.getFloat( s[1], -9999 );
}

String precip_path = DATA + “/USJJAPRECIP_1895-2014.csv”;
float PRECIP[][] = new float[NUM_YEARS][2];
lines = FILE.readList(precip_path);
for(int l = 0; l<lines.length; l++){
if(lines[l]==null){
continue;
}
String s[] = StringSplit.split(lines[l], “,”);
if( s==null  ||  s.length!=2 ){
continue;
}

int year = StringVal.getInt(s[0].substring(0,4),-999);
if( year<FIRST_YEAR  ||  year>LAST_YEAR){
continue;
}
int Y = year – FIRST_YEAR;
PRECIP[Y][0] = (float)year+0.5f;
PRECIP[Y][1] = StringVal.getFloat( s[1], -9999 );
}

float NUM=0f;
float AVE_PRECIP = 0f;
for(int Y=0; Y<NUM_YEARS; Y++){
if( PRECIP[Y][1] > -999f ){
AVE_PRECIP += PRECIP[Y][1];
NUM += 1f;
}
}
AVE_PRECIP /= NUM;

float PRECIP_DATA[] = new float[NUM_YEARS];
float PRECIP_DEFICIT[] = new float[NUM_YEARS];
float GMAT_DATA[] = new float[NUM_YEARS];
DataSeries precipSeries = new DataSeries( DataSeries.YEARLY, Color.BLUE, “JJA Precip”, “JJA Precip” );
DataSeries deficitSeries = new DataSeries( DataSeries.YEARLY, Palettes.Gold, “JJA Precip Deficit”, “JJA Precip Deficit” );
DataSeries gmatSeries = new DataSeries( DataSeries.YEARLY, Color.RED, “JJA Precip”, “JJA Precip” );
DataSeries hunSeries = new DataSeries( DataSeries.YEARLY, Color.RED, “USHCN 100F Days”, “USHCN 100F Days” );

String YEARS[] = new String[NUM_YEARS];
for(int N = 0; N<NUM_YEARS; N++){
GMAT_DATA[N] = GMAT[N][1];
PRECIP_DATA[N] = PRECIP[N][1];
PRECIP_DEFICIT[N] = AVE_PRECIP – PRECIP[N][1];
YEARS[N] = “”+(N+FIRST_YEAR);

float hun[] = new float[2];
hun[0] = (N+FIRST_YEAR);
hun[1] = DAYS_100_ADJ[N];
hunSeries.addSample(hun);

float def[] = new float[2];
def[0] = (N+FIRST_YEAR);
def[1] = PRECIP_DEFICIT[N];
deficitSeries.addSample(def);

float precip[] = new float[2];
precip[0] = (N+FIRST_YEAR);
precip[1] = PRECIP_DATA[N];
precipSeries.addSample(precip);

float gmat[] = new float[2];
gmat[0] = (N+FIRST_YEAR);
gmat[1] = GMAT_DATA[N];
gmatSeries.addSample(gmat);
}

hunSeries.consolidateSamples();
deficitSeries.consolidateSamples();
precipSeries.consolidateSamples();
gmatSeries.consolidateSamples();

ScatterPlot scatter = new ScatterPlot( WIDTH, LENGTH);
scatter.plotForm(“Mean # Days Temperature exceeded 100F vs NCDC Jun,Jul,Aug Precipitation”,”# days”,0f,17f,”inches of precipitation (Jun through Aug)”,6f,11f);
scatter.setColor(Color.BLUE);
scatter.plotYearlyData( YEARS,PRECIP_DATA,DAYS_100_ADJ,Color.BLUE);
scatter.plotLinearFit(PRECIP_DATA,DAYS_100_ADJ);
scatter.plotDataLabel( DESCRIPTION, Color.BLACK, DataPlot.LEFT, DataPlot.TOP );
scatter.plotSource(NCDC_CONUS_PRECIP_URL, 1 );
scatter.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_PRECIP_CORRELATION.png”);

DataPlot plot = new DataPlot();
plot.plotForm(“CONUS JJA Precipitation”,”Year”,”inches”,1894,TIME.getYear(), 6, 11 );
plot.plotDataSeries(precipSeries, 3 );
plot.plotSource(NCDC_CONUS_PRECIP_URL, 1);
plot.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_JJA_PRECIP.png”);

scatter = new ScatterPlot( WIDTH, LENGTH);
scatter.plotForm(“Mean # Days Temperature exceeded 100F vs NCDC Global Average Temperature Anomaly”,”# days”,0f,17f,”NCDC Global Temperature Anomaly(C)”,-0.5f,0.8f);
scatter.setFont(7);
scatter.setColor(Color.RED);
scatter.plotYearlyData(YEARS,GMAT_DATA,DAYS_100_ADJ,Color.RED);
scatter.plotLinearFit(GMAT_DATA,DAYS_100_ADJ);
scatter.plotSource(NCDC_GLOBAL_TEMPERATURE_URL, 1);
scatter.plotDataLabel( DESCRIPTION, Color.BLACK, DataPlot.LEFT, DataPlot.TOP );
scatter.savePlot( GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_GLOBALT_CORRELATION.png”);
}

public void plotCats(){
int TEMPS[]={    -200,    -100,        0,         100,        200,        300,         400,        500,        600,        700,        800,        900,        1000,        1100,        1200,        1300 };

int NUM_TEMPS=TEMPS.length;
int NUM_CATS=NUM_TEMPS-2;
// #####################################
float CATS_FIRST[]=new float[NUM_CATS];
float CATS_LAST[]=new float[NUM_CATS];

float NUM_FIRST=0f;
float NUM_LAST=0f;

for(int n=0; n<NUM_CATS; n++){
CATS_FIRST[n]=0f;
CATS_LAST[n]=0f;
}

int c = 0;
int TF = 0;
for(int s=0; s<STATIONS.length; s++){

for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y=YEAR-FIRST_YEAR;
if( ! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

for(int m=0; m<12; m++){
for(int d=0; d<31; d++){
if( STATIONS[s].ADJ[Y][m][d] > MISSING ){
NUM_FIRST+=1f;

for(int t=1; t<NUM_TEMPS-1; t++){
c = t-1;
for(int N=0; N<10; N++){
TF = STATIONS[s].ADJ[Y][m][d] – 5 + N;
if( TF >= TEMPS[t-1]  &&  TF < TEMPS[t] ){
CATS_FIRST[c] += 1;
}
}
}
}
}
}
}

for(int YEAR=LAST_START; YEAR<=LAST_YEAR; YEAR++){
int Y=YEAR-FIRST_YEAR;
if( ! STATIONS[s].GOOD_YEAR[Y] ){
continue;
}

for(int m=0; m<12; m++){
for(int d=0; d<31; d++){
if( STATIONS[s].ADJ[Y][m][d] > MISSING ){
NUM_LAST+=1f;

for(int t=1; t<NUM_TEMPS-1; t++){
c=t-1;
for(int N=0; N<10; N++){
TF = STATIONS[s].ADJ[Y][m][d] – 5 + N;
if( TF>=TEMPS[t-1]  &&  TF<TEMPS[t] ){
CATS_LAST[c]+=1;
}
}
}
}
}
}
}
}

float MAX=-99999f;
float MIN=99999f;
for(c=0; c<NUM_CATS; c++){
CATS_FIRST[c]  = 365.25f * CATS_FIRST[c]  / NUM_FIRST;
CATS_LAST[c]   = 365.25f * CATS_LAST[c]   / NUM_LAST;

// And because we oversample for considering tenths of a degree adjustment….
CATS_FIRST[c]  /= 10f;
CATS_LAST[c]   /= 10f;

if(CATS_FIRST[c]>MAX){
MAX = CATS_FIRST[c];
}
if(CATS_LAST[c]>MAX){
MAX = CATS_LAST[c];

}
if(CATS_FIRST[c]<MIN){
MIN = CATS_FIRST[c];
}
if(CATS_LAST[c]<MIN){
MIN = CATS_LAST[c];
}
}

// #############################################################################################################################
// #############################################################################################################################
// #############################################################################################################################

DataPlot plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm(“Ave # Days TMAX Occuring For Temperature Band”, “Temperature(F)”, “#Days”, TEMPS[0]/10f, TEMPS[NUM_TEMPS-2]/10f, 0, 1.1f*MAX );
for(c=0; c<NUM_CATS; c++){
int t = c + 1;
plot.plotBar( (TEMPS[t-1]+TEMPS[t])/10f/2f, CATS_FIRST[c],    Color.GRAY, 10 );
plot.plotBar( (TEMPS[t-1]+TEMPS[t])/10f/2f, CATS_LAST[c],    Palettes.DarkGold,    5 );
}
plot.plotDataLabel(“Mean Occurrence of All Obs[“+FIRST_YEAR+” through “+FIRST_END+”]”, Color.GRAY,    0, 0 );
plot.plotDataLabel(“Mean Occurrence of All Obs[“+LAST_START+” through “+LAST_YEAR+”]”, Palettes.DarkGold,        2, 0 );
plot.plotSource( DESCRIPTION, 1 );
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_BAND_COMPARISON.png”);
}
// #######################################################################################################
// #######################################################################################################
// #######################################################################################################

private static final int W=MAP_WIDTH;
private static final int L=MAP_LENGTH;

private static final float MIN_LAT=22, MAX_LAT=55;
private static final float MIN_LON=-127, MAX_LON=-65;

private static final float LAT_RANGE=MAX_LAT-MIN_LAT;
private static final float LON_RANGE=MAX_LON-MIN_LON;

public int getI(float lon){
return (int)((float)W*(lon-MIN_LON)/LON_RANGE);
}

public int getJ(float lat){
return (int)((float)L*(MAX_LAT-lat)/LAT_RANGE);
}

private void DRAW_LINE(float Lat1, float Lon1, float Lat2, float Lon2, int Code, Graphics2D G){
switch(Code){
default:
G.drawLine(getI(Lon1), getJ(Lat1), getI(Lon2), getJ(Lat2));
}
}

private GeoPoliticalBoundaries GP=new GeoPoliticalBoundaries(){
public void drawLine(float Lat1, float Lon1, float Lat2, float Lon2, int Code){
}

public void drawLine(float Lat1, float Lon1, float Lat2, float Lon2, int Code, Graphics2D G){
DRAW_LINE(Lat1, Lon1, Lat2, Lon2, Code, G);
}

public void setupDraw(java.awt.Graphics2D G){
G.setColor(Color.BLACK);
}
};

public void plotMaxMap(){

Color colors[]={ Color.BLACK, Color.WHITE, Color.GREEN, Palettes.Tan, Color.ORANGE, Color.RED, Palettes.Purple };

AnimatedGifEncoder AGE=new AnimatedGifEncoder();
String ANIM_PATH=GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_ANNUAL_MAX.gif”;
AGE.start(ANIM_PATH);
AGE.setRepeat(0);
AGE.setDelay(FRAME_DELAY); // 1 frame per sec

for(int Y=0; Y<NUM_YEARS; Y++){
GeoFrameRenderer.setAlpha(false);
BufferedImage BI=new BufferedImage( W, L, BufferedImage.TYPE_INT_RGB);
GeoFrameRenderer.setMap(BI, MIN_LAT, MIN_LON, MAX_LAT, MAX_LON);
Graphics2D G=(Graphics2D)BI.getGraphics();

G.setColor(Color.WHITE);
G.fillRect(0, 0, BI.getWidth(), BI.getHeight());

G.setColor(Color.BLACK);
GP.draw(G);

for(int s=0; s<STATIONS.length; s++){
if(!STATIONS[s].GOOD_YEAR[Y]){
continue;
}

int x=getI(STATIONS[s].LON);
int y=getJ(STATIONS[s].LAT);

G.setColor(Palettes.Purple);
if( STATIONS[s].HIGH_FOR_YEAR_ADJ[Y] < T110 ){
G.setColor(Color.RED);
}
if( STATIONS[s].HIGH_FOR_YEAR_ADJ[Y]< T100){
G.setColor(Color.ORANGE);
}
if( STATIONS[s].HIGH_FOR_YEAR_ADJ[Y]< T90){
G.setColor(Palettes.Tan);
}
if( STATIONS[s].HIGH_FOR_YEAR_ADJ[Y]< T80){
G.setColor(Color.GREEN);
}
G.fillArc(x-2, y-2, 5, 5, 0, 360);
}

G.setFont(new Font(null, Font.PLAIN, 12));
G.setColor(Color.WHITE);
G.fillRect(0, 0, W, 20);
G.setColor(Color.BLACK);
G.drawString(“Highest Daily TMAX for year “+(FIRST_YEAR+Y), 10, 10);
G.setColor(Palettes.Purple);
G.drawString(“>110F”, 350, 10);
G.setColor(Color.RED);
G.drawString(“>100F”, 400, 10);
G.setColor(Color.ORANGE);
G.drawString(“>90F”, 450, 10);
G.setColor(Palettes.Tan);
G.drawString(“>80F”, 500, 10);
G.setColor(Color.GREEN);
G.drawString(“<=80F”, 550, 10);

G.setFont(new Font(null, Font.PLAIN, 10));
G.setColor(Color.WHITE);
G.fillRect(0, L-18, W, 18);
G.setColor(Color.BLACK);
G.drawString( DESCRIPTION, W/2 – G.getFontMetrics().stringWidth(DESCRIPTION)/2, L-4 );

String dir=MAP_GRAPHICS_DIR+”/ANNUAL_MAX”;
FILE.createDirIfNecessary(dir);
String path=dir+”/”+GRAPHICS_ROOT+”___”+(FIRST_YEAR+Y)+”.png”;
FILE.writeBufferedImage(BI, path);

if(Y==(NUM_YEARS-1)){
AGE.setDelay(FRAME_DWELL);
}
else {
AGE.setDelay(FRAME_DELAY);
}
AGE.addFrame(BI, colors);
}
AGE.finish();
AGE=null;
}

public void plotAthMap(){
GeoFrameRenderer.setAlpha(false);
BufferedImage BI=new BufferedImage( W, L, BufferedImage.TYPE_INT_RGB);
GeoFrameRenderer.setMap(BI, MIN_LAT, MIN_LON, MAX_LAT, MAX_LON);
Graphics2D G=(Graphics2D)BI.getGraphics();

G.setColor(Color.WHITE);
G.fillRect(0, 0, BI.getWidth(), BI.getHeight());

G.setColor(Color.BLACK);
GP.draw(G);

for(int s=0; s<STATIONS.length; s++){
int x=getI(STATIONS[s].LON);
int y=getJ(STATIONS[s].LAT);

G.setColor( Palettes.Purple );
if( STATIONS[s].ALL_TIME_HIGH < T110 ){ G.setColor(Color.RED); }
if( STATIONS[s].ALL_TIME_HIGH< T100){
G.setColor(Color.ORANGE);
}
if( STATIONS[s].ALL_TIME_HIGH< T90){
G.setColor(Palettes.Tan);
}
if( STATIONS[s].ALL_TIME_HIGH< T80){
G.setColor(Color.GREEN);
}
G.fillArc(x-2, y-2, 5, 5, 0, 360);
}

G.setFont(new Font(null, Font.PLAIN, 12));
G.setColor(Color.WHITE);
G.fillRect(0, 0, W, 20);
G.setColor(Color.BLACK);
G.drawString(“Period of Record Highest Daily TMAX”, 10, 10);
G.setColor(Palettes.Purple);
G.drawString(“>110F”, 350, 10);
G.setColor(Color.RED);
G.drawString(“>100F”, 400, 10);
G.setColor(Color.ORANGE);
G.drawString(“>90F”, 450, 10);
G.setColor(Palettes.Tan);
G.drawString(“>80F”, 500, 10);
G.setColor(Color.GREEN);
G.drawString(“<=80F”, 550, 10);

G.setFont(new Font(null, Font.PLAIN, 10));
G.setColor(Color.WHITE);
G.fillRect(0, L-18, W, 18);
G.setColor(Color.BLACK);
G.drawString( DESCRIPTION, W/2 – G.getFontMetrics().stringWidth(DESCRIPTION)/2, L-4 );

String path = GRAPHICS_DIR + “/POR_MAP.png”;
FILE.writeBufferedImage(BI, path);
}

// #######################################################################################################
// #######################################################################################################
// #######################################################################################################

public void plotTrend(){
float MIN=99999f;
float MAX=-99999f;

DataSeries trend=new DataSeries( DataSeries.MONTHLY, Color.RED, “TMAXadj”, “TMAXadj”);

for(int Y=0; Y<NUM_YEARS; Y++){
float NUM=0f;
float SUM=0f;
for(int s=0; s<STATIONS.length; s++){
if( ! STATIONS[s].GOOD_YEAR[Y]){
continue;
}

for(int m=0; m<12; m++){
for(int d=0; d<31; d++){
if( STATIONS[s].ADJ[Y][m][d]>MISSING){
NUM += 1f;
SUM += (float)STATIONS[s].ADJ[Y][m][d]/10f;
}
}
}
}

float ya[]=new float[2];
ya[0]=0.5f+(float)(Y+FIRST_YEAR);
ya[1]= SUM/NUM;
trend.addSample(ya);

if(ya[1]>MAX){
MAX=ya[1];
}
if(ya[1]<MIN){
MIN=ya[1];
}
}

trend.consolidateSamples();

DataPlot plot=new DataPlot(WIDTH, LENGTH);
plot.plotForm( “Simple Mean of Annual CONUS USHCN Adjusted TMAX”, “Year”, “F”, 1894,TIME.getYear(), MIN-1, MAX+1);
plot.plotDataSeriesAndTrend( trend, 3 );
plot.plotDataLabel(trend, 3);
plot.plotSource(DESCRIPTION, 1);
plot.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_MEAN_T.png”);
}

// #######################################################################################################
// #######################################################################################################
// #######################################################################################################

public void plotMissing(){
for(int d=0; d<7; d++){
PERCENT_MISSING_DOW[d] = 0f;
}
for(int m=0; m<12; m++){
PERCENT_MISSING_MOY[m] = 0f;
}

float NUM_DAYS = 0f;

for(int s=0; s<STATIONS.length; s++){
for(int YEAR=FIRST_YEAR; YEAR<=FIRST_END; YEAR++){
int Y=YEAR-FIRST_YEAR;
for(int m=0; m<12; m++){
for(int d=0; d<31; d++){
if( ! expected( YEAR, m+1, d+1 ) ){
continue;
}

NUM_DAYS += 1f;

if( STATIONS[s].ADJ[Y][m][d] <= MISSING ){
int DOW = TIME.getDayOfWeek(YEAR,m+1,d+1, 12,0,0 );
PERCENT_MISSING_DOW[DOW-1] += 1f;
PERCENT_MISSING_MOY[m]     += 1f;
}
}
}
}
}

for(int d=0; d<7; d++){
PERCENT_MISSING_DOW[d] *= 100f;
PERCENT_MISSING_DOW[d] /= NUM_DAYS;
}
for(int m=0; m<12; m++){
PERCENT_MISSING_MOY[m] *= 100f;
PERCENT_MISSING_MOY[m] /= NUM_DAYS;
}

BarChart chart = new BarChart(WIDTH, LENGTH);
chart.plotForm(“Percentage Days missing by Day of the Week”,”%”, 0f,2f );
for(int d=0; d<7; d++){
chart.plot( d,7, 0f,PERCENT_MISSING_DOW[d], TIME.DAYS[d], Color.GRAY );
}
chart.plotSource( DESCRIPTION, 1 );
chart.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_MISSING_DOW.png”);

chart = new BarChart(WIDTH, LENGTH);
chart.plotForm(“Percentage Days missing by Month”,”%”, 0f,2f );
for(int m=0; m<12; m++){
chart.plot( m,12, 0f,PERCENT_MISSING_MOY[m], TIME.MONTHS[m], Color.GRAY );
}
chart.plotSource( DESCRIPTION, 1 );
chart.savePlot(GRAPHICS_DIR+”/”+GRAPHICS_ROOT+”_MISSING_MOY.png”);
}

public static void main(String[] args){
System.out.println(“\n\n################################################################################################\nTMAX…\n”);

FILE.deleteTree(GRAPHICS_DIR);

FILE.createDirIfNecessary(GRAPHICS_DIR);
FILE.createDirIfNecessary(MAP_GRAPHICS_DIR);

USHCN max = new USHCN();

max.readStations();
max.readAdjustments();
max.readData();
max.analyze();

max.plotCorrelations();
max.plotCats();
max.plotMaxMap();
max.plotTrend();
// — max.plotMissing();
max.plotAthMap();
}
}

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment