# Make tree diameter an integer
df.tree_dbh = df.tree_dbh.astype("int64")

df.describe()

len(df[df["tree_dbh"] < 50])

df[df["tree_dbh"] > 100]

df[df["tree_dbh"] < 40].tree_dbh.value_counts(sort=False).plot(kind="bar")

"""
Explanation: Notes on Columns
From data reference PDF
tree_dbh
Diameter of the tree, measured at approximately 54" / 137cm above the ground. Data was collected for both living and dead trees; for stumps, use stump_diam
Because standard measuring tapes are more accessible than forestry-specific measuring tapes designed to measure diameter, users originally measured tree circumference in the field. To better match other forestry datasets, this circumference value was subsequently divided by 3.14159 to transform it to diameter. Both the field measurement and processed value were rounded to the nearest whole inch.
health
Indicates the user's perception of tree health.
End of explanation
"""


tree_size_counts = df.tree_dbh.value_counts(sort=False)

df["size_score"] = np.sqrt(1 + df.tree_dbh)

df.size_score.hist(bins=30)

"""
Explanation: The most common tree trunk size is 4.
Assumptions

Increase in number of trees is a benefit. Every new tree within the radius of the bike station should increase score.
Any tree is valuable, even in poor condition. No negative scores.
There is a diminishing return in increasing tree size.

What is the relative benefit of increasing size of trees? Does a tree twice as large bring twice as much value to publice space? Or do trees have a diminishing return on size?
End of explanation
"""


df.health.value_counts(sort=False).plot(kind="bar")

# One tree does not have health status. Remove it.
df[pd.isnull(df.health)]

df = df[~pd.isnull(df.health)]

"""
Explanation: Much better distrbution. We'll use this for the score.
End of explanation
"""


def define_health(x):
    if x == "Good":
        return 1.0
    elif x == "Fair":
        return 0.8
    elif x == "Poor":
        return 0.6

df["health_multiplier"] = df.health.map(define_health)

df["score"] = df.health_multiplier * df.size_score

df.score.hist(bins=60)

df.describe()

"""
Explanation: Thoughts
Bad health should cause a penalty, good health should simply be 100%.

Good: 100%
Fair: 80%
Poor: 60%
End of explanation
"""


df.to_csv('../data/interim/tree-scores.csv')

"""
Explanation: The equation for the tree score is as follow:
$$
S = h \sqrt{1 + \oslash_{tree}}
$$
$h$ being the health multiplier, from 0.6 to 1.0 depending on the health of the tree.
$\oslash_{tree}$ being the diameter of the tree.
End of explanation
"""


# Merge into stations
stations = pd.read_csv('../data/processed/stations.csv')

# Convert stations csv into buffer polygons
geometry = gpd.GeoSeries([Point(xy) for xy in zip(stations.Longitude, stations.Latitude)])
geometry = geometry.buffer(.0005)

geo_stations = gpd.GeoDataFrame(stations, geometry=geometry)
geo_stations.crs = {'init' :'epsg:4326'}
geo_stations.head()
geo_stations.to_file('../data/interim/geo_stations')

# Merge street quality data with citibike stations using Geopandas Spatial Merge
station_df = gpd.sjoin(geo_stations, df, how="left", op='intersects')

# Save for Map
df.loc[station_df.index_right.dropna().unique(), :].to_csv("../data/map/trees.csv")

station_df

# Create new dataframe with summed score
station_scores = pd.DataFrame()

station_scores["score"] = station_df.groupby(['Station_id']).score.sum()
station_scores["score_mean"] = station_df.groupby(['Station_id']).score.mean()
station_scores["tree_count"] = station_df.groupby(['Station_id']).score.count()
station_scores["station_id"] = station_df.groupby(['Station_id']).score.mean().index

station_scores.fillna(0.0, inplace=True)

station_scores.head(3)

station_scores.describe()

# Histogram of scores
station_scores.score.hist(bins=50)

# Histogram of tree counts
station_scores.tree_count.hist(bins=20)

# Histogram of mean tree score per station
station_scores.score_mean.hist(bins=40)

zero_stations = len(station_scores[station_scores.score == 0])
print("Number of stations without trees:", str(zero_stations))

# Save to CSV
station_scores.to_csv("../data/processed/tree-canopy.csv")

"""
Explanation: Merge Into CSV
End of explanation
"""


