3
3
using System . Data ;
4
4
using System . Diagnostics ;
5
5
using System . Linq ;
6
+ using System . Security . Cryptography . X509Certificates ;
6
7
using System . Text ;
7
8
using System . Threading . Tasks ;
8
9
using eBirdDataVisualizer . Core . Models ;
@@ -12,9 +13,12 @@ namespace eBirdDataVisualizer.Core.Services;
12
13
13
14
public interface IBirdDataService
14
15
{
15
- public Task < IEnumerable < Bird > > GetGridDataAsync ( ) ;
16
+ public Task < IEnumerable < Bird > > GetBirdDataAsync ( ) ;
17
+ public Task < IEnumerable < MonthData > > GetMonthDataAsync ( ) ;
18
+ public Task < DataSourceMetadata > GetMetadataAsync ( ) ;
16
19
public void ClearData ( ) ;
17
20
public Task < bool > ParseData ( string data ) ;
21
+ public Task ParseMetadata ( string name ) ;
18
22
}
19
23
20
24
public class BirdDataService : IBirdDataService
@@ -30,7 +34,20 @@ public class BirdDataService : IBirdDataService
30
34
static DataColumn JanuaryQ3 = new DataColumn ( nameof ( JanuaryQ3 ) , typeof ( double ) ) ;
31
35
static DataColumn JanuaryQ4 = new DataColumn ( nameof ( JanuaryQ4 ) , typeof ( double ) ) ;
32
36
37
+ static DataTable Months = new DataTable ( nameof ( Months ) ) ;
38
+ static DataColumn Month = new DataColumn ( nameof ( Month ) , typeof ( Month ) ) ;
39
+ static DataColumn SampleSizes = new DataColumn ( nameof ( SampleSizes ) , typeof ( List < double > ) ) ;
40
+
41
+ static DataTable Metadata = new DataTable ( nameof ( Metadata ) ) ;
42
+ static DataColumn Name = new DataColumn ( nameof ( Name ) , typeof ( string ) ) ;
43
+ static DataColumn YearStart = new DataColumn ( nameof ( YearStart ) , typeof ( int ) ) ;
44
+ static DataColumn YearEnd = new DataColumn ( nameof ( YearEnd ) , typeof ( int ) ) ;
45
+ static DataColumn MonthStart = new DataColumn ( nameof ( MonthStart ) , typeof ( Month ) ) ;
46
+ static DataColumn MonthEnd = new DataColumn ( nameof ( MonthEnd ) , typeof ( Month ) ) ;
47
+ static DataColumn Location = new DataColumn ( nameof ( Location ) , typeof ( string ) ) ;
48
+
33
49
private static List < Bird > allBirds = new List < Bird > ( ) ;
50
+ private static List < MonthData > allMonths = new List < MonthData > ( ) ;
34
51
35
52
static BirdDataService ( )
36
53
{
@@ -43,31 +60,54 @@ static BirdDataService()
43
60
Birds . Columns . Add ( JanuaryQ3 ) ;
44
61
Birds . Columns . Add ( JanuaryQ4 ) ;
45
62
46
- Birds . Rows . Add ( 0 , "Black-bellied Whistling-Duck" , "Dendrocygna autumnalis" , new List < double > ( ) { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.655E-4 , 2.082E-4 , 4.693E-4 , 4.624E-4 , 8.357E-4 , 9.092E-4 , 8.3E-5 , 0.0012603 , 0.0012944 , 4.97E-5 , 0.0015 , 0.0010597 , 4.18E-4 , 7.671E-4 , 1.218E-4 , 6.09E-5 , 0.0 , 0.0 , 0.0019542 , 0.0 , 4.4E-5 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 } ) ;
47
-
48
- Birds . Rows . Add ( 3 , "West Indian Whistling-Duck" , "Dendrocygna arborea" , new List < double > ( ) { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 } ) ;
49
-
50
- Birds . Rows . Add ( 4 , "Fulvous Whistling-Duck" , "Dendrocygna bicolor" , new List < double > ( ) { 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 0.0 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 3.95E-5 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 0.0015 , 0.0015 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 0.0015 , 0.0 , 0.0015 , 0.0 , 0.0015 , 0.0 , 0.0 , 0.0015 } ) ;
51
-
52
- Birds . Rows . Add ( 1 , "Emu" , "Dromaius novaehollandiae" , new List < double > ( ) { 0.0 , 0.0 , 0.0 , 0.0 , 4.44E-5 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 } ) ;
53
-
54
- Birds . Rows . Add ( 2 , "Snow Goose" , "Anser caerulescens" , new List < double > ( ) { 0.0164127 , 0.0130752 , 0.0147944 , 0.0115589 , 0.0134523 , 0.0070272 , 0.0060272 , 0.0100091 , 0.0097213 , 0.0075751 , 0.0053493 , 0.0031462 , 0.0010052 , 6.83E-4 , 6.52E-4 , 4.76E-4 , 4.164E-4 , 7.41E-5 , 3.391E-4 , 2.279E-4 , 1.186E-4 , 8.3E-5 , 1.8E-4 , 0.0 , 1.491E-4 , 5.39E-5 , 5.89E-5 , 4.18E-5 , 1.18E-4 , 1.828E-4 , 1.218E-4 , 7.95E-5 , 2.555E-4 , 6.514E-4 , 9.051E-4 , 0.0011868 , 0.0010745 , 0.0026718 , 0.0040783 , 0.0059102 , 0.0064931 , 0.0110383 , 0.0122762 , 0.0232245 , 0.0200967 , 0.0151272 , 0.0184791 , 0.030209 } ) ;
63
+ Months . Columns . Add ( Month ) ;
64
+ Months . Columns . Add ( SampleSizes ) ;
55
65
56
- Birds . Rows . Add ( 5 , "Barnacle Goose" , "Branta leucopsis" , new List < double > ( ) { 3.17E-5 , 4.22E-5 , 4.12E-5 , 0.0015 , 3.108E-4 , 5.69E-5 , 3.57E-5 , 0.0015 , 0.0015 , 1.209E-4 , 1.207E-4 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.205E-4 , 5.19E-5 , 0.0 } ) ;
57
-
58
- Birds . Rows . Add ( 5 , "Egyptian Goose" , "Alopochen aegyptiaca" , new List < double > ( ) { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0015 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 4.152E-4 , 1.35E-4 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.97E-5 , 5.11E-5 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 4.48E-5 , 0.0 , 0.0 , 0.0 , 0.0 } ) ;
66
+ Metadata . Columns . Add ( Name ) ;
67
+ Metadata . Columns . Add ( Location ) ;
68
+ Metadata . Columns . Add ( YearStart ) ;
69
+ Metadata . Columns . Add ( YearEnd ) ;
70
+ Metadata . Columns . Add ( MonthStart ) ;
71
+ Metadata . Columns . Add ( MonthEnd ) ;
59
72
60
73
DataSet . Tables . Add ( Birds ) ;
74
+ DataSet . Tables . Add ( Months ) ;
75
+ DataSet . Tables . Add ( Metadata ) ;
61
76
}
62
77
63
- public BirdDataService ( )
78
+ public void ClearData ( )
64
79
{
80
+ for ( int i = 0 ; i < DataSet . Tables . Count ; ++ i )
81
+ DataSet . Tables [ i ] . Rows . Clear ( ) ;
82
+ }
65
83
84
+ private static DataSourceMetadata AllMetadata ( )
85
+ {
86
+ DataSourceMetadata metadata = new DataSourceMetadata ( ) ;
87
+ foreach ( DataRow row in DataSet . Tables [ DataSet . Tables . IndexOf ( Metadata ) ] . Rows )
88
+ {
89
+ metadata . Name = ( string ) row [ Name ] ;
90
+ metadata . YearStart = ( int ) row [ YearStart ] ;
91
+ metadata . YearEnd = ( int ) row [ YearEnd ] ;
92
+ metadata . MonthStart = ( Month ) row [ MonthStart ] ;
93
+ metadata . MonthEnd = ( Month ) row [ MonthEnd ] ;
94
+ metadata . Location = ( string ) row [ Location ] ;
95
+ }
96
+ return metadata ;
66
97
}
67
98
68
- public void ClearData ( )
99
+ private static IEnumerable < MonthData > AllMonths ( )
69
100
{
70
- DataSet . Clear ( ) ;
101
+ List < MonthData > months = new List < MonthData > ( ) ;
102
+ foreach ( DataRow row in DataSet . Tables [ DataSet . Tables . IndexOf ( Months ) ] . Rows )
103
+ {
104
+ months . Add ( new MonthData ( )
105
+ {
106
+ Month = ( Month ) row [ Month ] ,
107
+ SampleSizes = ( List < double > ) row [ SampleSizes ]
108
+ } ) ;
109
+ }
110
+ return months ;
71
111
}
72
112
73
113
private static IEnumerable < Bird > AllBirds ( )
@@ -81,7 +121,6 @@ private static IEnumerable<Bird> AllBirds()
81
121
BirdId = ( int ) row [ BirdId ] ,
82
122
CommonName = ( string ) row [ CommonName ] ,
83
123
ScientificName = ( string ) row [ ScientificName ] ,
84
- Frequency = frequency ,
85
124
JanuaryQ1 = ( double ) frequency [ 0 ] ,
86
125
JanuaryQ2 = ( double ) frequency [ 1 ] ,
87
126
JanuaryQ3 = ( double ) frequency [ 2 ] ,
@@ -135,16 +174,39 @@ private static IEnumerable<Bird> AllBirds()
135
174
return birds ;
136
175
}
137
176
138
- public async Task < IEnumerable < Bird > > GetGridDataAsync ( )
177
+ public async Task < IEnumerable < Bird > > GetBirdDataAsync ( )
139
178
{
140
179
allBirds = new List < Bird > ( AllBirds ( ) ) ;
141
180
142
181
await Task . CompletedTask ;
143
182
return allBirds ;
144
183
}
145
184
185
+ public async Task < IEnumerable < MonthData > > GetMonthDataAsync ( )
186
+ {
187
+ allMonths = new List < MonthData > ( AllMonths ( ) ) ;
188
+
189
+ await Task . CompletedTask ;
190
+ return allMonths ;
191
+ }
192
+
193
+ public async Task < DataSourceMetadata > GetMetadataAsync ( )
194
+ {
195
+ var data = AllMetadata ( ) ;
196
+ await Task . CompletedTask ;
197
+ return data ;
198
+ }
199
+
200
+ /// <summary>
201
+ /// Parse data loaded from an eBird barchart .txt file.
202
+ /// </summary>
203
+ /// <param name="data"></param>
204
+ /// <returns></returns>
146
205
public async Task < bool > ParseData ( string data )
147
206
{
207
+ //Months.Rows.Clear();
208
+ //Birds.Rows.Clear();
209
+
148
210
const string frequencyKey = "Frequency of observations in the selected location(s)" ;
149
211
const string numberTaxaKey = "Number of taxa" ;
150
212
const string sampleSizeKey = "Sample Size" ;
@@ -153,11 +215,37 @@ public async Task<bool> ParseData(string data)
153
215
154
216
try
155
217
{
156
- // Parse the histogram data text:
218
+ // Parse the monthly sample-size data:
219
+ var sampleSizes = data . Trim ( ) . Split ( '\n ' ) // split text into lines
220
+ . Where ( l => l != String . Empty ) // skip empty lines
221
+ . SkipWhile ( l => ! l . Contains ( sampleSizeKey ) ) . First ( ) // skip forward to the line containing sample size data
222
+ . Split ( '\t ' ) // separate the line by the value delimiter
223
+ . Where ( v => v != String . Empty && Double . TryParse ( v , out _ ) ) // exclude empty items and non-numeric values
224
+ . Select ( v => System . Convert . ToDouble ( v ) ) . ToList ( ) ; // cast the remaining items to doubles and return as list
225
+
226
+ // Parse the histogram data for bird entries:
157
227
var lines = data . Trim ( ) . Split ( '\n ' ) // split text into lines
158
- . Where ( l => l != "" ) // skip empty lines
228
+ . Where ( l => l != String . Empty ) // skip empty lines
159
229
. SkipWhile ( l => ! l . Contains ( sampleSizeKey ) ) // skip forward to the line containing sample size data
160
230
. Skip ( 1 ) . ToList ( ) ; // skip the sample size data line; subsequent lines should be bird entries
231
+
232
+ Months . Rows . Clear ( ) ;
233
+ Birds . Rows . Clear ( ) ;
234
+
235
+ int monthCounter = 0 ;
236
+ List < double > samples = new List < double > ( ) ;
237
+ for ( var i = 0 ; i < sampleSizes . Count ( ) + 1 ; ++ i )
238
+ {
239
+ if ( i > 0 && i % 4 == 0 )
240
+ {
241
+ Months . Rows . Add ( ( Month ) Enum . GetValues ( typeof ( Month ) ) . GetValue ( monthCounter ) , samples ) ;
242
+ monthCounter ++ ;
243
+ samples = new List < double > ( ) ;
244
+ }
245
+ if ( i < sampleSizes . Count ( ) )
246
+ samples . Add ( sampleSizes [ i ] ) ;
247
+ }
248
+
161
249
for ( var i = 0 ; i < lines . Count ( ) ; ++ i )
162
250
{
163
251
// the common name appears first in the data entry:
@@ -166,7 +254,7 @@ public async Task<bool> ParseData(string data)
166
254
var scientificNameSplit = commonNameSplit . Last ( ) . Split ( "</em>)" ) ;
167
255
var commonName = commonNameSplit . First ( ) ;
168
256
var scientificName = scientificNameSplit . First ( ) ;
169
- var frequencyData = scientificNameSplit . Last ( ) . Trim ( ) . Split ( '\t ' ) . Where ( x => x != "" ) . Select ( x => System . Convert . ToDouble ( x ) ) . ToList ( ) ;
257
+ var frequencyData = scientificNameSplit . Last ( ) . Trim ( ) . Split ( '\t ' ) . Where ( x => x != String . Empty ) . Select ( x => System . Convert . ToDouble ( x ) ) . ToList ( ) ;
170
258
171
259
Birds . Rows . Add ( i , commonName , scientificName , frequencyData ) ;
172
260
}
@@ -181,4 +269,30 @@ public async Task<bool> ParseData(string data)
181
269
await Task . CompletedTask ;
182
270
return importResult ;
183
271
}
272
+
273
+ public async Task ParseMetadata ( string name )
274
+ {
275
+ var yearStart = 0 ;
276
+ var yearEnd = 0 ;
277
+ var monthStart = Models . Month . January ;
278
+ var monthEnd = Models . Month . January ;
279
+ var location = name . Split ( "__" ) . First ( ) . Split ( '_' ) . Last ( ) ;
280
+ var timeInfo = name . Split ( "__" ) . Last ( ) . Split ( "barchart.txt" ) . First ( ) . Split ( '_' ) . Where ( x => x != String . Empty ) ;
281
+ if ( timeInfo . Count ( ) == 4 )
282
+ {
283
+ try
284
+ {
285
+ yearStart = int . Parse ( timeInfo . ElementAt ( 0 ) ) ;
286
+ yearEnd = int . Parse ( timeInfo . ElementAt ( 1 ) ) ;
287
+ monthStart = ( Month ) ( int . Parse ( timeInfo . ElementAt ( 2 ) ) - 1 ) ;
288
+ monthEnd = ( Month ) ( int . Parse ( timeInfo . ElementAt ( 3 ) ) - 1 ) ;
289
+ }
290
+ catch ( Exception ) { }
291
+ }
292
+
293
+ Metadata . Rows . Clear ( ) ;
294
+ Metadata . Rows . Add ( name , location , yearStart , yearEnd , monthStart , monthEnd ) ;
295
+ await Task . CompletedTask ;
296
+ return ;
297
+ }
184
298
}
0 commit comments