-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
1129 lines (631 loc) · 709 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Save SVG in JS</title>
<link href="/posts/21788/"/>
<content type="html"><![CDATA[<p>To save a SVG when it is rendered in the page, you can write this in the console:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> svgData = $(<span class="string">"#figureSvg"</span>)[<span class="number">0</span>].outerHTML;</span><br><span class="line"><span class="keyword">var</span> svgBlob = <span class="keyword">new</span> Blob([svgData], {<span class="attr">type</span>:<span class="string">"image/svg+xml;charset=utf-8"</span>});</span><br><span class="line"><span class="keyword">var</span> svgUrl = URL.createObjectURL(svgBlob);</span><br><span class="line"><span class="keyword">var</span> downloadLink = <span class="built_in">document</span>.createElement(<span class="string">"a"</span>);</span><br><span class="line">downloadLink.href = svgUrl;</span><br><span class="line">downloadLink.download = <span class="string">"newesttree.svg"</span>;</span><br><span class="line"><span class="built_in">document</span>.body.appendChild(downloadLink);</span><br><span class="line">downloadLink.click();</span><br><span class="line"><span class="built_in">document</span>.body.removeChild(downloadLink);</span><br></pre></td></tr></table></figure><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p><a href="https://stackoverflow.com/questions/23218174/how-do-i-save-export-an-svg-file-after-creating-an-svg-with-d3-js-ie-safari-an" target="_blank" rel="noopener">How do I save/export an SVG file after creating an SVG with D3.js (IE, safari and chrome)?</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> visualization </tag>
</tags>
</entry>
<entry>
<title>How to Draw a Horizon Chart with R</title>
<link href="/posts/7349/"/>
<content type="html"><![CDATA[<p>Commonly, line chart is used to show the temporal change of a variable. But, if the value has a large range, it could take a large space for the chart to show the whole change. Horizon chart dissolved the fluctuations in the line charts in several bands and overlap the bands to show the large range of the values in a relative narrow space. It benefit us to compare various variable in a short time.</p><h3 id="The-data"><a href="#The-data" class="headerlink" title="The data"></a>The data</h3><p>Either vector data or matrix can be the input of the chart. My original dataset is composed of three columns: mon, frequency, and keyword. </p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">library</span>(lattice)</span><br><span class="line"><span class="keyword">library</span>(latticeExtra)</span><br><span class="line"></span><br><span class="line"><span class="comment"># read data</span></span><br><span class="line">paper_all_frequency <- read_csv(<span class="string">"C:your_address_of_the_data.csv"</span>)</span><br><span class="line">paper_all_frequency$mon = as.Date(paste(paper_all_frequency$mon,<span class="string">"-01"</span>,sep=<span class="string">""</span>))</span><br><span class="line"><span class="comment"># ranking the origin dataset by time</span></span><br><span class="line">frequency_ordered = paper_keyword_frequency[order( paper_keyword_frequency$keyword,paper_keyword_frequency$mon),]</span><br><span class="line"><span class="comment"># convert the frequency into matrix</span></span><br><span class="line">paper_frequency = matrix(frequency_ordered$frequency, ncol = <span class="number">5</span>)</span><br><span class="line"><span class="comment"># convert the matrix into the time-series data</span></span><br><span class="line"><span class="comment"># frequency = 12 means the temporal gap is one month</span></span><br><span class="line">paper_frequency = ts(paper_frequency, start = c(<span class="number">2017</span>, <span class="number">1</span>), frequency = <span class="number">12</span>, names = c( <span class="string">"all"</span> , <span class="string">"Artificial intelligence"</span>,<span class="string">"Human computer interaction"</span>,<span class="string">"Life and medical sciences"</span>,<span class="string">"Machine learning"</span>))</span><br></pre></td></tr></table></figure><h3 id="Horizon-chart"><a href="#Horizon-chart" class="headerlink" title="Horizon chart"></a>Horizon chart</h3><p>Draw the horizon chart:</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># draw horizon plot</span></span><br><span class="line"><span class="comment"># nbands indicates the layers of each chart</span></span><br><span class="line"><span class="comment"># horizonscale is the width of each band</span></span><br><span class="line">horizonplot(paper_frequency, nbands = <span class="number">8</span>, horizonscale = <span class="number">150</span>, origin = <span class="number">0</span>, colorkey = <span class="literal">TRUE</span>)</span><br></pre></td></tr></table></figure><p><img src="/images/horizon_chart.png" alt="A Horizon Chart"></p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://rpubs.com/ramanraja/horizon" target="_blank" rel="noopener">Horizon Plots</a><br>[2] <a href="https://bernatgel.github.io/karyoploter_tutorial/Tutorial/PlotHorizon/PlotHorizon.html" target="_blank" rel="noopener">Plotting Horizon Plots</a><br>[3] <a href="https://yonicd.github.io/ggalt/articles/horizon.html" target="_blank" rel="noopener">Horizon Plots</a></p>]]></content>
<categories>
<category> R </category>
</categories>
<tags>
<tag> visualization </tag>
</tags>
</entry>
<entry>
<title>CORS Error</title>
<link href="/posts/4537/"/>
<content type="html"><![CDATA[<p>To ensure the cyber security, JavaScript does not allow a webpage to load extra dataset from another website by default. If you add the resources by using an URL, the error massage <code>Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://cl.ly/2wr4. This can be fixed by moving the resource to the same domain or enabling CORS.</code> will be shown on the console. </p><p>This problem can be solved by enabling the CORS in the HTML file. You can add this following snipet to your HTML head.<br><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="undefined">response.addHeader("Access-Control-Allow-Origin", "http://the_address_of_your_resource");</span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure></p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://www.w3.org/wiki/CORS_Enabled" target="_blank" rel="noopener">CORS Enabled</a></p><p>[2] <a href="https://stackoverflow.com/questions/10636611/how-does-access-control-allow-origin-header-work" target="_blank" rel="noopener">How does Access-Control-Allow-Origin header work?</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> front end </tag>
</tags>
</entry>
<entry>
<title>Postgis Error on st_within</title>
<link href="/posts/37160/"/>
<content type="html"><![CDATA[<p><code>SRID</code> is a spatial reference identifier. The <code>SRID</code> of WGS84 is 4326. In Postgis, the spatial query is based on the geometries have the same <code>SRIDs</code>. When using the PostGIS Shapefile Import/Export Manager, the <code>SRID</code> is shown. </p><p>To check the <code>SRID</code> of a shapefile:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> Find_SRID(<span class="string">'schema_name'</span>, <span class="string">'table_name'</span>, <span class="string">'geom'</span>);</span><br></pre></td></tr></table></figure></p><p>To change the wrong <code>SRID</code> to WGS84:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- update SRID in the polygon</span></span><br><span class="line"><span class="keyword">UPDATE</span> table_name <span class="keyword">SET</span> geom=ST_SetSRID(geom,<span class="number">4326</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- or</span></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> table_name</span><br><span class="line"> <span class="keyword">ALTER</span> <span class="keyword">COLUMN</span> geom <span class="keyword">TYPE</span> geometry(MultiPolygon,<span class="number">4326</span>) </span><br><span class="line"> <span class="keyword">USING</span> ST_SetSRID(geom,<span class="number">4326</span>);</span><br></pre></td></tr></table></figure></p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://postgis.net/2013/08/30/tip_ST_Set_or_Transform/" target="_blank" rel="noopener">ST_Transform and ST_SetSRID: To project or not to project?</a></p><p>[2] <a href="http://stackoverflow.com/questions/35798823/omnimarkuppreviewer-404" target="_blank" rel="noopener">OmniMarkupPreviewer 404</a></p>]]></content>
<categories>
<category> Database </category>
</categories>
<tags>
<tag> spatial query </tag>
</tags>
</entry>
<entry>
<title>Show Changes in Latex</title>
<link href="/posts/33608/"/>
<content type="html"><![CDATA[<p>It is not necessary to manually mark each change of the latex file. One can edit directly in the tex file, using <code>latexdiff</code> to mark the changes texts. One drawback is that when changing the titles of the figures and tables, the changes would note be properly marked. </p><p>The command line for generating the marked tex is:</p><pre><code>latexdiff origin.tex modify.tex > diff.tex</code></pre><p><code>origin.tex</code> is the original tex file. <code>modify.tex</code> is the changed tex file. <code>diff.tex</code> is the tex which could show the changes of the texts.</p>]]></content>
<categories>
<category> Latex </category>
</categories>
<tags>
<tag> writing, tool </tag>
</tags>
</entry>
<entry>
<title>Latex Footnote in Figure Caption</title>
<link href="/posts/25922/"/>
<content type="html"><![CDATA[<p>To add a footnote in a figure caption:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">\begin{figure}[!ht]</span><br><span class="line"> \centering</span><br><span class="line"> \includegraphics[width=3in]{images/radar2.png}</span><br><span class="line"> \caption{A radar chart\protect\footnotemark ~shows overview of the advantages and disadvantages of map-based dashboard and storytelling map. }</span><br><span class="line"> \label{fig:comparison2}</span><br><span class="line">\end{figure}</span><br><span class="line">\footnotetext{The style referred to: https://www.visualcinnamon.com/2015/10/different-look-d3-radar-chart.html}</span><br></pre></td></tr></table></figure><p>Generated PDF:<br><img src="/images/footnote.png" alt="A Footnote in Figure Caption"></p><hr><p>References:</p><p><a href="https://tex.stackexchange.com/questions/452206/footnote-in-caption-and-in-the-same-page-of-caption" target="_blank" rel="noopener">Footnote in caption and in the same page of caption</a></p><p><a href="https://tex.stackexchange.com/questions/228973/argument-of-captionydblarg-has-an-extra" target="_blank" rel="noopener">Argument of \caption@ydblarg has an extra }</a></p>]]></content>
<categories>
<category> Latex </category>
</categories>
<tags>
<tag> writing </tag>
</tags>
</entry>
<entry>
<title>Convert Two-dimensional Table to One-dimensional Table</title>
<link href="/posts/23844/"/>
<content type="html"><![CDATA[<p>The test data is 2D data:</p><p><img src="/images/2Dtable.png" alt="Test data"></p><p>To convert two-dimensional table to one-dimensional table in JavaScript:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">data_1D = [];</span><br><span class="line"></span><br><span class="line">data_2D.filter(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> d.code && d.code!=<span class="string">'SOF46'</span>; <span class="comment">//skip the row "SOF46"</span></span><br><span class="line">}).forEach(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{</span><br><span class="line"> d.sum = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">var</span> p <span class="keyword">in</span> d)</span><br><span class="line"> <span class="keyword">if</span> (p && p!=<span class="string">"code"</span> && p!=<span class="string">"sum"</span>) {</span><br><span class="line"> dataP.push({<span class="string">'code'</span>:d.code,<span class="string">'type'</span>:p,<span class="string">'value'</span>:+d[p]});</span><br><span class="line"> d.sum+=+d[p];</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure><hr><p>Reference: <a href="https://github.com/yurukov/dc.leaflet.js" target="_blank" rel="noopener">dc.leaflet.js</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> snippet </tag>
</tags>
</entry>
<entry>
<title>Load External Geojson to Leaflet</title>
<link href="/posts/35618/"/>
<content type="html"><![CDATA[<p>Geojson benefits the geo-data visualzing. Here we introduce two methods of loading external <code>geojson</code> to <code>Leaflet</code>. <a id="more"></a></p><h3 id="Data-Stucture"><a href="#Data-Stucture" class="headerlink" title="Data Stucture"></a>Data Stucture</h3><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Feature"</span>,</span><br><span class="line"> <span class="attr">"id"</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">"geometry"</span>: {</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Polygon"</span>,</span><br><span class="line"> <span class="attr">"coordinates"</span>: </span><br><span class="line"> ...</span><br><span class="line"> ...</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"properties"</span>: {</span><br><span class="line"> <span class="attr">"FID"</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">"NAME"</span>: <span class="string">"district 1"</span>,</span><br><span class="line"> <span class="attr">"s1980"</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">"s1981"</span>: <span class="string">" "</span>,</span><br><span class="line"> ...</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>geometry</code> saves the information of location. <code>properties</code> saves added information of the place, which is very friendly for feature web mapping.</p><hr><h3 id="Method-1-organize-geojson-as-js"><a href="#Method-1-organize-geojson-as-js" class="headerlink" title="Method 1: organize .geojson as .js"></a>Method 1: organize <code>.geojson</code> as <code>.js</code></h3><p>Organize the <code>.geojson</code> file as a <code>.js</code> file, for example named as <code>geojson_data.js</code>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> geojson1 = {</span><br><span class="line"><span class="string">"type"</span>: <span class="string">"FeatureCollection"</span>,</span><br><span class="line">...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> geojson2 = {...}</span><br></pre></td></tr></table></figure><p>Then import the <code>.js</code> file to the <code>HTML</code> file as a script:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><!-- add the file in the head --></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"geojson_data.js"</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>Then the geojson can be used in the code as an global variable, using <code>geojson1</code> and <code>geojson2</code> directly in the codes.</p><hr><h3 id="Method-2-read-geojson-with-AJAX"><a href="#Method-2-read-geojson-with-AJAX" class="headerlink" title="Method 2: read .geojson with AJAX"></a>Method 2: read <code>.geojson</code> with <code>AJAX</code></h3><p>Firstly, add <code>jQuery</code> and <code>.geojson</code> to the HTML file:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><!-- Add jQuery --></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- add geojson file --></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"location"</span> <span class="attr">type</span>=<span class="string">"application/json"</span> <span class="attr">href</span>=<span class="string">"geojson_data.geojson"</span>/></span></span><br></pre></td></tr></table></figure><p>Then read the <code>geojson</code> file with <code>AJAX</code> in script:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> geojson_file = $.ajax({</span><br><span class="line"> url:<span class="string">"geojson_data.geojson"</span>,</span><br><span class="line"> dataType: <span class="string">"json"</span>,</span><br><span class="line"> success: <span class="built_in">console</span>.log(<span class="string">"Data successfully loaded!"</span>),</span><br><span class="line"> error: <span class="function"><span class="keyword">function</span> (<span class="params">xhr</span>) </span>{</span><br><span class="line"> alert(xhr.statusText)</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure></p><p>However, the <code>geojson</code> data is not the <code>geojson_file</code> we read in the last step. Therefore, we need to extract the <code>geojson</code> data out from geojson file. But, loading the <code>geojson</code> file might take some time, the data extraction can be done only after the file successfully loaded. Otherwise, the errors will be arised as:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">error: Invalid GeoJSON object</span><br></pre></td></tr></table></figure></p><p>Here we use <code>when().done()</code> to solve this problem.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// when the data is ready, draw GeoJSON</span><br><span class="line">$.when(geojson_file).done(function() {</span><br><span class="line"> var geojson = geojson_file.responseJSON;</span><br><span class="line"></span><br><span class="line"> // Add requested external GeoJSON to map</span><br><span class="line"> var Layer_GDP = L.geoJSON(geojson, {</span><br><span class="line"> style: style,</span><br><span class="line"> onEachFeature: onEachFeature</span><br><span class="line"> }).addTo(map);</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><hr><h3 id="Method3-load-with-Leaflet-AJAX"><a href="#Method3-load-with-Leaflet-AJAX" class="headerlink" title="Method3: load with Leaflet AJAX"></a>Method3: load with Leaflet AJAX</h3><p>I tried, it does not work for now!</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> geojsonLayer = <span class="keyword">new</span> L.GeoJSON.AJAX(<span class="string">"geojson.json"</span>);</span><br></pre></td></tr></table></figure><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p><a href="https://medium.com/@maptastik/loading-external-geojson-a-nother-way-to-do-it-with-jquery-c72ae3b41c01" target="_blank" rel="noopener">Loading External GeoJSON: A(nother) Way to Do It with jQuery</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> web mapping </tag>
</tags>
</entry>
<entry>
<title>Install Geopandas</title>
<link href="/posts/18707/"/>
<content type="html"><![CDATA[<p><code>GeoPandas</code> provides extension to <code>pandas</code>. It makes geo-data processing and geo-visualization much easier. <code>geojson</code> can be parsed and visualized easily.</p><hr><h3 id="Installation"><a href="#Installation" class="headerlink" title="Installation"></a>Installation</h3><p>However, installing <code>GeoPandas</code> caused a lot of problems. Errors as below appeared frequently. </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Command "python setup.py egg_info" failed with error code 1</span><br></pre></td></tr></table></figure><p>I downloaded <code>geojson</code> and its dependencies’ <code>wheel</code> files (<a href="https://www.lfd.uci.edu/~gohlke/pythonlibs/" target="_blank" rel="noopener">download website</a>). Then installed them manually. The files are <code>OSGeo4W, GDAL, Fiona, pyproj, rtree, shapely and geopandas</code> packages.</p><hr><h3 id="Applications"><a href="#Applications" class="headerlink" title="Applications"></a>Applications</h3><p><code>GeoPandas</code> tutorial: <a href="https://www.twilio.com/blog/2017/08/geospatial-analysis-python-geojson-geopandas.html" target="_blank" rel="noopener">https://www.twilio.com/blog/2017/08/geospatial-analysis-python-geojson-geopandas.html</a></p><p><code>GeoPandas</code> gallery: <a href="http://geopandas.org/gallery/index.html" target="_blank" rel="noopener">http://geopandas.org/gallery/index.html</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>Multiple Linear Regression in R</title>
<link href="/posts/31988/"/>
<content type="html"><![CDATA[<h3 id="Math-model"><a href="#Math-model" class="headerlink" title="Math model"></a>Math model</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Y = a1*X1 + a2*X2 + a3*X3 + ... + an*Xn + b</span><br></pre></td></tr></table></figure><p><code>Y</code> and <code>X</code> are known, <code>a</code> and <code>b</code> will be calculated.</p><hr><h3 id="Data-processing"><a href="#Data-processing" class="headerlink" title="Data processing"></a>Data processing</h3><p>Input <code>Y</code> and <code>X</code> to Rstudio.</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># build multiple regression model</span></span><br><span class="line"><span class="keyword">library</span>(<span class="string">"readxl"</span>, lib.loc=<span class="string">"~/R/win-library/3.5"</span>)</span><br><span class="line">df = read_excel(<span class="string">"yourdata.xlsx"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># explore the data structure</span></span><br><span class="line">str(df)</span><br><span class="line">summary(df$GRDP)</span><br><span class="line">hist(df$GRDP)</span><br></pre></td></tr></table></figure><p>Build the model. <code>lm()</code> take thes the known <code>Y</code> and <code>X</code> as arguments, <code>lm(Y ~ X1 + X2 + ... + Xn)</code>.</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">model = lm(GRDP~LANDU_21+LANDU_22+LANDU_23+LANDU_24, data = df)</span><br><span class="line"></span><br><span class="line"><span class="comment"># check the model</span></span><br><span class="line">summary(model)</span><br></pre></td></tr></table></figure><p>Model application.</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">test = read_excel(<span class="string">"your_test_data.xlsx"</span>)</span><br><span class="line">pred = predict(model, newdata = test)</span><br><span class="line">pred</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> R </category>
</categories>
<tags>
<tag> model </tag>
</tags>
</entry>
<entry>
<title>Spatial polygon area calculation by another polygon layer</title>
<link href="/posts/30557/"/>
<content type="html"><![CDATA[<h3 id="Topic-description"><a href="#Topic-description" class="headerlink" title="Topic description"></a>Topic description</h3><p>I have two polygon layers in the same region: 1) data layer, the area of the polygons needs to be calculated, 2) reference layer, the polygons in this layer will be used as statistic units.</p><p>Data layer: landuse data in Jiangsu.</p><p><img src="/images/areaStatistics/landuse.png" alt="Landuse in Jiangsu 2010"></p><p>Reference layer: administrative boundary in Jiangsu.</p><p><img src="/images/areaStatistics/boundary.png" alt="Administrative boundaries in Jiangsu 2010"></p><p>I would like to know the each landuse type area in each county.</p><h3 id="Data-processing"><a href="#Data-processing" class="headerlink" title="Data processing"></a>Data processing</h3><p><a href="http://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/tabulate-area.htm" target="_blank" rel="noopener"><code>Tabulate Area</code></a> is a tool provided by <code>ArcGIS</code>, this tool calculates cross-tabulated areas between two datasets and outputs a table.</p><p><img src="/images/areaStatistics/para.png" alt="Tabulate Area"></p><p>After calculating, we can get a table of land use area statistic in each county.</p>]]></content>
<categories>
<category> ArcGIS </category>
</categories>
</entry>
<entry>
<title>How to Draw Interactive Steamgraph in R</title>
<link href="/posts/17204/"/>
<content type="html"><![CDATA[<p>Streamgraph is a type of stacked area graph which is displaced around a central axis, resulting in a flowing, organic shape. Streamgraphs and their use were popularized by Lee Byron in a February 2008 New York Times article on movie box office revenues.</p><h3 id="Data"><a href="#Data" class="headerlink" title="Data"></a>Data</h3><p>Here we have census data about GDP values in some counties in southeast China.</p><p><img src="\images\streamgraph\data.png" alt="Census GDP data"></p><hr><h3 id="Convert-to-1-dimensional-table"><a href="#Convert-to-1-dimensional-table" class="headerlink" title="Convert to 1-dimensional table"></a>Convert to 1-dimensional table</h3><p>We have a 2-dimensional table above. Before drawing streamgraph, we need to convert 2-dimensional table to 1-dimensional table. We can use <code>Microsoft Excel</code> to convert it.</p><p>Press <code>Alt + D + P</code>, then we have the widget.</p><p><img src="\images\streamgraph\step1.png" alt="Step1"></p><p><img src="\images\streamgraph\step2.png" alt="Step2"></p><p>Select the data need to be ploted.<br><img src="\images\streamgraph\step3.png" alt="Step3"></p><p>Hit complate.<br><img src="\images\streamgraph\step1.png" alt="Step1"></p><p>Now we have a new table, <code>double click</code> the bottom right sum value. Then we will have a 1-dimensional table.</p><p><img src="\images\streamgraph\data2.png" alt="1-dimensional table"></p><hr><h3 id="Draw-the-graph-in-Rstudio"><a href="#Draw-the-graph-in-Rstudio" class="headerlink" title="Draw the graph in Rstudio"></a>Draw the graph in Rstudio</h3><p>Because <code>read_csv</code> can not read Chinese characters correctly, we use <code>read_excel</code> to input the data.</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">library</span>(readxl)</span><br><span class="line">df = read_excel(<span class="string">"your_file_path/one_dimension.xlsx"</span>)</span><br></pre></td></tr></table></figure><p>Install <code>streamgraph</code> package from github.</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">devtools::install_github(<span class="string">"hrbrmstr/streamgraph"</span>)</span><br></pre></td></tr></table></figure><p>Draw the graph;</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">streamgraph(df, key=<span class="string">"name"</span>, value=<span class="string">"gdp"</span>, date=<span class="string">"year"</span> , offset=<span class="string">"zero"</span>) %>%</span><br><span class="line"> sg_fill_tableau() %>% <span class="comment"># set color</span></span><br><span class="line"> sg_axis_x(tick_interval = <span class="number">1</span>) %>% <span class="comment"># set x-axis interval as one year</span></span><br><span class="line"> sg_legend(<span class="literal">TRUE</span>, <span class="string">"Name: "</span>) <span class="comment"># add legend</span></span><br></pre></td></tr></table></figure><p><img src="\images\streamgraph\graph1.png" alt="Streamgraph of Jiangsu GDP"></p><p><img src="\images\streamgraph\graph2.png" alt="Streamgraph of Jiangsu GDP: user select one county"></p><hr><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p><a href="https://github.com/hrbrmstr/streamgraph" target="_blank" rel="noopener">GitHub | hrbrmstr | streamgraph</a></p><p><a href="https://www.r-graph-gallery.com/155-interactive-streamgraph-change-offset/" target="_blank" rel="noopener">Art from data | #155 INTERACTIVE STREAMGRAPH | CHANGE OFFSET</a></p>]]></content>
<categories>
<category> R </category>
</categories>
<tags>
<tag> data visualization </tag>
</tags>
</entry>
<entry>
<title>Extract Column from Tables</title>
<link href="/posts/39979/"/>
<content type="html"><![CDATA[<h3 id="Problem-description"><a href="#Problem-description" class="headerlink" title="Problem description"></a>Problem description</h3><p>I have some census data, which are 20 excel files for 20 year respectively (1980 - 1999). Each of the files contains county names and corresponding census data, e.g., GRDP, population, education.</p><p>The aim is to get GDP data from each year, and save them in one excel file.</p><p>I used Python 3.7 pandas packge to solve this problem.</p><hr><h3 id="Code"><a href="#Code" class="headerlink" title="Code"></a>Code</h3><p><strong>Function 1: get GPD column from a excel file</strong></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># get GRDP and name from a certain year</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getGRDP</span><span class="params">(year)</span>:</span></span><br><span class="line"> <span class="comment"># read data from excel</span></span><br><span class="line"> file_name = <span class="string">"Jiangsu_"</span> + str(year) + <span class="string">".xls"</span></span><br><span class="line"> data = pd.read_excel(file_name)</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># form column names</span></span><br><span class="line"> name = <span class="string">"_"</span> + str(year) + <span class="string">"$.name"</span></span><br><span class="line"> gdp = <span class="string">"_"</span> + str(year) + <span class="string">"$.GRDP"</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># get name and GRDP column</span></span><br><span class="line"> data = data.loc[:, [name, gdp]][:<span class="number">60</span>]</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> data</span><br></pre></td></tr></table></figure><p><strong>Function 2: join a column to an existing table</strong></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># join a table to the table of 1999</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">join2_table</span><span class="params">(year, result)</span>:</span> </span><br><span class="line"> </span><br><span class="line"> targetGDP = getGRDP(year)</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># get index name</span></span><br><span class="line"> index_name = <span class="string">"_"</span>+ str(year) + <span class="string">"$.name"</span></span><br><span class="line"> </span><br><span class="line"> result = result.join(targetGDP.set_index(index_name))</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> result</span><br></pre></td></tr></table></figure><p><strong>Global variable</strong></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># initialize</span></span><br><span class="line">result = getGRDP(<span class="number">1999</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># set key for the table</span></span><br><span class="line">result.set_index(<span class="string">"_1999$.name"</span>)</span><br></pre></td></tr></table></figure><p><strong>Add all the GPD column to the global variable</strong></p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1998</span>, <span class="number">1980</span>, <span class="number">-1</span>):</span><br><span class="line"> data = getGRDP(i)</span><br><span class="line"> index_name = <span class="string">'_'</span> + str(i) + <span class="string">"$.name"</span></span><br><span class="line"> result = result.join(data.set_index(index_name))</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Python </category>
</categories>
<tags>
<tag> pandas </tag>
</tags>
</entry>
<entry>
<title>Leaflet Overlay OnEachFeature</title>
<link href="/posts/38366/"/>
<content type="html"><![CDATA[<p>When you are displaying <code>geojson</code> with <code>leaflet</code> overlays, <code>onEachFeature</code> is a function will be applied on each feature, e.g. a point or a polygon in a <code>features</code> collection.</p><p>I overwrote the <code>onEachFeature</code> with a cusmerized function, when this funtion is running, it get the information from current display/undisplay layer, and changes the global variable <code>gDisplayLayersInfo</code> accordingly.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">overlayOnEachFeature</span>(<span class="params">feature, layer</span>)</span>{</span><br><span class="line"> layer.on({</span><br><span class="line"> <span class="comment">// when a overlay is on display</span></span><br><span class="line"> add: <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="comment">// get information from the current layer</span></span><br><span class="line"> <span class="keyword">var</span> layerInfo = getLayerInfo(layer);</span><br><span class="line"> <span class="comment">// add the information to a global variable</span></span><br><span class="line"> gDisplayLayersInfo.push(<span class="string">'<br>'</span> + layerInfo);</span><br><span class="line"> },</span><br><span class="line"> remove: <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> layerInfo = getLayerInfo(layer);</span><br><span class="line"> <span class="keyword">var</span> listElement = <span class="string">'<br>'</span> + layerInfo;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> l <span class="keyword">in</span> gDisplayLayersInfo){</span><br><span class="line"> <span class="comment">// if the information is in the global variable, delete the information</span></span><br><span class="line"> <span class="keyword">if</span> (listElement === gDisplayLayersInfo[l]){</span><br><span class="line"> gDisplayLayersInfo.splice(l,<span class="number">1</span>);</span><br><span class="line"> };</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Apply the cusmerized <code>onEachFeature</code> to the layer which will be added:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//add geojson polygon to the map</span></span><br><span class="line"><span class="keyword">var</span> transportationLayer = <span class="keyword">new</span> L.geoJSON(gTransportation, {</span><br><span class="line"> style: transportationStyle,</span><br><span class="line"> <span class="comment">// overwrite the function</span></span><br><span class="line"> onEachFeature: overlayOnEachFeature</span><br><span class="line">});</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> JavaScript </category>
</categories>
</entry>
<entry>
<title>Control Leadlet Overlays</title>
<link href="/posts/27622/"/>
<content type="html"><![CDATA[<p>Adding several lays to leaflet and display the basic information of the layers on the map is very useful. <code>Leaflet</code> provaided lots handy APIs. </p><p>This article talks about how to update the layers’ information according to users selection.</p><p><img src="\images\leaflet\overlays.png" alt="Leaflet Overlays"></p><h3 id="Add-layers-to-leaflet"><a href="#Add-layers-to-leaflet" class="headerlink" title="Add layers to leaflet"></a>Add layers to leaflet</h3><p>Base layer:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// OSM map</span></span><br><span class="line"><span class="keyword">var</span> OpenStreetMap = L.tileLayer(<span class="string">'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span>, {</span><br><span class="line"> attribution: <span class="string">'&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"><span class="comment">// Mapbox map</span></span><br><span class="line"><span class="keyword">var</span> Mapbox_light = L.tileLayer(<span class="string">'https://api.mapbox.com/styles/v1/cherylzuo/cji2tjfdj10032sp4xfjd7nvp/tiles/256/{z}/{x}/{y}?access_token=pk.yourowntoken'</span>, {</span><br><span class="line"> attribution: <span class="string">'&copy; <a href="https://www.mapbox.com/">Mapbox</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> baseLayers = {</span><br><span class="line"><span class="string">"Open Street Map"</span>: OpenStreetMap,</span><br><span class="line"><span class="string">"Light Map"</span>: Mapbox_light</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p>In this example, Geojson is added as overlays (the geojson used in this case is polygons).</p><p>Overlay styles:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> transportationStyle = {</span><br><span class="line"> <span class="string">"color"</span>: <span class="string">"#2340b9"</span>,</span><br><span class="line"> <span class="string">"weight"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="string">"opacity"</span>: <span class="number">0.01</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> nature_resourceStyle = {</span><br><span class="line"> <span class="string">"color"</span>: <span class="string">"#60ee4c"</span>,</span><br><span class="line"> <span class="string">"weight"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="string">"opacity"</span>: <span class="number">0.5</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p>Geojson layers:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//add geojson polygon to the map</span></span><br><span class="line"><span class="keyword">var</span> transportation = <span class="keyword">new</span> L.geoJSON(transportation, {</span><br><span class="line"> style: transportationStyle,</span><br><span class="line"><span class="comment">// onEachFeature: layersOnEachFeature</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">//add geojson polygon to the map</span></span><br><span class="line"><span class="keyword">var</span> nature = <span class="keyword">new</span> L.geoJSON(nature_resources, {</span><br><span class="line"> style: nature_resourceStyle</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> overlays_geojson = {</span><br><span class="line"> <span class="string">"Transportation"</span>: transportation,</span><br><span class="line"><span class="string">"Nature resources"</span>: nature</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p>Add baselays and overlays to <code>map</code>:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// add layer control to the map, overlays invisible by default</span></span><br><span class="line">L.control.layers(baseLayers,overlays_geojson).addTo(map);</span><br></pre></td></tr></table></figure></p><h3 id="Add-info-box"><a href="#Add-info-box" class="headerlink" title="Add info box"></a>Add info box</h3><p>When users click on overlays, the corresponding information will appear/disappear on the webpage.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> info = L.control();</span><br><span class="line"></span><br><span class="line">info.onAdd = <span class="function"><span class="keyword">function</span> (<span class="params">map</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>._div = L.DomUtil.create(<span class="string">'div'</span>, <span class="string">'info'</span>); <span class="comment">// create a div with a class "info"</span></span><br><span class="line"> <span class="keyword">this</span>.update();</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._div;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// method that we will use to update the control based on feature properties pacssed</span></span><br><span class="line">info.update = <span class="function"><span class="keyword">function</span> (<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>._div.innerHTML = <span class="string">'<h4>Dataset Information</h4>'</span> + (props ? props : <span class="string">'Choose a category'</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">info.addTo(map);</span><br></pre></td></tr></table></figure><h3 id="Custermize-info-box"><a href="#Custermize-info-box" class="headerlink" title="Custermize info box"></a>Custermize info box</h3><p>When users click the overlay button, we need to know which layer(s) is checked. We need to add listeners on <code>overlayadd</code> and <code>overlayremove</code>. By comparing the added/removed layers with the overlay elements, we can know which layer is clicked.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// list of on display overlays</span></span><br><span class="line"><span class="keyword">var</span> layerDisplay = [];</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">map.on(<span class="string">"overlayadd overlayremove"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">event</span>) </span>{</span><br><span class="line"><span class="keyword">var</span> layer = event.layer;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// get the information from all overlays</span></span><br><span class="line"> <span class="keyword">var</span> allLayers = <span class="built_in">Object</span>.values(overlays_geojson);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (event.type == <span class="string">"overlayadd"</span>){</span><br><span class="line"></span><br><span class="line"><span class="comment">// when a layer is added, push the layer information into the list</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> l <span class="keyword">in</span> allLayers){</span><br><span class="line"> <span class="keyword">if</span> (layer === allLayers[l]){</span><br><span class="line"> layerDisplay.push(layer);</span><br><span class="line">};</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">} <span class="keyword">else</span> <span class="keyword">if</span>(event.type == <span class="string">"overlayremove"</span>){</span><br><span class="line"></span><br><span class="line"> <span class="comment">// when a layer is removed, pop the layer information out of the list</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> l <span class="keyword">in</span> layerDisplay){</span><br><span class="line"> <span class="keyword">if</span> (layer === layerDisplay[l]){</span><br><span class="line"> layerDisplay.splice(l,<span class="number">1</span>);</span><br><span class="line"> };</span><br><span class="line"> };</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// if no overlays, display default info</span></span><br><span class="line"><span class="keyword">if</span> (layerDisplay.length == <span class="number">0</span>){</span><br><span class="line"> info.update();</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> <span class="comment">// overlay info box</span></span><br><span class="line"> <span class="keyword">var</span> data_info = <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Tget the information from layerDisplay and send it to update</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">var</span> l <span class="keyword">in</span> layerDisplay){</span><br><span class="line"><span class="keyword">var</span> tmplayer = layerDisplay[l]._layers;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i <span class="keyword">in</span> tmplayer){</span><br><span class="line"> <span class="keyword">var</span> properties = tmplayer[i].feature.properties;</span><br><span class="line"> data_info += properties.title + <span class="string">' '</span> + properties.year + <span class="string">'<br\>'</span>;</span><br><span class="line">}</span><br><span class="line">data_info += <span class="string">'<br\>'</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">info.update(data_info);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p><a href="https://www.e-education.psu.edu/geog585/node/769" target="_blank" rel="noopener">Walkthrough: Adding interactive GeoJSON layers in Leaflet</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> listener </tag>
</tags>
</entry>
<entry>
<title>ArcGIS_admin Python Module is Online</title>
<link href="/posts/14057/"/>
<content type="html"><![CDATA[<p>When I was working in Esri Deutshcland in November and December 2017 as a working student, my job is scripting for ArcGIS Pro User Management.</p><p>Before I got the job, I was temporarily living in Frankfurt am Main. While Esri Deutshcland located in a small village close to Munich, it takes quite a while to go from Munich to there. Although the interview was scheduled at 1 pm, I needed to leave Munich at 8 am. The earliest ICE (German high speed train) from Frankfurt am Main to Munich would arrive in Munich at 9 am. The only option left was over-night bus.</p><p>I quiet enjoyed the work in Esri Deutshcland. The module is used for ArcGIS user management, to retrieve users and their items, licensing and deleting users. It favors the administrators in an organization. </p><p>The Python module address: <a href="http://www.arcgis.com/home/item.html?id=0e590693631c47bbb7e0d00feac14f2c#overview" target="_blank" rel="noopener">http://www.arcgis.com/home/item.html?id=0e590693631c47bbb7e0d00feac14f2c#overview</a><br>The blog address: <a href="https://gis-iq.esri.de/lizenzzuweisung-von-arcgis-pro-und-loeschen-inaktiver-nutzer-mit-der-arcgis-api-for-python/" target="_blank" rel="noopener">https://gis-iq.esri.de/lizenzzuweisung-von-arcgis-pro-und-loeschen-inaktiver-nutzer-mit-der-arcgis-api-for-python/</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
<tags>
<tag> ArcGIS Pro </tag>
<tag> user management </tag>
</tags>
</entry>
<entry>
<title>Shapefile Import Failed</title>
<link href="/posts/4483/"/>
<content type="html"><![CDATA[<p>Using <code>PostGIS Shapefile Import/Export Manager</code> to import <code>shapefile</code> into database, but it failed.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">==============================</span><br><span class="line">Shapefile type: Point</span><br><span class="line">PostGIS type: POINT[2]</span><br><span class="line">Failed in pgui_exec(): ERROR: schema "public" does not exist</span><br><span class="line">LINE 4: CREATE TABLE "public"."railwayStation" (gid serial,</span><br><span class="line"> ^</span><br><span class="line"></span><br><span class="line">Shapefile import failed.</span><br></pre></td></tr></table></figure><p>Because the database is not a geo database.</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> EXTENSION postgis;</span><br></pre></td></tr></table></figure><p>If get the ERROR:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ERROR: no schema has been selected to <span class="keyword">create</span> <span class="keyword">in</span></span><br></pre></td></tr></table></figure><p>excute:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">SCHEMA</span> <span class="keyword">public</span>;</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Database </category>
</categories>
</entry>
<entry>
<title>Drop All Tables in PostgreSQL</title>
<link href="/posts/35459/"/>
<content type="html"><![CDATA[<p>Drop all tables in a database, but keep the database.</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GRANT</span> ALL <span class="keyword">ON</span> <span class="keyword">SCHEMA</span> <span class="keyword">public</span> <span class="keyword">TO</span> postgres;</span><br><span class="line"><span class="keyword">GRANT</span> ALL <span class="keyword">ON</span> <span class="keyword">SCHEMA</span> <span class="keyword">public</span> <span class="keyword">TO</span> <span class="keyword">public</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">SCHEMA</span> <span class="keyword">public</span> <span class="keyword">CASCADE</span>;</span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">SCHEMA</span> <span class="keyword">public</span>;</span><br></pre></td></tr></table></figure><p>Reference: <a href="https://stackoverflow.com/questions/3327312/drop-all-tables-in-postgresql" target="_blank" rel="noopener">stakoverflow | Drop all tables in PostgreSQL?</a></p>]]></content>
<categories>
<category> Database </category>
</categories>
</entry>
<entry>
<title>An Investigation of Visual Analytics Maps</title>
<link href="/posts/3493/"/>
<content type="html"><![CDATA[<p>This is an investigation related to econimic geography visual analytics.</p><a id="more"></a><hr><h3 id="Labs-and-researchers"><a href="#Labs-and-researchers" class="headerlink" title="Labs and researchers"></a>Labs and researchers</h3><h4 id="Funded-projects"><a href="#Funded-projects" class="headerlink" title="Funded projects"></a>Funded projects</h4><p><a href="http://geoanalytics.net/and/projects.html" target="_blank" rel="noopener">link</a></p><h4 id="MIT-senseable-lab"><a href="#MIT-senseable-lab" class="headerlink" title="MIT senseable lab."></a>MIT senseable lab.</h4><p>Urban imagination and social innovation through design & science. <a href="http://senseable.mit.edu/" target="_blank" rel="noopener">MIT senseable lab.</a></p><h4 id="GeoVISTA-Center"><a href="#GeoVISTA-Center" class="headerlink" title="GeoVISTA Center"></a>GeoVISTA Center</h4><p>As diverse scientific and societal issues generate growing volumes of geospatial data, demand for technologies to facilitate effective use of these data also grows. Critical issues include: assessing terrorist threats, understanding health-environment interactions, planning for dramatic changes in regional demographics, and managing environmental risk.</p><p><a href="https://www.geovista.psu.edu/" target="_blank" rel="noopener">The GeoVISTA Center</a> is working to address the array of research challenges and opportunities posed in developing useful and usable technologies to take advantage of a wealth of geospatial data. </p><h4 id="Beijing-City-Lab"><a href="#Beijing-City-Lab" class="headerlink" title="Beijing City Lab"></a>Beijing City Lab</h4><p>The Beijing City Lab <a href="https://www.beijingcitylab.com/" target="_blank" rel="noopener">(BCL)</a> is a research community, dedicated to (but not limited to) studying China’s capital Beijing. The Lab focuses on employing interdisciplinary methods to quantify urban dynamics, generating new insights for urban planning and governance, and ultimately producing the science of cities required for sustainable urban development. The lab’s current mix of planners, architects, geographers, economists, and policy analysts lends unique research strength.</p><p><a href="https://urbanindex.jimdo.com/" target="_blank" rel="noopener">City monitoring with big data</a></p><h4 id="BIGSCity"><a href="#BIGSCity" class="headerlink" title="BIGSCity"></a>BIGSCity</h4><p>The Beihang Interest Group on Smart City <a href="https://www.bigscity.com/" target="_blank" rel="noopener">(BIGSCity)</a> is a research group in Beihang University. BIGSCity aims to study data-driven science and technologies of making cities more intelligence and comfortable. The research interests of BIGSCity include urban computing, spatio-temporal data mining, interpretable machine learning, and data visualization. BIGSCity has published more than 30 paper in prestigious conferences and journals in data mining, artificial intelligence and network communications. The technologies developed by BIGSCity have been applied in many real-world applications such as urban planning, intelligent transportation and health services. Tens of millions of populations living in Beijing, Tianjin, Shenzhen, Wuxi, and Chengdu were benefited from these technologies.</p><h4 id="300-000-Km-s-Firm"><a href="#300-000-Km-s-Firm" class="headerlink" title="300.000 Km/s (Firm)"></a>300.000 Km/s (Firm)</h4><p><a href="http://300000kms.net/" target="_blank" rel="noopener">300.000 Km/s</a> is a professional firm of architects, urban planners and engineers that provides design, data analysis and consulting services for cities.</p><h4 id="Department-of-Land-Economy-Cambridge"><a href="#Department-of-Land-Economy-Cambridge" class="headerlink" title="Department of Land Economy, Cambridge"></a>Department of Land Economy, Cambridge</h4><p>A project named, <a href="https://www.landecon.cam.ac.uk/research/research-centres/lisa/research#four" target="_blank" rel="noopener">From Big Data Sets to Collective Human Behavior Patterns and Urban Spatial Structure</a>. </p><h4 id="Oliver-O’Brien"><a href="#Oliver-O’Brien" class="headerlink" title="Oliver O’Brien"></a>Oliver O’Brien</h4><p><a href="http://oobrien.com/" target="_blank" rel="noopener">Oliver O’Brien</a>, a Senior Research Associate at University College London (UCL), joining the university in 2008 and initially and currently based at the Department of Geography, in the Geospatial Analytics and Computing Research Group (GSAC) and forming part of the ESRC Consumer Data Research Centre (CDRC). Prior to joining UCL I worked as a financial software developer in the City, and then studied an MSc in GIS at City University London in 2007.</p><h4 id="sunsp-net"><a href="#sunsp-net" class="headerlink" title="sunsp.net"></a>sunsp.net</h4><p><a href="http://sunsp.net/index.html" target="_blank" rel="noopener">Shipeng Sun</a>, he is an assistant professor in the department of geography at Hunter College-CUNY. I teach geographic information science/geoinformatics related courses and also develop and apply spatial analysis and modeling techniques to explore our networked world.</p><p><a href="http://sunsp.net/demo/GeogTreeMaps/" target="_blank" rel="noopener">A visualization of Nitrogen</a></p><p><img src="\images\platforms\nitrogen.png" alt="Global Excess Nitrogen"></p><h4 id="PEI-Tao-裴韬"><a href="#PEI-Tao-裴韬" class="headerlink" title="PEI, Tao (裴韬)"></a>PEI, Tao (裴韬)</h4><p><a href="http://sourcedb.igsnrr.cas.cn/zw/zjrck/qcqn/200906/t20090626_1842388.html" target="_blank" rel="noopener">裴韬</a>, 任中国科学院地理科学与资源研究所研究员、博生生导师,资源与环境信息系统国家重点实验室副主任,国家杰出青年基金获得者(2015)。 长期从事时空数据挖掘、空间统计等方面的研究,已在国内外发表论文70余篇,其中SCI论文30余篇,合作出版专著3部。担任《地球信息科学》、《计算机科学与应用》等杂志编委。</p><hr><h3 id="Innovative-visusalizations-techniques"><a href="#Innovative-visusalizations-techniques" class="headerlink" title="Innovative visusalizations techniques"></a>Innovative visusalizations techniques</h3><h4 id="Bubble-Sets"><a href="#Bubble-Sets" class="headerlink" title="Bubble Sets"></a>Bubble Sets</h4><p><a href="https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=5290706&tag=1" target="_blank" rel="noopener">Bubble Sets</a>: Revealing Set Relations with Isocontours over Existing Visualizations</p><p><img src="\images\platforms\bubble.png" alt="Bubble sets"></p><hr><h4 id="Line-sets"><a href="#Line-sets" class="headerlink" title="Line sets"></a>Line sets</h4><p>Design Study of <a href="https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=6064991" target="_blank" rel="noopener">LineSets</a>, a Novel Set Visualization Technique</p><p><img src="\images\platforms\line.png" alt="Line sets"></p><hr><h3 id="Visualization-Applications"><a href="#Visualization-Applications" class="headerlink" title="Visualization Applications"></a>Visualization Applications</h3><h4 id="LIVE-Singapore"><a href="#LIVE-Singapore" class="headerlink" title="LIVE Singapore!"></a>LIVE Singapore!</h4><p><a href="http://senseable.mit.edu/livesingapore/index.html" target="_blank" rel="noopener">LIVE Singapore!</a> provides people with access to a range of useful real-time information about their city by developing an open platform for the collection, elaboration and distribution of real-time data that reflect urban activity. Giving people visual and tangible access to real-time information about their city enables them to take their decisions more in sync with their environment, with what is actually happening around them.</p><p><img src="\images\platforms\singapore.jpg" alt="Live Singapore"></p><p>The LIVE Singapore! 2.0, <a href="http://datacollider.io/" target="_blank" rel="noopener">DATACOLLIDER</a>.</p><p><a href="http://eoe.airscapes.io/front.html" target="_blank" rel="noopener">Airspaces Singapore</a>: The primary aim of this initiative was to conduct an exposure study. Another objective was to demonstrate the collection, aggregation and storage of air quality and meteorological data from the network of moving sensors, using an appropriate architecture for this purpose. A third technical challenge was to demonstrate the display of data collected by the monitoring network on a web application in real-time. </p><p><img src="\images\platforms\airspace.PNG" alt="Airspaces Singapore"></p><hr><h4 id="Regional-eXplorer"><a href="#Regional-eXplorer" class="headerlink" title="Regional eXplorer"></a>Regional eXplorer</h4><p>The Organisation for Economic Co-operation and Development <a href="http://www.oecd.org" target="_blank" rel="noopener">(OECD)</a></p><p>The mission of the Organisation for Economic Co-operation and Development (OECD) is to promote policies that will improve the economic and social well-being of people around the world. A visual <a href="http://stats.oecd.org/OECDregionalstatistics/#story=0" target="_blank" rel="noopener">application</a> is made to explore the<br>population density in many regions. </p><p><img src="\images\platforms\popu.png" alt="Population density Severity"></p><hr><h4 id="Innovative-initiatives-in-Barcelona"><a href="#Innovative-initiatives-in-Barcelona" class="headerlink" title="Innovative initiatives in Barcelona"></a>Innovative initiatives in Barcelona</h4><p>Innovation occurs in education, civic organization and economy as the result of multiple social, financial and urban factors. This <a href="http://innovation.300000kms.net/" target="_blank" rel="noopener">map</a> explores innovative initiatives in Barcelona, where they are located, how they cluster in urban space and which sector of activity they belong to.</p><p><img src="\images\platforms\barcelona.png" alt="Economy in Barcelona"></p><hr><h4 id="eurostat"><a href="#eurostat" class="headerlink" title="eurostat"></a>eurostat</h4><p>The Statistical Atlas is an interactive viewer for statistical and topographical maps. It contains all the maps from Eurostat’s regional yearbook, sorted by publication themes. <a href="http://ec.europa.eu/eurostat/cache/RCI/#?vis=nuts2.economy&lang=en" target="_blank" rel="noopener">map link</a></p><p><img src="\images\platforms\eurostat.png" alt="eurostat"></p><hr><h4 id="National-Bureau-of-Statistics-of-China"><a href="#National-Bureau-of-Statistics-of-China" class="headerlink" title="National Bureau of Statistics of China"></a>National Bureau of Statistics of China</h4><p><a href="http://data.stats.gov.cn/mapdata.htm?cn=E0102" target="_blank" rel="noopener">The visualization</a> of national statistics, which covers national plans, cival life, prices and etc.</p><p><img src="\images\platforms\china.PNG" alt="National statistics"></p><hr><h4 id="Statistics-Bundesamt-des-Deutschland"><a href="#Statistics-Bundesamt-des-Deutschland" class="headerlink" title="Statistics Bundesamt des Deutschland"></a>Statistics Bundesamt des Deutschland</h4><p><a href="https://www.destatis.de/EN/Service/InteractiveVisual/InteractiveVisualised.html" target="_blank" rel="noopener">Visual graphics</a> (more maps are available)</p><p><a href="https://atlas.zensus2011.de/" target="_blank" rel="noopener">The interactive Census Atlas</a> of the statistical offices of the Federation and the Länder presents the 2011 Census results on the basis of a 1-kilometre grid.</p><p><img src="\images\platforms\germany.PNG" alt="Bevölkerung am 09.05.2011 pro km²"></p><hr><h4 id="United-States-Census-Bureau"><a href="#United-States-Census-Bureau" class="headerlink" title="United States Census Bureau"></a>United States Census Bureau</h4><p><a href="https://datamapper.geo.census.gov/map.html" target="_blank" rel="noopener">Census Data Mapper</a></p><p><img src="\images\platforms\usa.PNG" alt="Census data"></p><hr><h4 id="Mapping-the-Spread-of-Drought-Across-the-U-S"><a href="#Mapping-the-Spread-of-Drought-Across-the-U-S" class="headerlink" title="Mapping the Spread of Drought Across the U.S."></a>Mapping the Spread of Drought Across the U.S.</h4><p><a href="https://www.nytimes.com/interactive/2014/upshot/mapping-the-spread-of-drought-across-the-us.html?abt=0002&abg=1" target="_blank" rel="noopener">Maps and charts</a> updated weekly show the latest extent of the drought in the United States.</p><p><img src="\images\platforms\drought.png" alt="Drought Severity"></p><hr><h4 id="Net-lending-borrowing-of-GDP"><a href="#Net-lending-borrowing-of-GDP" class="headerlink" title="Net lending/borrowing (% of GDP)"></a>Net lending/borrowing (% of GDP)</h4><p>The IMF is working to foster global monetary cooperation. Th map provaids API. <a href="http://data.imf.org/?sk=061a17b2-7e6a-4b58-9b17-042af9e59a3d&sId=1390030109571" target="_blank" rel="noopener">Map link</a></p><p><img src="\images\platforms\imf.png" alt="Net Lending/borrowing"></p><hr><h4 id="Nike-runners-route"><a href="#Nike-runners-route" class="headerlink" title="Nike runners route"></a>Nike runners route</h4><p><a href="http://cargocollective.com/coopersmith/WIRED-Joggers-Logged-1" target="_blank" rel="noopener">This project</a> culminated with the author working with WIRED UK to do a full spread visualization, using a new dataset of 10,000 runs throughout London, for their October 2011 issue.</p><p><img src="\images\platforms\nike.png" alt="Joggers in London"></p><hr><h4 id="Facebook-Visualizing-Friendships"><a href="#Facebook-Visualizing-Friendships" class="headerlink" title="Facebook Visualizing Friendships"></a>Facebook Visualizing Friendships</h4><p><a href="https://www.facebook.com/notes/facebook-engineering/visualizing-friendships/469716398919" target="_blank" rel="noopener">Visualizing Friendships</a> presented the locality of friendship. How geography and political borders affected where people lived relative to their friends is the intereting point in this visualization.</p><p><img src="\images\platforms\facebook.jpg" alt="Visualizing Friendships"></p><hr><h4 id="A-Map-of-Olympic-Medals"><a href="#A-Map-of-Olympic-Medals" class="headerlink" title="A Map of Olympic Medals"></a>A Map of Olympic Medals</h4><p><a href="https://archive.nytimes.com/www.nytimes.com/interactive/2008/08/04/sports/olympics/20080804_MEDALCOUNT_MAP.html" target="_blank" rel="noopener">A Map of Olympic Medals</a> is a Cartogram. Circles are sized by the number of medals that countries won in summer Olympic Games. Use the slider to view past Olympics, or click on a country to display a list of its medal winners.</p><p><img src="\images\platforms\medals.png" alt="Olympic medals"></p><hr><h3 id="Tools"><a href="#Tools" class="headerlink" title="Tools"></a>Tools</h3><p><a href="http://echarts.baidu.com/index.html" target="_blank" rel="noopener">ECharts</a></p><p><a href="https://carto.com/" target="_blank" rel="noopener">CARTO</a></p><p><a href="https://leafletjs.com/index.html" target="_blank" rel="noopener">Leaflet</a></p><p><a href="https://www.mapbox.com/" target="_blank" rel="noopener">Mapbox</a></p><p><a href="https://www.anychart.com/" target="_blank" rel="noopener">AnyChart</a></p><p><a href="http://www.chartjs.org/" target="_blank" rel="noopener">Chart.js</a></p><p><a href="https://github.com/d3" target="_blank" rel="noopener">d3.js</a></p><p><a href="https://cesiumjs.org/" target="_blank" rel="noopener">CesiumJS</a></p><p><a href="http://tilemill-project.github.io/tilemill/" target="_blank" rel="noopener">TileMill</a></p><p><a href="https://infogram.com/" target="_blank" rel="noopener">Infogram</a></p><p><a href="https://www.fusioncharts.com/" target="_blank" rel="noopener">FusionCharts</a></p><p><a href="http://dygraphs.com/" target="_blank" rel="noopener">dygraphs</a></p><hr><h3 id="Data-source"><a href="#Data-source" class="headerlink" title="Data source"></a>Data source</h3><p><a href="http://www.webmap.cn/main.do?method=index" target="_blank" rel="noopener">China National Catalogue Service for Geographic informaiton</a></p><p><a href="http://nnu.geodata.cn:8008/" target="_blank" rel="noopener">Yangtze River Delta Data Center</a></p><p><a href="http://www.moojnn.com/data-market/market.html#sourceId=&typeId=&sizeId=&isFree=true&tagId=&industryId=&keyword=&isRecommended=&pageSize=10&pageNumber=1&tType=free" target="_blank" rel="noopener">Moojnn</a></p><p><a href="https://data.europa.eu/euodp/data/" target="_blank" rel="noopener">EU Open Data Portal</a></p><p><a href="https://www.govdata.de/" target="_blank" rel="noopener">Das Datenportal für Deutschland</a></p><p><a href="https://www.data.gov/" target="_blank" rel="noopener">U.S. Government’s open data</a></p><p><a href="https://search.earthdata.nasa.gov/search" target="_blank" rel="noopener">EARTHDATA</a></p><p><a href="https://landscan.ornl.gov/" target="_blank" rel="noopener">LandScan</a></p><p><a href="http://sedac.ciesin.columbia.edu/data/collection/gpw-v3/sets/browse" target="_blank" rel="noopener">Socioeconomic data and application center</a></p><p><a href="https://fred.stlouisfed.org/" target="_blank" rel="noopener">Economic research | Federal reverve bank of St. Louis</a></p><p><a href="http://www.jssb.gov.cn/tjxxgk/tjsj/tjnq/nj2017/index_1508.html" target="_blank" rel="noopener">江苏统计年鉴</a></p><p><a href="http://data.stats.gov.cn/easyquery.htm?cn=E0103" target="_blank" rel="noopener">国家统计局</a></p><p><a href="http://www.most.gov.cn/kjtj/" target="_blank" rel="noopener">中华人民共和国科学技术部</a></p><p><a href="http://www.mohrss.gov.cn/" target="_blank" rel="noopener">中华人民共和国人力资源和社会保障部</a></p><p><a href="http://www.nhfpc.gov.cn/zhuz/xzqq/list.shtml" target="_blank" rel="noopener">中华人民共和国国家卫生健康委员会</a></p><p><a href="https://www.oecd-ilibrary.org/" target="_blank" rel="noopener">OECDiLibrary</a><br>OECD iLibrary is the online library of the Organisation for Economic Cooperation and Development (OECD) featuring its books, papers and statistics and is the gateway to OECD’s analysis and data.</p><p><a href="http://databank.worldbank.org/data/home.aspx" target="_blank" rel="noopener">DataBank</a><br>DataBank is an analysis and visualisation tool that contains collections of time series data on a variety of topics. You can create your own queries; generate tables, charts, and maps; and easily save, embed, and share them.</p><p><a href="http://stat.wto.org/StatisticalProgram/WSDBStatProgramHome.aspx?Language=E" target="_blank" rel="noopener">Time Series</a><br>This site provides a searchable database on international trade in merchandise and commercial services. The data are presented according to the product definitions and regional groupings specified in the technical notes. </p><p><a href="http://www.nationmaster.com/statistics" target="_blank" rel="noopener">NationMaster</a><br>NationMaster is a global team of passionate stat geeks, dedicated to the mission of bringing facts to the world of geopolitics, economics, geography, defence and culture.</p><p><a href="http://data.imf.org/?sk=388DFA60-1D26-4ADE-B505-A05A558D9A42" target="_blank" rel="noopener">International Monetary Fund</a><br>The International Monetary Fund (IMF) is an organization of 189 countries, working to foster global monetary cooperation, secure financial stability, facilitate international trade, promote high employment and sustainable economic growth, and reduce poverty around the world.</p><p><a href="https://data.worldbank.org/indicator" target="_blank" rel="noopener">The world bank</a><br>At the World Bank, the Development Data Group coordinates statistical and data work and maintains a number of macro, financial and sector databases. Working closely with the Bank’s regions and Global Practices, the group is guided by professional standards in the collection, compilation and dissemination of data to ensure that all data users can have confidence in the quality and integrity of the data produced.</p><p><a href="https://www.ipums.org/" target="_blank" rel="noopener">IPUMS</a><br>IPUMS provides census and survey data from around the world integrated across time and space. IPUMS integration and documentation makes it easy to study change, conduct comparative research, merge information across data types, and analyze individuals within family and community context. Data and services available free of charge.</p><p><a href="https://www.icpsr.umich.edu/icpsrweb/ICPSR/" target="_blank" rel="noopener">ICPSR</a><br>CPSR advances and expands social and behavioral research, acting as a global leader in data stewardship and providing rich data resources and responsive educational opportunities for present and future generations.</p>]]></content>
<categories>
<category> Others </category>
</categories>
</entry>
<entry>
<title>A Detailed Introduction of Webmapping with WMS and Leaflet</title>
<link href="/posts/8757/"/>
<content type="html"><![CDATA[<h3 id="Leaflet-and-WMS"><a href="#Leaflet-and-WMS" class="headerlink" title="Leaflet and WMS"></a>Leaflet and WMS</h3><p><code>Web Map Service (WMS)</code> is a way of publishing local geodata as map tiles, but more opetational. It can be published by <code>GeoServer</code> or other softwares e.g. QGIS.<br><code>Leaflet.js</code> is a open source JS library, which is made for interacitve maps. With <code>Mapbox</code>, more maps can be designed, personalised and added to web applications via <code>Leaflet.js</code>.</p><hr><h3 id="Insert-js-libraries"><a href="#Insert-js-libraries" class="headerlink" title="Insert js libraries"></a>Insert js libraries</h3><p>Download the libs in your local folder, and include them in your <code>HTML</code> file.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><!-- Leaflet--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/leaflet.css"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/leaflet.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- GeoCoder--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/Control.OSMGeocoder.css"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/Control.OSMGeocoder.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- Overview--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/overview/MiniMap.css"</span> /></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/overview/MiniMap.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- Location--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/L.Control.Locate.min.css"</span> /></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/L.Control.Locate.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- Mouse position display--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/L.Control.MousePosition.css"</span> /></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/L.Control.MousePosition.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- Navigation Bar--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/NavBar/NavBar.css"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/NavBar/NavBar.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- Font--></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">href</span>=<span class="string">"//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!-- jquery --></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://code.jquery.com/jquery-2.1.1.min.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><hr><h3 id="Diaplay-OSM-as-base-map"><a href="#Diaplay-OSM-as-base-map" class="headerlink" title="Diaplay OSM as base map"></a>Diaplay OSM as base map</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"><span class="comment"><!-- down load Leaflet lib from internet --></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"libs/leaflet.css"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"libs/leaflet.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"map"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="comment">//OSM as base map</span></span></span><br><span class="line"><span class="javascript"><span class="keyword">var</span> OpenStreetMap = L.tileLayer(<span class="string">'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="comment">//map configuration</span></span></span><br><span class="line"><span class="javascript"><span class="keyword">var</span> map = L.map(<span class="string">'map'</span>, {</span></span><br><span class="line"><span class="undefined">layers: [OpenStreetMap], </span></span><br><span class="line"><span class="javascript">center: [<span class="number">31.2</span>, <span class="number">121.4</span>], <span class="comment">// default center coordinate, here is Shanghai</span></span></span><br><span class="line"><span class="javascript">zoom: <span class="number">3</span> <span class="comment">// default zoom level</span></span></span><br><span class="line"><span class="undefined">});</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms_shagnhai.png" alt="Screenshot of OSM base map"></p><hr><h3 id="WMS-Layer"><a href="#WMS-Layer" class="headerlink" title="WMS Layer"></a>WMS Layer</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// add WMS to map</span></span><br><span class="line"><span class="keyword">var</span> wmsLayer = L.tileLayer.wms(<span class="string">'http://localhost:8080/geoserver/first/wms?'</span>, {</span><br><span class="line"> layers: <span class="string">'first:railways_cn'</span>,</span><br><span class="line">}).addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms2.png" alt="Screenshot of WMS Layer"></p><p>WMS is loaded as tailed photos, the default format is <code>.jepg</code>, so that the layer can not have transparent band. The upper layers will cover the base map. Change the tailed photo’s format and set transparency:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wmsLayer = L.tileLayer.wms(<span class="string">'http://localhost:8080/geoserver/first/wms?'</span>, {</span><br><span class="line"> layers: <span class="string">'first:railways_cn'</span>,</span><br><span class="line"> format: <span class="string">'image/png'</span>,</span><br><span class="line"> transparent: <span class="literal">true</span>,</span><br><span class="line">}).addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms3.png" alt="Screenshot of transparent WMS Layer"></p><hr><h3 id="Projection"><a href="#Projection" class="headerlink" title="Projection"></a>Projection</h3><p>Leaflet supports very few coordinate systems: CRS:3857, CRS:3395 and CRS:4326. If your WMS service doesn’t serve images in those coordinate systems, you might need to use Proj4Leaflet to use a different coordinate system in Leaflet.</p><p>Or set the layer’s coordinates in <code>GeoServer</code>.</p><p><img src="\images\wms\wms4.png" alt="Railway WMS Layer"></p><hr><h3 id="Layer-control"><a href="#Layer-control" class="headerlink" title="Layer control"></a>Layer control</h3><h4 id="Base-map"><a href="#Base-map" class="headerlink" title="Base map"></a>Base map</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// base map server url</span></span><br><span class="line"><span class="keyword">var</span> OpenStreetMap = L.tileLayer(<span class="string">'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span>);</span><br><span class="line"><span class="keyword">var</span> WorldImagery = L.tileLayer(<span class="string">'http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//add layer to a attribute</span></span><br><span class="line"><span class="keyword">var</span> baseLayers = {</span><br><span class="line"><span class="string">"Open Street Map"</span>: OpenStreetMap,</span><br><span class="line"><span class="string">"World Imagery"</span>: WorldImagery</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">L.control.layers(baseLayers).addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\basemap.png" alt="Base maps"></p><h4 id="Overlays"><a href="#Overlays" class="headerlink" title="Overlays"></a>Overlays</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// layers from Geoserver (format WMS)</span></span><br><span class="line"><span class="keyword">var</span> points = L.tileLayer.wms(<span class="string">"http://localhost:8080/geoserver/first/wms"</span>, {</span><br><span class="line">layers: <span class="string">'fitst:points_cn'</span>,</span><br><span class="line">format: <span class="string">'image/png'</span>,</span><br><span class="line">transparent: <span class="literal">true</span>,</span><br><span class="line">version: <span class="string">'1.1.0'</span>,</span><br><span class="line">attribution: <span class="string">"myattribution"</span></span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> railways = L.tileLayer.wms(<span class="string">"http://localhost:8080/geoserver/first/wms"</span>, {</span><br><span class="line">layers: <span class="string">'fitst:railways_cn'</span>,</span><br><span class="line">format: <span class="string">'image/png'</span>,</span><br><span class="line">transparent: <span class="literal">true</span>,</span><br><span class="line">version: <span class="string">'1.1.0'</span>,</span><br><span class="line">attribution: <span class="string">"myattribution"</span></span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> buildings = L.tileLayer.wms(<span class="string">"http://localhost:8080/geoserver/first/wms"</span>, {</span><br><span class="line">layers: <span class="string">'fitst:buildings_cn'</span>,</span><br><span class="line">format: <span class="string">'image/png'</span>,</span><br><span class="line">transparent: <span class="literal">true</span>,</span><br><span class="line">version: <span class="string">'1.1.0'</span>,</span><br><span class="line">attribution: <span class="string">"myattribution"</span></span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> landuse = L.tileLayer.wms(<span class="string">"http://localhost:8080/geoserver/first/wms"</span>, {</span><br><span class="line">layers: <span class="string">'fitst:landuse_cn'</span>,</span><br><span class="line">format: <span class="string">'image/png'</span>,</span><br><span class="line">transparent: <span class="literal">true</span>,</span><br><span class="line">version: <span class="string">'1.1.0'</span>,</span><br><span class="line">attribution: <span class="string">"myattribution"</span></span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> boundary = L.tileLayer.wms(<span class="string">"http://localhost:8080/geoserver/first/wms"</span>, {</span><br><span class="line">layers: <span class="string">'fitst:boundary_cn'</span>,</span><br><span class="line">format: <span class="string">'image/png'</span>,</span><br><span class="line">transparent: <span class="literal">true</span>,</span><br><span class="line">version: <span class="string">'1.1.0'</span>,</span><br><span class="line">attribution: <span class="string">"myattribution"</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Group layers</span></span><br><span class="line"><span class="keyword">var</span> overlays = {</span><br><span class="line"><span class="string">"points"</span>: points,</span><br><span class="line"><span class="string">"railways"</span>: railways,</span><br><span class="line"><span class="string">"buildings"</span>: buildings,</span><br><span class="line"><span class="string">"landuse"</span>: landuse,</span><br><span class="line"><span class="string">"boundary"</span>: boundary,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// add base maps and overlays together to the map</span></span><br><span class="line">L.control.layers(baseLayers,overlays).addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\overlays.png" alt="Layers"></p><hr><h3 id="Widgets"><a href="#Widgets" class="headerlink" title="Widgets"></a>Widgets</h3><h4 id="Search-function"><a href="#Search-function" class="headerlink" title="Search function"></a>Search function</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> osmGeocoder = <span class="keyword">new</span> L.Control.OSMGeocoder();</span><br><span class="line">map.addControl(osmGeocoder);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms_find.png" alt="Search function"></p><h4 id="Overview-Map"><a href="#Overview-Map" class="headerlink" title="Overview Map"></a>Overview Map</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> osm2 = L.tileLayer(<span class="string">'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span>);</span><br><span class="line"><span class="keyword">var</span> miniMap = <span class="keyword">new</span> L.Control.MiniMap(osm2, { <span class="attr">toggleDisplay</span>: <span class="literal">true</span> }).addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms_nav.png" alt="The overview map in the right bottom corner"></p><h4 id="Navigator-bar"><a href="#Navigator-bar" class="headerlink" title="Navigator bar"></a>Navigator bar</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">L.control.navbar({<span class="attr">position</span>: <span class="string">'topleft'</span>}).addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms_navbar.png" alt="Navigator in the left top corner"></p><h4 id="Scale-bar"><a href="#Scale-bar" class="headerlink" title="Scale bar"></a>Scale bar</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">L.control.scale().addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms_scale.png" alt="Scale bar in the left bottom corner"></p><h4 id="Mouse-hover-position"><a href="#Mouse-hover-position" class="headerlink" title="Mouse hover position"></a>Mouse hover position</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">L.control.mousePosition().addTo(map);</span><br></pre></td></tr></table></figure><p><img src="\images\wms\wms_hover.png" alt="Coordinate at right bottom"></p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p><a href="https://leafletjs.com/examples/wms/wms.html" target="_blank" rel="noopener">Leaflet Tutorial</a><br><a href="https://gis.stackexchange.com/questions/143350/how-to-make-transparent-wms-vector-background-in-qgis" target="_blank" rel="noopener">stackoverflow | How to make transparent WMS vector background in QGIS?</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> web mapping </tag>
<tag> Network </tag>
</tags>
</entry>
<entry>
<title>Build up Webmapping Environment on Windows</title>
<link href="/posts/9583/"/>
<content type="html"><![CDATA[<p>This blog is about how to do web mapping with local database and server.</p><p>Tools: </p><ul><li>Java</li><li>Apache Tomcat</li><li>PostgreSQL</li><li>GeoServer</li></ul><hr><h3 id="Install-Java"><a href="#Install-Java" class="headerlink" title="Install Java"></a>Install Java</h3><p>Install <code>jdk-10.0.1_windows-x64_bin.exe</code> and <code>jre-8u171-windows-i586.exe</code></p><p>Set system environment:</p><table><thead><tr><th>Variable</th><th>Value</th></tr></thead><tbody><tr><td>JAVA_HOME</td><td>C:\Program Files (x86)\Java\jdk1.8.0_171</td></tr><tr><td>JAVA_BIN</td><td>%JAVA_HOME%\bin</td></tr></tbody></table><p>Check <code>Java</code> in <code>cmd</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">java -version</span><br><span class="line"></span><br><span class="line">java version <span class="string">"1.8.0_171"</span></span><br><span class="line">Java(TM) SE Runtime Environment (build 1.8.0_171-b11)</span><br><span class="line">Java HotSpot(TM) Client VM (build 25.171-b11, mixed mode)</span><br></pre></td></tr></table></figure><hr><h3 id="Deploy-Apache-Tomcat"><a href="#Deploy-Apache-Tomcat" class="headerlink" title="Deploy Apache Tomcat"></a>Deploy Apache Tomcat</h3><p>Unzip <code>apache-tomcat-9.0.8-windows-x64.zip</code></p><p>Set system environment:</p><table><thead><tr><th>Variable</th><th>Value</th></tr></thead><tbody><tr><td>CATALINA_BASE</td><td>C:\apache-tomcat-9.0.8</td></tr><tr><td>CATALINA_BIN</td><td>C:\apache-tomcat-9.0.8\bin</td></tr><tr><td>CATALINA_HOME</td><td>C:\apache-tomcat-9.0.8</td></tr></tbody></table><p>Add users in <code>C:\apache-tomcat-9.0.8\conf\tomcat-users.xml</code>:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">role</span> <span class="attr">rolename</span>=<span class="string">"manager-gui"</span>/></span> </span><br><span class="line"><span class="tag"><<span class="name">role</span> <span class="attr">rolename</span>=<span class="string">"admin-gui"</span>/></span> </span><br><span class="line"><span class="tag"><<span class="name">user</span> <span class="attr">username</span>=<span class="string">"tomcat"</span> <span class="attr">password</span>=<span class="string">"tomcat"</span> <span class="attr">roles</span>=<span class="string">"manager-gui"</span>/></span></span><br></pre></td></tr></table></figure><p>Chnage Tomcat port in <code>C:\apache-tomcat-9.0.8\conf\server.xml</code> if <code>8080</code> is occupied:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">Connector</span> <span class="attr">port</span>=<span class="string">"8090"</span> <span class="attr">protocol</span>=<span class="string">"HTTP/1.1"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">connectionTimeout</span>=<span class="string">"20000"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">redirectPort</span>=<span class="string">"8443"</span> /></span></span><br></pre></td></tr></table></figure><p>Increase Tomcat file size in <code>C:\apache-tomcat-9.0.8\webapps\manager\WEB-INF\web.xml</code>:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">max-file-size</span>></span>252428800<span class="tag"></<span class="name">max-file-size</span>></span></span><br><span class="line"><span class="tag"><<span class="name">max-request-size</span>></span>252428800<span class="tag"></<span class="name">max-request-size</span>></span></span><br></pre></td></tr></table></figure></p><p>Start server <code>C:\apache-tomcat-9.0.8\bin\service.bat</code></p><p>Close your firewall.</p><p>Open <code>localhost:8090</code> in a browser.</p><p>If Tomcat flashback, check Tomcat in debug mode:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> to\your\tomcat\bin</span><br><span class="line">startup.bat debug</span><br></pre></td></tr></table></figure><h3 id="Publish-local-geodata-as-WMS"><a href="#Publish-local-geodata-as-WMS" class="headerlink" title="Publish local geodata as WMS"></a>Publish local geodata as WMS</h3><p>Install PostgreSQL(Database) and PostGIS(a spatial database extender), and GeoServer.</p><p>Input Geodata (e.g. shape file) to PostgreSQL by PostGIS.</p><p><img src="\images\postgis_ui.png" alt="PostgreSQL web UI"></p><p>Login GeoServer <a href="http://localhost:8080/geoserver" target="_blank" rel="noopener">http://localhost:8080/geoserver</a>, click <code>Stores</code> add data from database, click <code>Layers</code> to publish a layer as <code>WMS</code>, click <code>Layer Groups</code> to organize Layers. Finally, click <code>Layer preview</code> , open layers afrom <code>OpenLayers</code> to preview.</p><p><img src="\images\geoserver_pre.png" alt="GeoServer Layer Preview"></p><h3 id="Publish-website"><a href="#Publish-website" class="headerlink" title="Publish website"></a>Publish website</h3><p>Finish your front-end codes (HTML, CSS, JS), include the <code>WMS</code> in your JS codes. Open a command window on your website folder:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jar -cvf webmapping.war *</span><br></pre></td></tr></table></figure></p><p>Copy <code>.war</code> to Tomcat webapps folder <code>C:\apache-tomcat-9.0.8\webapps</code>. Start Tomcat server, login Tomcat with <code>manager</code> account. Click <code>Manager App</code>, then upload the <code>.war</code> file in the <code>WAR file to deploy</code> part and click deploy.</p><p><img src="\images\tomcat_manager.png" alt="Tomcat Web Application Manager"></p><p>If everything works, click <code>webmapping</code> to open the web application.</p><p><img src="\images\webapp.png" alt="Web App"></p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p><a href="https://www.youtube.com/watch?v=08LS7XZWzPE&t=619s" target="_blank" rel="noopener">YouTube | Web mapping: PostGIS + Geoserver + QGis + Leaflet</a><br><a href="https://gis.stackexchange.com/questions/192548/the-connection-was-reset-deploying-geoserver-war-in-ubuntu" target="_blank" rel="noopener">stackoverflow | The connection was reset deploying geoserver.war in ubuntu</a><br><a href="https://gis.stackexchange.com/questions/204495/not-able-to-deploy-geoserver-war-through-apache-tomcat" target="_blank" rel="noopener">stackoverflow | Not able to deploy geoserver.war through apache tomcat</a></p>]]></content>
<categories>
<category> Network </category>
</categories>
<tags>
<tag> Tomcat </tag>
<tag> PostgreSQL </tag>
<tag> GeoServer </tag>
<tag> Leaflet </tag>
</tags>
</entry>
<entry>
<title>Start a Local Server with Python3</title>
<link href="/posts/50946/"/>
<content type="html"><![CDATA[<p>Python3 changed the <code>SimpleHTTPServer</code>. To use it, see as followed:</p><ol><li><p>Open <code>cmd</code> on the folder you would like to start a server</p></li><li><p>Start a server:</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -m http.server <span class="number">90</span></span><br></pre></td></tr></table></figure></li><li><p>Check your local network address:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">C:\>ipconfig</span><br><span class="line"></span><br><span class="line">Windows IP Configuration</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Wireless LAN adapter Wi-Fi:</span><br><span class="line"></span><br><span class="line"> Media State . . . . . . . . . . . : Media disconnected</span><br><span class="line"> Connection-specific DNS Suffix . : eduroam.mwn.de</span><br><span class="line"></span><br><span class="line">Wireless LAN adapter Local Area Connection* 2:</span><br><span class="line"></span><br><span class="line"> Media State . . . . . . . . . . . : Media disconnected</span><br><span class="line"> Connection-specific DNS Suffix . :</span><br><span class="line"></span><br><span class="line">Ethernet adapter Ethernet 2:</span><br><span class="line"></span><br><span class="line"> Connection-specific DNS Suffix . : tum.de</span><br><span class="line"> Link-local IPv6 Address . . . . . : *****************</span><br><span class="line"> IPv4 Address. . . . . . . . . . . : 10.162.**.***</span><br><span class="line"> Subnet Mask . . . . . . . . . . . : 255.255.255.0</span><br><span class="line"> Default Gateway . . . . . . . . . : 10.162.**.***</span><br></pre></td></tr></table></figure></li><li><p>Open local server<br>Take your IPv4 address, open in your browser:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://10.162.**.***:90/</span><br></pre></td></tr></table></figure></li></ol><p>Reference:<br>[1] <a href="https://stackoverflow.com/questions/4341638/python-m-simplehttpserver-listening-on-0-0-0-08000-but-http-0-0-0-08000-t" target="_blank" rel="noopener">stackoverflow | python -m SimpleHTTPServer - Listening on 0.0.0.0:8000 but http://0.0.0.0:8000/test.html gives “Page Not Found”</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
<tags>
<tag> network </tag>
</tags>
</entry>
<entry>
<title>How to automatically vectorize raster images with Arcgis</title>
<link href="/posts/61525/"/>
<content type="html"><![CDATA[<p>Tool: ArcGIS Pro Desktop 2.1<br>Original data: 9 grayscale images in Shanghai area</p><a id="more"></a><hr><h3 id="Combine-image-parts"><a href="#Combine-image-parts" class="headerlink" title="Combine image parts"></a>Combine image parts</h3><p>Using <code>Mosaic</code> to stich images into onw big image (click to see clearer images).</p><table><thead><tr><th style="text-align:center">Parameters</th><th style="text-align:center">Result</th></tr></thead><tbody><tr><td style="text-align:center"><img src="\images\vectorize\1_imageStiching.png" alt="ArcGIS screenshoot"></td><td style="text-align:center"><img src="\images\vectorize\1_imageStiching_img.png" alt="result image"></td></tr></tbody></table><!-- ![alt-text-1](\images\vectorize\1_imageStiching.png "title-1") ![alt-text-2](\images\vectorize\1_imageStiching_img.png "title-2") --><hr><h3 id="Convert-grayscale-image-to-binary"><a href="#Convert-grayscale-image-to-binary" class="headerlink" title="Convert grayscale image to binary"></a>Convert grayscale image to binary</h3><p>In grayscale image, the value of each pixel can range from e.g. [0-255]. But the bianry image pixel value can be either 0 or 1. </p><p>This step is to set a threshold, which will be used in classify grascale pixel values into 0 or 1. </p><p>The threshhold is vital in the whole processing, e.g. some grascale images can have blurring building edges. This threshold determines the edge shape in vector images. The threshold value can be different in every cases. </p><p><code>Reclassify</code> function is used in this step.</p><table><thead><tr><th style="text-align:center">Parameters</th><th style="text-align:center">Result</th></tr></thead><tbody><tr><td style="text-align:center"><img src="\images\vectorize\2_Reclassification.png" alt="ArcGIS screenshoot"></td><td style="text-align:center"><img src="\images\vectorize\2_Reclassification_img1.png" alt="result image"></td></tr></tbody></table><p><img src="\images\vectorize\2_Reclassification_img2.png" alt="Details"></p><hr><h3 id="Automatic-vectorization"><a href="#Automatic-vectorization" class="headerlink" title="Automatic vectorization"></a>Automatic vectorization</h3><p>Using <code>Raster to Polygon</code> (or <code>Raster to Polyline</code>) to vectorize the binary image. P.S. If the image size is big, this step can take a long time.</p><table><thead><tr><th style="text-align:center">Parameters</th><th style="text-align:center">Result</th></tr></thead><tbody><tr><td style="text-align:center"><img src="\images\vectorize\3_raster2polygon.png" alt="ArcGIS screenshoot"></td><td style="text-align:center"><img src="\images\vectorize\3_raster2polygon_img1.png" alt="result image"></td></tr></tbody></table><p><img src="\images\vectorize\3_raster2polygon_img2.png" alt="Details"></p><p>Here we have the voctor image. But if you check the image closely, you will find some small islands on the image and some jagged edges. In order to remove them, the image needs to be furture processed.</p><hr><h3 id="Projection"><a href="#Projection" class="headerlink" title="Projection"></a>Projection</h3><p>If the image has a <code>Geographic Coordinate System</code>, we need to project it into a <code>Projected Coordinate System</code>.</p><p>Using <code>Project</code> to reprojection the image.</p><table><thead><tr><th style="text-align:center">Parameters</th><th style="text-align:center">Result</th></tr></thead><tbody><tr><td style="text-align:center"><img src="\images\vectorize\4_projection.png" alt="ArcGIS screenshoot"></td><td style="text-align:center"><img src="\images\vectorize\4_projection_result.png" alt="result projection"></td></tr></tbody></table><hr><h3 id="Simplification"><a href="#Simplification" class="headerlink" title="Simplification"></a>Simplification</h3><p>Using <code>Simplify Polygon</code> to remove the small islands and smoothify the edges.</p><table><thead><tr><th style="text-align:center">Parameters</th><th style="text-align:center">Result</th></tr></thead><tbody><tr><td style="text-align:center"><img src="\images\vectorize\5_simplification.png" alt="ArcGIS screenshoot"></td><td style="text-align:center"><img src="\images\vectorize\final.png" alt="result projection"></td></tr></tbody></table><p><img src="\images\vectorize\final_detail.png" alt="Details"></p>]]></content>
<categories>
<category> ArcGIS </category>
</categories>
<tags>
<tag> ArcGIS </tag>
</tags>
</entry>
<entry>
<title>Pandas DataFrame Row Slicing by Value from another Table</title>
<link href="/posts/4477/"/>
<content type="html"><![CDATA[<p>There are <code>field_1</code> in both tables, we want to get rows <code>field_3</code> from <code>table_2</code> if the <code>field_1</code> shows in <code>Table_1</code>.</p><h3 id="Data"><a href="#Data" class="headerlink" title="Data"></a>Data</h3><p>Table_1:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">| field_1 | field_2 |</span><br><span class="line">|---------|:--------|</span><br><span class="line">| 1 | apple |</span><br><span class="line">| 1 | pearl |</span><br><span class="line">| 2 | banana |</span><br><span class="line">| 3 | apple |</span><br><span class="line">| 4 | peach |</span><br></pre></td></tr></table></figure><p>Table_2:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">| field_1 | field_3 |</span><br><span class="line">|---------|:--------|</span><br><span class="line">| 2 | train1 |</span><br><span class="line">| 1 | bus1 |</span><br><span class="line">| 2 | train3 |</span><br><span class="line">| 5 | metro1 |</span><br><span class="line">| 4 | tram1 |</span><br><span class="line">| 1 | bus2 |</span><br><span class="line">| 5 | metro2 |</span><br><span class="line">| 5 | metro3 |</span><br></pre></td></tr></table></figure><p>In this case, the <code>field_1</code> values in <code>table_1</code> are <code>1, 2, 3, 4</code>.</p><p>The output should be:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">| field_1 | field_3 |</span><br><span class="line">|---------|:--------|</span><br><span class="line">| 2 | train1 |</span><br><span class="line">| 1 | bus1 |</span><br><span class="line">| 2 | train3 |</span><br><span class="line">| 4 | tram1 |</span><br><span class="line">| 1 | bus2 |</span><br></pre></td></tr></table></figure><h3 id="Code"><a href="#Code" class="headerlink" title="Code"></a>Code</h3><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line">table_1_path = <span class="string">'path\\table_1.txt'</span></span><br><span class="line">table_2_path = <span class="string">'path\\table_2.txt'</span></span><br><span class="line"> </span><br><span class="line">table_1 = pd.read_csv(table_1_path)</span><br><span class="line">table_2 = pd.read_csv(table_2_path)</span><br><span class="line"> </span><br><span class="line">value = table_1[<span class="string">'field_1'</span>]</span><br><span class="line"><span class="comment"># To select rows whose column value is in an iterable, use .isin()</span></span><br><span class="line">output = table_2.loc[table_2[<span class="string">'field_1'</span>].isin(value)]</span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> output</span><br><span class="line"><span class="comment">#-------------------------</span></span><br><span class="line"> field_1 field_3</span><br><span class="line"><span class="number">0</span> <span class="number">2</span> train1 </span><br><span class="line"><span class="number">1</span> <span class="number">1</span> bus1 </span><br><span class="line"><span class="number">2</span> <span class="number">2</span> train3 </span><br><span class="line"><span class="number">4</span> <span class="number">4</span> tram1 </span><br><span class="line"><span class="number">5</span> <span class="number">1</span> bus2 </span><br><span class="line">[Finished <span class="keyword">in</span> <span class="number">1.0</span>s]</span><br></pre></td></tr></table></figure><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="https://stackoverflow.com/questions/17071871/select-rows-from-a-dataframe-based-on-values-in-a-column-in-pandas" target="_blank" rel="noopener">Select rows from a DataFrame based on values in a column in pandas</a><br>[2] <a href="https://pandas.pydata.org/pandas-docs/stable/indexing.html" target="_blank" rel="noopener">Pandas document | Different Choices for Indexing</a></p>]]></content>
</entry>
<entry>
<title>Python Nested Class</title>
<link href="/posts/31044/"/>
<content type="html"><![CDATA[<p>What I want to do, is to have a hierarchically organized Python <code>Class</code>. I wanted to pass the <code>outer class</code> instance vatible to <code>inner class</code>. Like: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Outer</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, outerObj)</span>:</span></span><br><span class="line"> self.obj = outerObj</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">outerFunction</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="comment"># do something</span></span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">Inner</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line"> self.varible = Outer.obj.varible</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">innerFunction</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="comment"># do something else</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Usage: -----------------------------------</span></span><br><span class="line">f = Outer(sth)</span><br><span class="line">b = f.Inner()</span><br><span class="line">b.innerFunction()</span><br></pre></td></tr></table></figure><p>But this can not work. The only solution is to instance <code>outer class</code> again in <code>inner class</code>. It will make the code looks like nested class, but actually there are two <code>outer class objects</code>. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Outer</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">some_method</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="comment"># do something</span></span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">_Inner</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, outer)</span>:</span></span><br><span class="line"> outer.some_method()</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">Inner</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="keyword">return</span> Inner(self)</span><br></pre></td></tr></table></figure><p>The best way to write nested class, is to avoid it.</p><blockquote><p>The methods of a nested class cannot directly access the instance attributes of the outer class.<br>Note that it is not necessarily the case that an instance of the outer class exists even when you have created an instance of the inner class.<br>In fact, it is often recommended against using nested classes, since the nesting does not imply any particular relationship between the inner and outer classes.</p></blockquote><p>Reference:<br>[1] <a href="https://stackoverflow.com/questions/2024566/access-outer-class-from-inner-class-in-python" target="_blank" rel="noopener">Access outer class from inner class in python</a><br>[2] <a href="https://stackoverflow.com/questions/13798044/in-nested-classes-how-to-access-outer-classs-elements-from-nested-class-in-pyt" target="_blank" rel="noopener">In nested classes, how to access outer class’s elements from nested class in Python?</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>GIS Object Has No Attribute 'admin'</title>
<link href="/posts/8573/"/>
<content type="html"><![CDATA[<h3 id="ArcGIS-Python-API"><a href="#ArcGIS-Python-API" class="headerlink" title="ArcGIS Python API"></a>ArcGIS Python API</h3><blockquote><p>The ArcGIS API for Python is a powerful, modern and easy to use Pythonic library to perform GIS visualization and analysis, spatial data management and GIS system administration tasks that can run both in an interactive fashion, as well as using scripts.</p></blockquote><blockquote><p>The <code>gis</code> module acts as a representation of your GIS. It forms the entry point to your scripst and gives you the ability to manage users, groups and content.</p></blockquote><p>There are a lot of changes in ArcGIS Python API 1.2 than 1.0. E.g, <code>gis.admin</code> module is new, it can allow a better management for adminiatrators of their accounts.</p><hr><h3 id="Error"><a href="#Error" class="headerlink" title="Error"></a>Error</h3><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">pro_license = gis.admin.license.get(<span class="string">'ArcGIS Pro'</span>)</span><br><span class="line">pro_license.user_entitlement(<span class="string">'Testing_User1'</span>, <span class="string">'geostatAnalystN'</span>)</span><br><span class="line"></span><br><span class="line">---------------------------------------------------------------------------</span><br><span class="line">AttributeError Traceback (most recent call last)</span><br><span class="line"><ipython-input<span class="number">-42</span><span class="number">-81</span>b2838eb931> <span class="keyword">in</span> <module>()</span><br><span class="line">----> 1 pro_license = gis_zuo.admin.license.get('ArcGIS Pro')</span><br><span class="line"> <span class="number">2</span> pro_license.user_entitlement(<span class="string">'Testing_User1'</span>, <span class="string">'geostatAnalystN'</span>)</span><br><span class="line">AttributeError: <span class="string">'GIS'</span> object has no attribute <span class="string">'admin'</span></span><br></pre></td></tr></table></figure><hr><h3 id="Reasons"><a href="#Reasons" class="headerlink" title="Reasons"></a>Reasons</h3><p>Arcgis python API Version 1.2 introduces a new <code>admin</code> module. Lower versions need to be upgraded to call <code>admin</code>.</p><hr><h3 id="Resolution"><a href="#Resolution" class="headerlink" title="Resolution"></a>Resolution</h3><p>Ungrade the API in command line:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda upgrade -c esri arcgis</span><br></pre></td></tr></table></figure></p><hr><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="http://esri.github.io/arcgis-python-api/apidoc/html/arcgis.gis.admin.html" target="_blank" rel="noopener">The gis.admin module</a><br>[2] <a href="https://developers.arcgis.com/python/guide/gis-admin-module/" target="_blank" rel="noopener">arcgis.gis.admin module</a><br>[3] <a href="https://community.esri.com/thread/202991-module-arcgisgis-has-no-attribute-server" target="_blank" rel="noopener">AttributeError: ‘GIS’ object has no attribute ‘admin’</a><br>[4] <a href="https://developers.arcgis.com/python/guide/install-and-set-up/" target="_blank" rel="noopener">ArcGIS API for Python</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
<tags>
<tag> error shooting </tag>
</tags>
</entry>
<entry>
<title>Python Logging to Console and External File</title>
<link href="/posts/22406/"/>
<content type="html"><![CDATA[<h3 id="Function"><a href="#Function" class="headerlink" title="Function"></a>Function</h3><p>Logging to multiple destinations with different levels.</p><h3 id="Code"><a href="#Code" class="headerlink" title="Code"></a>Code</h3><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#https://docs.python.org/3.5/howto/logging-cookbook.html</span></span><br><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"></span><br><span class="line"><span class="comment"># set up logging to file - see previous section for more details</span></span><br><span class="line">logging.basicConfig(level=logging.DEBUG,</span><br><span class="line"> format=<span class="string">'%(asctime)s %(name)-12s %(levelname)-8s %(message)s'</span>,</span><br><span class="line"> datefmt=<span class="string">'%m-%d %H:%M'</span>,</span><br><span class="line"> filename=<span class="string">'myapp.log'</span>,</span><br><span class="line"> filemode=<span class="string">'w'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># define a Handler which writes INFO messages or higher to the sys.stderr</span></span><br><span class="line">console = logging.StreamHandler()</span><br><span class="line">console.setLevel(logging.INFO)</span><br><span class="line"></span><br><span class="line"><span class="comment"># set a format which is simpler for console use</span></span><br><span class="line">formatter = logging.Formatter(<span class="string">'%(name)-12s: %(levelname)-8s %(message)s'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># tell the handler to use this format</span></span><br><span class="line">console.setFormatter(formatter)</span><br><span class="line"></span><br><span class="line"><span class="comment"># add the handler to the root logger</span></span><br><span class="line">logging.getLogger(<span class="string">''</span>).addHandler(console)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Now, we can log to the root logger, or any other logger. First the root...</span></span><br><span class="line">logging.info(<span class="string">'root logging'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Now, define a couple of other loggers which might represent areas in your</span></span><br><span class="line"><span class="comment"># application:</span></span><br><span class="line">logger1 = logging.getLogger(<span class="string">'area1'</span>)</span><br><span class="line">logger2 = logging.getLogger(<span class="string">'area2'</span>)</span><br><span class="line">logger1.debug(<span class="string">'logger1'</span>)</span><br><span class="line">logger1.info(<span class="string">'logger1'</span>)</span><br><span class="line">logger1.warning(<span class="string">'logger1'</span>)</span><br><span class="line">logger1.error(<span class="string">'logger1'</span>)</span><br><span class="line">logger2.debug(<span class="string">'logger2'</span>)</span><br><span class="line">logger2.info(<span class="string">'logger2'</span>)</span><br><span class="line">logger2.warning(<span class="string">'logger2'</span>)</span><br><span class="line">logger2.error(<span class="string">'logger2'</span>)</span><br></pre></td></tr></table></figure><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://docs.python.org/3.5/howto/logging-cookbook.html#logging-to-multiple-destinations" target="_blank" rel="noopener">Python Cookbook</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>Some Useful Packages in Latex</title>
<link href="/posts/49491/"/>
<content type="html"><![CDATA[<ul><li><p>Color control</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">\usepackage{xcolor}</span><br><span class="line">\usepackage{color}</span><br><span class="line">\definecolor{col_matrix1}{HTML}{535353}</span><br><span class="line">\definecolor{col_matrix2}{HTML}{D9D9D9}</span><br><span class="line">\definecolor{col_matrix3}{HTML}{989898}</span><br></pre></td></tr></table></figure></li><li><p>Color in tables</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\usepackage{colortbl}</span><br></pre></td></tr></table></figure></li><li><p>Table formatting</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\usepackage{tabularx}</span><br></pre></td></tr></table></figure></li><li><p>Figure formatting</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">\usepackage{graphicx,subfigure}</span><br><span class="line">\begin{figure}</span><br><span class="line">\centering </span><br><span class="line">\subfigure[Subfigure a.]{\label{fig:1}\includegraphics[width=68mm]{figure1.png}}</span><br><span class="line">\subfigure[Subfigure b.]{\label{fig:2}\includegraphics[width=66mm]{figure2.png}}</span><br><span class="line">\caption{Two figures in a row.}</span><br><span class="line">\end{figure}</span><br></pre></td></tr></table></figure></li><li><p>Page padding</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">\usepackage{geometry}</span><br><span class="line">\geometry{left=3.8cm,right=3.8cm,top=3.5cm,bottom=3.5cm}</span><br><span class="line">\setmainfont[</span><br><span class="line"> Extension=.otf,</span><br><span class="line"> UprightFont= *-regular,</span><br><span class="line"> BoldFont=*-bold,</span><br><span class="line"> ItalicFont=*-italic,</span><br><span class="line"> BoldItalicFont=*-bolditalic,</span><br><span class="line">]{texgyreheros}</span><br></pre></td></tr></table></figure></li><li><p>Citation formatting</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">\usepackage{apacite}</span><br><span class="line">\bibliographystyle{apacite}</span><br><span class="line">\bibliography{bibliography.bib}</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<categories>
<category> Latex </category>
</categories>
</entry>
<entry>
<title>Extract Hour Field from Text under Database(PostgreSQL)</title>
<link href="/posts/9892/"/>
<content type="html"><![CDATA[<h3 id="What-to-Extract"><a href="#What-to-Extract" class="headerlink" title="What to Extract?"></a>What to Extract?</h3><p>We have a text file, which including texts, numbers and time. We want to extract some time information, for instance hour field from the whole data.</p><p>One row from original data:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Unnamed: 0,createdAT,createdATUnixTime,msgtext,WGS84Latitude,WGS84Longitude,class</span><br><span class="line">2506097,2014-03-16 15:52:05,1394985125,连环撞车啊,五部车子 我在这里:,31.2415853271484,121.417396393555,1</span><br></pre></td></tr></table></figure></p><p>For this record, what we want to extract is hour field <code>15</code> from column <code>createdAT</code>. We load the data set into database and use <code>EXTRACT</code> command to do this.</p><p>An example:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">database=# SELECT EXTRACT(HOUR FROM TIMESTAMP '2014-03-16 15:52:05');</span><br><span class="line"></span><br><span class="line"> date_part </span><br><span class="line"><span class="comment">-----------</span></span><br><span class="line"> 15</span><br><span class="line">(1 row)</span><br></pre></td></tr></table></figure></p><hr><h3 id="How-to-extract"><a href="#How-to-extract" class="headerlink" title="How to extract?"></a>How to extract?</h3><ol><li><p>Load data into Database by ‘Command’</p><p>Input the bash in terminal.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pgcsv --db postgresql://localhost/yourdatabase table /Users/xxx/Documents/xxx.csv</span><br></pre></td></tr></table></figure></li><li><p>Convert <code>char</code> to <code>timestamp</code></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> <span class="keyword">table</span> </span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">COLUMN</span> createdAT </span><br><span class="line"><span class="keyword">TYPE</span> <span class="keyword">TIMESTAMP</span> <span class="keyword">WITHOUT</span> <span class="keyword">TIME</span> ZONE </span><br><span class="line"><span class="keyword">USING</span> to_timestamp(createdAT, <span class="string">'YYYY-MM-DD HH24:MI:SS'</span>);</span><br></pre></td></tr></table></figure></li><li><p>Add a new column</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> <span class="keyword">table</span></span><br><span class="line"><span class="keyword">ADD</span> <span class="keyword">COLUMN</span> <span class="keyword">hour</span> <span <span class="keyword">class</span>=<span class="string">"built_in"</span>><span class="built_in">smallint</span>;</span><br></pre></td></tr></table></figure></li><li><p>Extract hour field and save it in a column</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">UPDATE</span> ntt_cluster <span class="keyword">SET</span> <span class="keyword">hour</span> = <span class="keyword">EXTRACT</span>(<span class="keyword">HOUR</span> <span class="keyword">FROM</span> createdat);</span><br></pre></td></tr></table></figure></li><li><p>Check extract result</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">database=# select * from table limit 1;</span><br><span class="line"></span><br><span class="line"> unnamed_0 | createdat | createdatunixtime | msgtext | wgs84latitude | wgs84longitude | class | hour </span><br><span class="line"><span class="comment">-----------+---------------------+-------------------+--------------------------------+------------------+------------------+-------+------</span></span><br><span class="line"> 2506097 | 2014-03-16 15:52:05 | 1394985125 | 连环撞车啊,五部车子 我在这里: | 31.2415853271484 | 121.417396393555 | 1 | 15</span><br><span class="line"></span><br><span class="line">(1 row)</span><br></pre></td></tr></table></figure></li></ol><hr><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="https://www.postgresql.org/docs/8.2/static/functions-datetime.html" target="_blank" rel="noopener">PostgreSQL 8.2.23 Documentation | Chapter 9. Functions and Operators</a><br>[2] <a href="https://stackoverflow.com/questions/22804778/updating-postgresql-column-with-extract-function-more-than-one-row-returned-by" target="_blank" rel="noopener">StackOverFlow | Updating postgreSQL column with EXTRACT function (More than one row returned by a subquery used as an expression)</a></p>]]></content>
<categories>
<category> Database </category>
</categories>
<tags>
<tag> text processing </tag>
</tags>
</entry>
<entry>
<title>Including Chinese Charaters in Latex</title>
<link href="/posts/57760/"/>
<content type="html"><![CDATA[<h3 id="Building-System"><a href="#Building-System" class="headerlink" title="Building System"></a>Building System</h3><p>Using <code>xelatex</code> instead of <code>pdf</code> to build the document. Adding below codes at the first line to change build system. </p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/python</span><br></pre></td></tr></table></figure><hr><h3 id="ctex-classes"><a href="#ctex-classes" class="headerlink" title="ctex classes"></a><code>ctex classes</code></h3><p>To compile simplified Chinese, you can used <code>ctex</code> document classes. </p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">\<span class="name">documentclass</span><span class="string">{ctexart}</span></span></span><br></pre></td></tr></table></figure><hr><h3 id="CJK-package"><a href="#CJK-package" class="headerlink" title="CJK package"></a>CJK package</h3><p>Other easy way to create Chinese documents is by importing the <code>xeCJK</code> package and setting up your favourite font. The <code>xeCJK</code> package also includes traditional Chinese, Japanese and Korean. </p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">\<span class="name">usepackage</span><span class="string">{xeCJK}</span></span></span><br></pre></td></tr></table></figure><hr><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="https://www.sharelatex.com/learn/Chinese" target="_blank" rel="noopener">ShareLaTeX guides | Chinese</a></p>]]></content>
<categories>
<category> Latex </category>
</categories>
<tags>
<tag> error shooting </tag>
</tags>
</entry>
<entry>
<title>An Easy Way to Draw Study Area</title>
<link href="/posts/21415/"/>
<content type="html"><![CDATA[<p>There are many ways to draw a map.</p><ul><li>ArcGIS, QGIS<br>With <code>ArcGIS</code> and <code>QGIS</code>, firstly we need a <code>shapefile</code> of target area.</li><li>Adobe Illustrator<br>With the <code>MapPublisher</code> plug-in, people can draw high resolution maps. Also, it can be saved as <code>PDF</code>, <code>JPEG</code> or <code>TIF</code>.</li><li>R<br>If you don’t know anything about programming, you can also follow this tutorial. Mapping with <code>R</code> is pretty friendly. Users can export maps as <code>PDF</code> or <code>PNG</code>.</li></ul><h3 id="Install-R"><a href="#Install-R" class="headerlink" title="Install R"></a>Install R</h3><p>Firstly, download and install <code>R</code> environment for your machine. <a href="https://cran.r-project.org/bin/windows/base/" target="_blank" rel="noopener">Windows</a>, <a href="https://cran.r-project.org/bin/macosx/" target="_blank" rel="noopener">Mac</a>.</p><p><code>RStudio</code> is a set of integrated tools designed to help you be more productive with R. <a href="https://www.rstudio.com/products/rstudio/download/" target="_blank" rel="noopener">download</a></p><h3 id="Install-ggmap"><a href="#Install-ggmap" class="headerlink" title="Install ggmap"></a>Install ggmap</h3><p><a href="https://github.com/dkahle/ggmap" target="_blank" rel="noopener"><code>ggmap</code></a> makes it easy to retrieve raster map tiles from popular online mapping services like <a href="https://developers.google.com/maps/documentation/static-maps/?hl=en" target="_blank" rel="noopener">Google Maps</a>, <a href="https://www.openstreetmap.org/#map=6/51.330/10.453" target="_blank" rel="noopener">OpenStreetMap</a>, <a href="http://maps.stamen.com/#watercolor/12/37.7706/-122.3782" target="_blank" rel="noopener">Stamen Maps</a>.</p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(!requireNamespace(<span class="string">"devtools"</span>)) install.packages(<span class="string">"devtools"</span>)</span><br><span class="line">devtools::install_github(<span class="string">"dkahle/ggmap"</span>, ref = <span class="string">"tidyup"</span>)</span><br></pre></td></tr></table></figure><p>Here we use <code>Stamen Maps</code> and <code>Google Maps</code> as an example.</p><h3 id="Examples"><a href="#Examples" class="headerlink" title="Examples"></a>Examples</h3><p>Use <code>ggmap</code> package. </p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">library</span>(ggmap)</span><br></pre></td></tr></table></figure><h4 id="Stamen-Maps"><a href="#Stamen-Maps" class="headerlink" title="Stamen Maps"></a>Stamen Maps</h4><p>With <code>Stamen Maps</code>, there are many themes to choose from. “Toner” is for high-contrast B+W (black and white) map, with six flavors: standard toner, hybrid, labels, lines, background, and lite. “Terrain” suits terrain maps, featuring hill shading and natural vegetation colors, with four flavors: standard terrain, labels, lines, and background. Moreover, there are “Watercolor”, “Burning Map” and so forth.<br>Draw a map of China: </p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">china <- c(left = <span class="number">72</span>, bottom = <span class="number">15</span>, right = <span class="number">135</span>, top = <span class="number">60</span>) <span class="comment"># coordinates</span></span><br><span class="line"></span><br><span class="line">map_china <- get_stamenmap(china, zoom = <span class="number">4</span>, maptype = <span class="string">"toner-lite"</span>) <span class="comment">#get tiles from net</span></span><br><span class="line"></span><br><span class="line">ggmap(map_china) <span class="comment">#draw the map</span></span><br></pre></td></tr></table></figure><p><img src="/images/MapChina.jpg" alt="Map of China"></p><p>But the problem for <code>Stamen Maps</code> is not so detailed. If we set <code>zoom = 12</code>, the map is blurring. </p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">center <- c(left = <span class="number">121.424063</span>, bottom = <span class="number">31.195848</span>, right = <span class="number">121.490231</span>, top = <span class="number">31.236447</span>)</span><br><span class="line"></span><br><span class="line">map_center <- get_stamenmap(center, zoom = <span class="number">12</span>, maptype = <span class="string">"toner-lite"</span>)</span><br><span class="line"></span><br><span class="line">ggmap(map_center)</span><br></pre></td></tr></table></figure><p><img src="/images/MapCenter_blur.jpg" alt="Map of Shanghai Center"></p><p>So we use <code>Google Map</code> to draw maps with big zoom levels.</p><h4 id="Google-Maps"><a href="#Google-Maps" class="headerlink" title="Google Maps"></a>Google Maps</h4><p>The benifit of Google is we don’t need to specify coordinates manully. We can put country or city names as we search them in <code>Google Maps</code>. </p><figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">map <- get_map(location = <span class="string">'Zhangjiang'</span>, zoom = <span class="number">10</span>)</span><br><span class="line">ggmap(map)</span><br></pre></td></tr></table></figure><p><img src="/images/MapCenter.jpg" alt="Map of Shanghai Center"></p><h3 id="Others"><a href="#Others" class="headerlink" title="Others"></a>Others</h3><p>With <code>R</code> and <code>ggmap</code> there are much more fancy feathres can be plotted in maps. For instance, <code>points</code>, <code>polygons</code>, <code>choropleth map</code> and also with external data.</p><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="https://github.com/dkahle/ggmap" target="_blank" rel="noopener">GitHub | A package for plotting maps in R with ggplot2</a><br>[2] <a href="http://eriqande.github.io/rep-res-web/lectures/making-maps-with-R.html" target="_blank" rel="noopener">Eric C. Anderson | Making Maps with R</a><br>[3] <a href="http://www.molecularecologist.com/2012/09/making-maps-with-r/" target="_blank" rel="noopener">kimgilbert | Making Maps with R</a></p>]]></content>
<categories>
<category> R </category>
</categories>
<tags>
<tag> map </tag>
</tags>
</entry>
<entry>
<title>Text Comparision with Sublime</title>
<link href="/posts/1328/"/>
<content type="html"><![CDATA[<p>Sublimerge is a sublime tool used for text comparision.</p><h3 id="Installation"><a href="#Installation" class="headerlink" title="Installation"></a>Installation</h3><ol><li>Install the Package Control (if you haven’t already)</li><li>Open Command Palette (ctrl + shift + p on Windows and Linux, cmd + shift + p on Mac)</li><li>Choose Package Control: Install Package</li><li>Search for Sublimerge 3 and hit enter</li><li>Restart Sublime Text to complete the installation</li></ol><hr><h3 id="How-to-use"><a href="#How-to-use" class="headerlink" title="How to use"></a>How to use</h3><p><code>Right Click</code> and choose <code>Sublimerge</code><br><img src="/images/textDiff0.png" alt=""></p><p>It will be like:<br><img src="/images/textDiff.png" alt=""></p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://www.sublimerge.com/sm3/docs/quick-start.html#installing-license" target="_blank" rel="noopener">Sublimerge 3 documentation</a></p>]]></content>
<categories>
<category> Sublime </category>
</categories>
</entry>
<entry>
<title>Table Deduplication with Postgresql</title>
<link href="/posts/28777/"/>
<content type="html"><![CDATA[<h3 id="ctid"><a href="#ctid" class="headerlink" title="ctid"></a><code>ctid</code></h3><blockquote><p>Every <code>table</code> has several system columns that are implicitly defined by the system.<br><code>ctid</code>, the physical location of the row version within its <code>table</code>. Note that although the ctid can be used to locate the row version very quickly, a row’s ctid will change each time it is updated or moved by VACUUM FULL. Therefore ctid is useless as a long-term row identifier. The OID, or even better a user-defined serial number, should be used to identify logical rows.</p></blockquote><p>In this case, <code>ctid</code> can be used for deduplication.</p><hr><h3 id="Create-test-table"><a href="#Create-test-table" class="headerlink" title="Create test table"></a>Create test table</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">test_table=# create table test(</span><br><span class="line">test_table(# id int,</span><br><span class="line">test_table(# name varchar);</span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span></span><br></pre></td></tr></table></figure><hr><h3 id="Insert-test-data"><a href="#Insert-test-data" class="headerlink" title="Insert test data"></a>Insert test data</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">test_table=# insert into test values(1, 'David');</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">1</span>, <span class="string">'Wang'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">1</span>, <span class="string">'Fatti'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">2</span>, <span class="string">'Haupt'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">2</span>, <span class="string">'Ost'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">2</span>, <span class="string">'Ost'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">3</span>, <span class="string">'Buch'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br><span class="line">test_table=# <span class="keyword">insert</span> <span class="keyword">into</span> <span class="keyword">test</span> <span class="keyword">values</span>(<span class="number">3</span>, <span class="string">'Musik'</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="number">0</span> <span class="number">1</span></span><br></pre></td></tr></table></figure><hr><h3 id="Check-raw-data"><a href="#Check-raw-data" class="headerlink" title="Check raw data"></a>Check raw data</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">test_table=# select *,ctid from test;</span><br><span class="line"> id | name | ctid </span><br><span class="line"><span class="comment">----+-------+-------</span></span><br><span class="line"> 1 | David | (0,1)</span><br><span class="line"> 1 | Wang | (0,2)</span><br><span class="line"> 1 | Fatti | (0,3)</span><br><span class="line"> 2 | Haupt | (0,4)</span><br><span class="line"> 2 | Ost | (0,5)</span><br><span class="line"> 2 | Ost | (0,6)</span><br><span class="line"> 3 | Buch | (0,7)</span><br><span class="line"> 3 | Musik | (0,8)</span><br><span class="line">(8 rows)</span><br></pre></td></tr></table></figure><hr><h3 id="Finding-duplication"><a href="#Finding-duplication" class="headerlink" title="Finding duplication"></a>Finding duplication</h3><p>Here we want to delete rows with same <code>id</code>. Finding data by unique <code>id</code>: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">test_table=# select distinct id, count(*) from test group by id having count(*) > 1;</span><br><span class="line"> id | count </span><br><span class="line"><span class="comment">----+-------</span></span><br><span class="line"> 1 | 3</span><br><span class="line"> 2 | 3</span><br><span class="line"> 3 | 2</span><br><span class="line">(3 rows)</span><br></pre></td></tr></table></figure><p>It means we have 3 rows with <code>id = 1</code>, 3 rows with <code>id = 2</code>, 2 rows with <code>id = 3</code>.</p><hr><h3 id="Finding-rows-needed-to-kept"><a href="#Finding-rows-needed-to-kept" class="headerlink" title="Finding rows needed to kept"></a>Finding rows needed to kept</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">test_table=# select ctid, * from test where ctid in (select min(ctid) from test group by id);</span><br><span class="line"> ctid | id | name </span><br><span class="line"><span class="comment">-------+----+-------</span></span><br><span class="line"> (0,1) | 1 | David</span><br><span class="line"> (0,4) | 2 | Haupt</span><br><span class="line"> (0,7) | 3 | Buch</span><br><span class="line">(3 rows)</span><br></pre></td></tr></table></figure><p>Because <code>ctid</code> means phsical address of each rows, <code>min(ctid)</code> gets the first row by query. <code>select min(ctid) from emp group by id</code> gets phsical addresses of the first rows by identified <code>id</code>.</p><hr><h3 id="Delete-duplication"><a href="#Delete-duplication" class="headerlink" title="Delete duplication"></a>Delete duplication</h3><p>Simply, we can delete the rows not in <code>select min(ctid) from emp group by id</code>. Identified <code>id</code> rows will be remained. </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">test_table=# delete from test where ctid not in (select min(ctid) from test group by id);</span><br><span class="line"><span class="keyword">DELETE</span> <span class="number">5</span></span><br></pre></td></tr></table></figure><hr><h3 id="Check-result"><a href="#Check-result" class="headerlink" title="Check result"></a>Check result</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">test_table=# select * from test;</span><br><span class="line"> id | name </span><br><span class="line"><span class="comment">----+-------</span></span><br><span class="line"> 1 | David</span><br><span class="line"> 2 | Haupt</span><br><span class="line"> 3 | Buch</span><br><span class="line">(3 rows)</span><br></pre></td></tr></table></figure><hr><h3 id="Refrence"><a href="#Refrence" class="headerlink" title="Refrence"></a>Refrence</h3><p>[1] <a href="https://www.postgresql.org/docs/8.2/static/ddl-system-columns.html" target="_blank" rel="noopener">PostgreSQL 8.2.23 Documentation</a><br>[2] <a href="http://www.cnblogs.com/mchina/archive/2013/04/15/3022086.html" target="_blank" rel="noopener">PostgreSQL删除重复数据</a><br>[3] <a href="http://www.cybertec.at/removing-duplicate-rows-in-postgresql/" target="_blank" rel="noopener">Removing duplicate rows in PostgreSQL</a><br>[4] <a href="http://www.postgresqltutorial.com/postgresql-select-distinct/" target="_blank" rel="noopener">PostgreSQL SELECT DISTINCT</a></p>]]></content>
<categories>
<category> Database </category>
</categories>
</entry>
<entry>
<title>Using Regular Expression to Filter Chinese</title>
<link href="/posts/28001/"/>
<content type="html"><![CDATA[<p><a href="https://docs.python.org/3/library/re.html" target="_blank" rel="noopener"><code>Regular expression</code></a> is used for pattern matching. It’s a powerful and handy tool for text filteration.<br><a id="more"></a></p><hr><h3 id="Get-only-Chinese-characters"><a href="#Get-only-Chinese-characters" class="headerlink" title="Get only Chinese characters"></a>Get only Chinese characters</h3><p>Simply remove all non-Chinese characters: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getChinese</span><span class="params">(context)</span>:</span></span><br><span class="line"> context = context.decode(<span class="string">"utf-8"</span>) <span class="comment"># convert context from str to unicode</span></span><br><span class="line"> filtrate = re.compile(<span class="string">u'[^\u4E00-\u9FA5]'</span>) <span class="comment"># non-Chinese unicode range</span></span><br><span class="line"> context = filtrate.sub(<span class="string">r''</span>, context) <span class="comment"># remove all non-Chinese characters</span></span><br><span class="line"> context = context.encode(<span class="string">"utf-8"</span>) <span class="comment"># convert unicode back to str</span></span><br><span class="line"> <span class="keyword">return</span> context</span><br></pre></td></tr></table></figure><hr><h3 id="Clean-text"><a href="#Clean-text" class="headerlink" title="Clean text"></a>Clean text</h3><p>Remove links: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context = re.sub(<span class="string">"http://[a-zA-z./\d]*"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Remove emoji: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context = re.sub(<span class="string">"\[.{0,12}\]"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Extract and remove tags: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">tags = re.findall(<span class="string">"#(.{0,30})#"</span>,context)</span><br><span class="line">context = re.sub(<span class="string">"#.{0,30}#"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Extract and remove @somebody: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">at = re.findall(<span class="string">"@([^@]{0,30})\s"</span>,context)</span><br><span class="line">context = re.sub(<span class="string">"@([^@]{0,30})\s"</span>,<span class="string">""</span>,context)</span><br><span class="line">at+= re.findall(<span class="string">"@([^@]{0,30}))"</span>,context)</span><br><span class="line">context = re.sub(<span class="string">"@([^@]{0,30}))"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Extract and remove english characters: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">english = re.findall(<span class="string">"[a-z]+"</span>,context)</span><br><span class="line">context = re.sub(<span class="string">"[a-z]+"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Remove punctuation: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">context = re.sub(<span class="string">"[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+"</span>.decode(<span class="string">"utf8"</span>), <span class="string">""</span>,context)</span><br><span class="line">context = re.sub(<span class="string">"[【】╮╯▽╰╭★→「」]+"</span>.decode(<span class="string">"utf8"</span>),<span class="string">""</span>,context)</span><br><span class="line">context = re.sub(<span class="string">"!,❤。~《》:()【】「」?”“;:、"</span>.decode(<span class="string">"utf8"</span>),<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Remove space: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context = re.sub(<span class="string">"\s"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Remove digits: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context = re.sub(<span class="string">"\d"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><p>Remove <code>....</code>: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context = re.sub(<span class="string">"\.*"</span>,<span class="string">""</span>,context)</span><br></pre></td></tr></table></figure><hr><h3 id="Chinese-text-segmentation"><a href="#Chinese-text-segmentation" class="headerlink" title="Chinese text segmentation"></a>Chinese text segmentation</h3><p><a href="https://github.com/fxsjy/jieba" target="_blank" rel="noopener"><code>jieba</code></a> is a <code>python</code> package used for Chinese text segmentation. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> jieba</span><br><span class="line">text = jieba.lcut(context)</span><br></pre></td></tr></table></figure><hr><h3 id="Stop-Words"><a href="#Stop-Words" class="headerlink" title="Stop Words"></a>Stop Words</h3><p>For key words extraction, some regular words are unusable, e.g. <code>我</code>, <code>我们</code>,<code>你</code>, <code>你们</code>, <code>一些</code>, <code>以及</code>, <code>只是</code> and etc.<br>Filtering with stop words list is necessary for keywords extraction.<br>There’s manay stop word lists online, which you can reach easily.</p><p>Remove English stopwords: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">from</span> nltk.corpus <span class="keyword">import</span> stopwords <span class="keyword">as</span> e_stopwords</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">EngStopword</span><span class="params">(context)</span>:</span></span><br><span class="line"> english = re.findall(<span class="string">"[a-z]+"</span>,context)</span><br><span class="line"> e_clean = [t <span class="keyword">for</span> t <span class="keyword">in</span> english <span class="keyword">if</span> t <span class="keyword">not</span> <span class="keyword">in</span> e_stopwords.words(<span class="string">'english'</span>) <span class="keyword">and</span> len(t) <span class="keyword">is</span> <span class="keyword">not</span> <span class="number">1</span>]</span><br><span class="line"> <span class="keyword">return</span> e_clean</span><br></pre></td></tr></table></figure><p>Remove Chinese stopwords: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">ChiStopwords</span><span class="params">(context)</span>:</span></span><br><span class="line"> <span class="comment"># read stopwords list from local file</span></span><br><span class="line"> stop_f=open(<span class="string">'filepath'</span>,<span class="string">'r'</span>)</span><br><span class="line"> stopwords = [l.strip() <span class="keyword">for</span> l <span class="keyword">in</span> stop_f.readlines()]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(stopwords)):</span><br><span class="line"> stopwords[i] = stopwords[i]</span><br><span class="line"> stop_f.close()</span><br><span class="line"> clean = [t <span class="keyword">for</span> t <span class="keyword">in</span> context <span class="keyword">if</span> t <span class="keyword">not</span> <span class="keyword">in</span> stopwords]</span><br><span class="line"> <span class="keyword">return</span> clean</span><br></pre></td></tr></table></figure><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://github.com/JeremyLi28/Data-pipeline-for-Sina-Weibo-Interaction-prediction" target="_blank" rel="noopener">Data pipeline for Sina Weibo Interaction-prediction</a><br>[2] <a href="http://www.linuxhub.org/?p=3196" target="_blank" rel="noopener">Python过滤中文re匹配</a><br>[3] <a href="http://blog.csdn.net/shijiebei2009/article/details/39696571" target="_blank" rel="noopener">最全中文停用词表整理(1893个)</a><br>[4] <a href="https://stackoverflow.com/questions/5242213/whats-the-fast-way-to-split-a-unicode-string-into-a-list-using-white-spaces-or" target="_blank" rel="noopener">What’s the fast way to split a unicode string into a list, using white spaces OR punctuation as a separator?</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>Python Encoding System</title>
<link href="/posts/50024/"/>
<content type="html"><![CDATA[<p>When dealing with Chinese characters, decoding disorder might be a normal problem, espatially, with cross platform development.</p><p>Some error like: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal</span><br></pre></td></tr></table></figure><p>occurs normally.</p><p>Local environment:<br>Platform: Mac English system<br>Python version: 2.7.10<br>Editor: Sublime 3</p><hr><h3 id="Unicode-and-UTF-8"><a href="#Unicode-and-UTF-8" class="headerlink" title="Unicode and UTF-8"></a>Unicode and UTF-8</h3><p><code>Unicode</code> is a computing industry standard for the consistent encoding, representation, and handling of text expressed in most of the world’s writing systems. It can be implemented by different character encodings. The Unicode standard defines <code>UTF-8</code>, <code>UTF-16</code>, and <code>UTF-32</code>, and several other encodings are in use. The most commonly used encodings are UTF-8, UTF-16 and UCS-2, a precursor of UTF-16.</p><p><code>UTF-8</code>, the most widely used by web-sites, uses one byte for the first 128 code points, and up to 4 bytes for other characters. The first 128 Unicode code points are the <code>ASCII</code> characters; so an <code>ASCII</code> text is a <code>UTF-8</code> text.</p><hr><h3 id="Unicode-V-S-String"><a href="#Unicode-V-S-String" class="headerlink" title="Unicode V.S. String"></a>Unicode V.S. String</h3><p><code>Unicode</code> is not encoded, text can be encoded in a specific encoding to represent the text as raw bytes(e.g. utf-8, latin-1…).<br><code>str</code> is meaningful string which are human readable.</p><p>Create a <code>str</code> (byte string): </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">byteString = <span class="string">"hello world! (in my default locale)"</span></span><br></pre></td></tr></table></figure><p>Create a <code>unicode</code> (unicode stirng): </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">unicodeString = <span class="string">u"hello Unicode world!"</span></span><br></pre></td></tr></table></figure><p>You can think of <code>unicode</code> as a general representation of some text, a lower level of text presentataion, which can be encoded in many different ways into a sequence of binary data represented via <code>str</code>.</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>len(<span class="string">u'à'</span>) <span class="comment"># a single unicode</span></span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="meta">>>> </span>len(<span class="string">'à'</span>) <span class="comment"># by default encoding utf-8 -> takes two bytes</span></span><br><span class="line"><span class="number">2</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">u'à'</span></span><br><span class="line"><span class="string">u'\xe0'</span></span><br><span class="line"><span class="meta">>>> </span>len(<span class="string">u'à'</span>.encode(<span class="string">'latin1'</span>)) <span class="comment"># `encoding` is to represent a unicode string as a string of bytes</span></span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="meta">>>> </span>len(<span class="string">u'à'</span>.encode(<span class="string">'utf-8'</span>))</span><br><span class="line"><span class="number">2</span></span><br><span class="line"><span class="comment"># internal storage of different encoding systems</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">u'à'</span>.encode(<span class="string">'latin1'</span>) <span class="comment"># only takes one byte</span></span><br><span class="line"><span class="string">'\xe0'</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">u'à'</span>.encode(<span class="string">'utf-8'</span>) <span class="comment"># takes two bytes</span></span><br><span class="line"><span class="string">'\xc3\xa0'</span></span><br><span class="line"><span class="comment"># to display the meaningful text</span></span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> <span class="string">u'à'</span>.encode(<span class="string">'utf-8'</span>) <span class="comment"># terminal encoding is utf-8</span></span><br><span class="line">à</span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> <span class="string">u'à'</span>.encode(<span class="string">'latin1'</span>) <span class="comment"># terminal cannot understand the latin1 byte</span></span><br><span class="line">�</span><br></pre></td></tr></table></figure><p>How to convert <code>str</code> to <code>unicode</code>, and convert it back:</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>s = <span class="string">"hello normal string"</span> <span class="comment"># s is encoded to utf8 by default</span></span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> s</span><br><span class="line">hello normal string</span><br><span class="line"><span class="meta">>>> </span>type(s)</span><br><span class="line"><type <span class="string">'str'</span>></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>u = s.decode(<span class="string">"UTF-8"</span>) <span class="comment"># decode s back to unicode form</span></span><br><span class="line"><span class="meta">>>> </span>type(u)</span><br><span class="line"><type <span class="string">'unicode'</span>></span><br><span class="line"><span class="meta">>>> </span>u</span><br><span class="line"><span class="string">u'hello normal string'</span></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>backToBytes = u.encode( <span class="string">"UTF-8"</span> )</span><br><span class="line"><span class="meta">>>> </span>type(backToBytes)</span><br><span class="line"><type <span class="string">'str'</span>></span><br><span class="line"><span class="meta">>>> </span>backToBytes</span><br><span class="line"><span class="string">'hello normal string'</span></span><br></pre></td></tr></table></figure><p>Note that using <code>str</code> you have a lower-level control on the single bytes of a specific encoding representation, while using <code>unicode</code> you can only control at the code-point level.</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="string">'àèìòù'</span></span><br><span class="line"><span class="string">'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'</span></span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> <span class="string">'àèìòù'</span>.replace(<span class="string">'è'</span>, <span class="string">''</span>)</span><br><span class="line">àìòù</span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> <span class="string">'àèìòù'</span>.replace(<span class="string">'\xa8'</span>, <span class="string">''</span>)</span><br><span class="line">à?ìòù</span><br></pre></td></tr></table></figure><hr><h3 id="String-encoding-check"><a href="#String-encoding-check" class="headerlink" title="String encoding check"></a>String encoding check</h3><p>To check if a obj is <code>str</code> or <code>unicode</code>: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>isinstance(<span class="string">u'中文'</span>, unicode)</span><br><span class="line"><span class="keyword">True</span></span><br><span class="line"><span class="meta">>>> </span>isinstance(<span class="string">'中文'</span>, unicode)</span><br><span class="line"><span class="keyword">False</span></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>isinstance(<span class="string">'中文'</span>, str)</span><br><span class="line"><span class="keyword">True</span></span><br><span class="line"><span class="meta">>>> </span>isinstance(<span class="string">u'中文'</span>, str)</span><br><span class="line"><span class="keyword">False</span></span><br></pre></td></tr></table></figure><p>Don’t <code>decode</code> a <code>unicode</code>, and don’t <code>encode</code> a <code>str</code>.</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>s = <span class="string">u'ö'</span></span><br><span class="line"><span class="meta">>>> </span>s.decode()</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">1</span>, <span class="keyword">in</span> <module></span><br><span class="line">UnicodeEncodeError: <span class="string">'ascii'</span> codec can<span class="string">'t encode character u'</span>\xf6<span class="string">' in position 0:</span></span><br><span class="line"><span class="string">ordinal not in range(128)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">>>> s.encode('</span>ascii<span class="string">')</span></span><br><span class="line"><span class="string">Traceback (most recent call last):</span></span><br><span class="line"><span class="string"> File "<stdin>", line 1, in <module></span></span><br><span class="line"><span class="string">UnicodeEncodeError: '</span>ascii<span class="string">' codec can'</span>t encode character <span class="string">u'\xf6'</span> <span class="keyword">in</span> position <span class="number">0</span>:</span><br><span class="line">ordinal <span class="keyword">not</span> <span class="keyword">in</span> range(<span class="number">128</span>)</span><br></pre></td></tr></table></figure><hr><h3 id="Unicode-comparison"><a href="#Unicode-comparison" class="headerlink" title="Unicode comparison"></a>Unicode comparison</h3><p>You may use the <code>==</code> operator to compare unicode objects for equality. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>s1 = <span class="string">u'Hello'</span></span><br><span class="line"><span class="meta">>>> </span>s2 = unicode(<span class="string">"Hello"</span>)</span><br><span class="line"><span class="meta">>>> </span>type(s1), type(s2)</span><br><span class="line">(<type <span class="string">'unicode'</span>>, <type <span class="string">'unicode'</span>>)</span><br><span class="line"><span class="meta">>>> </span>s1==s2</span><br><span class="line"><span class="keyword">True</span></span><br><span class="line"><span class="meta">>>> </span></span><br><span class="line"><span class="meta">>>> </span>s3=<span class="string">'Hello'</span>.decode(<span class="string">'utf-8'</span>)</span><br><span class="line"><span class="meta">>>> </span>type(s3)</span><br><span class="line"><type <span class="string">'unicode'</span>></span><br><span class="line"><span class="meta">>>> </span>s1==s3</span><br><span class="line"><span class="keyword">True</span></span><br></pre></td></tr></table></figure><p>If you compare <code>unicode</code> obj with a <code>str</code> obj: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="string">u'Hello'</span> == <span class="string">'Hello'</span></span><br><span class="line"><span class="keyword">True</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">'Hello'</span> == <span class="string">u'Hello'</span></span><br><span class="line"><span class="keyword">True</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">u'Hello'</span> == <span class="string">'\x81\x01'</span> </span><br><span class="line">__main__:<span class="number">1</span>: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them <span class="keyword">as</span> being unequal</span><br><span class="line"><span class="keyword">False</span></span><br></pre></td></tr></table></figure><p>Compare a unicode object against a string which does not represent a valid UTF8 encoding, errors will be returned.</p><p>Compare <code>unicode</code> in a list: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> json</span><br><span class="line"><span class="meta">>>> </span>data = json.loads(<span class="string">'{"number1":"first", "number2":"second", "number3":"third"}'</span>)</span><br><span class="line"><span class="meta">>>> </span>[item <span class="keyword">for</span> item <span class="keyword">in</span> data <span class="keyword">if</span> item == <span class="string">"number1"</span>]</span><br><span class="line">[<span class="string">u'number1'</span>]</span><br><span class="line">[item <span class="keyword">for</span> item <span class="keyword">in</span> data <span class="keyword">if</span> <span class="keyword">not</span> item == <span class="string">u"number1"</span>]</span><br><span class="line">[<span class="string">u'number2'</span>, <span class="string">u'number3'</span>]</span><br></pre></td></tr></table></figure><p>When compare non-english letters, you need to <code>encode</code> or <code>decode</code> them to <code>str</code> or <code>unicode</code> firstly: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="string">u'了'</span> == <span class="string">'了'</span></span><br><span class="line"><span class="keyword">False</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">u'Hello'</span> == <span class="string">'Hello'</span></span><br><span class="line"><span class="keyword">True</span></span><br><span class="line"><span class="meta">>>> </span>>>了<span class="string">' == '</span>了<span class="string">'.decode('</span>utf<span class="number">-8</span><span class="string">')</span></span><br><span class="line"><span class="string">True</span></span><br><span class="line"><span class="string">>>> u'</span>了<span class="string">'.encode('</span>utf<span class="number">-8</span><span class="string">') == '</span>了<span class="string">'</span></span><br><span class="line"><span class="string">True</span></span><br></pre></td></tr></table></figure><h3 id="Local-system-encoding"><a href="#Local-system-encoding" class="headerlink" title="Local system encoding"></a>Local system encoding</h3><p>Python command </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Python <span class="number">2.7</span><span class="number">.10</span> (default, Feb <span class="number">7</span> <span class="number">2017</span>, <span class="number">00</span>:<span class="number">08</span>:<span class="number">15</span>) </span><br><span class="line">[GCC <span class="number">4.2</span><span class="number">.1</span> Compatible Apple LLVM <span class="number">8.0</span><span class="number">.0</span> (clang<span class="number">-800.0</span><span class="number">.34</span>)] on darwin</span><br><span class="line">Type <span class="string">"help"</span>, <span class="string">"copyright"</span>, <span class="string">"credits"</span> <span class="keyword">or</span> <span class="string">"license"</span> <span class="keyword">for</span> more information.</span><br><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> sys</span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> sys.getdefaultencoding()</span><br><span class="line">ascii</span><br></pre></td></tr></table></figure><p>Change ternimal’s encoding: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> sys</span><br><span class="line"><span class="meta">>>> </span>sys.setdefaultencoding(<span class="string">'UTF-8'</span>)</span><br></pre></td></tr></table></figure><p>When Unicode characters are printed to stdout, sys.stdout.encoding is used. A non-Unicode character is assumed to be in sys.stdout.encoding and is just sent to the terminal. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> unicodedata <span class="keyword">as</span> ud</span><br><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> sys</span><br><span class="line"><span class="meta">>>> </span>sys.stdout.encoding</span><br><span class="line"><span class="string">'cp437'</span></span><br><span class="line"><span class="meta">>>> </span>ud.name(<span class="string">u'\xe9'</span>)</span><br><span class="line"><span class="string">'LATIN SMALL LETTER E WITH ACUTE'</span></span><br><span class="line"><span class="meta">>>> </span>ud.name(<span class="string">'\xe9'</span>.decode(<span class="string">'cp437'</span>))</span><br><span class="line"><span class="string">'GREEK CAPITAL LETTER THETA'</span></span><br><span class="line"><span class="meta">>>> </span><span class="keyword">import</span> unicodedata <span class="keyword">as</span> ud</span><br><span class="line"><span class="meta">>>> </span>ud.name(<span class="string">u'\xe9'</span>)</span><br><span class="line"><span class="string">'LATIN SMALL LETTER E WITH ACUTE'</span></span><br><span class="line"><span class="meta">>>> </span><span class="string">'\xe9'</span>.decode(<span class="string">'cp437'</span>)</span><br><span class="line"><span class="string">u'\u0398'</span></span><br><span class="line"><span class="meta">>>> </span>ud.name(<span class="string">u'\u0398'</span>)</span><br><span class="line"><span class="string">'GREEK CAPITAL LETTER THETA'</span></span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> <span class="string">u'\xe9'</span></span><br><span class="line">é</span><br><span class="line"><span class="meta">>>> </span><span class="keyword">print</span> <span class="string">'\xe9'</span></span><br><span class="line">Θ</span><br></pre></td></tr></table></figure><p>As you may have noticed from the examples on this page, you can actually write Python scripts in UTF-8. Variables must be in ASCII, but you can include Chinese comments, or Korean strings in your source files. Errors will be retured: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">File "XXX.py", line 3</span><br><span class="line">SyntaxError: Non-ASCII character '\xd6' in file c.py on line 3, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details</span><br></pre></td></tr></table></figure><p>In order for this to work correctly, Python needs to know that your script file is not ASCII. You can place the following special comment in the first or second lines of your script: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python</span></span><br><span class="line"><span class="comment"># -*- coding: UTF-8 -*-</span></span><br></pre></td></tr></table></figure><hr><h3 id="Reading-UTF-8-Files"><a href="#Reading-UTF-8-Files" class="headerlink" title="Reading UTF-8 Files"></a>Reading UTF-8 Files</h3><p>You can manually convert strings that you read from files, however there is an easier way: </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> codecs</span><br><span class="line">fileObj = codecs.open( <span class="string">"someFile"</span>, <span class="string">"r"</span>, <span class="string">"utf-8"</span> )</span><br><span class="line">u = fileObj.read() <span class="comment"># Returns a Unicode string from the UTF-8 bytes in the file</span></span><br></pre></td></tr></table></figure><p>The <a href="https://docs.python.org/2/library/codecs.html" target="_blank" rel="noopener">codecs module</a> will take care of all the conversions for you. You can also open a file for writing and it will convert the Unicode strings you pass in to write into whatever encoding you have chosen.</p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://en.wikipedia.org/wiki/Unicode" target="_blank" rel="noopener">Unicode(Wikipedia)</a><br>[2] <a href="https://stackoverflow.com/questions/18034272/python-str-vs-unicode-types" target="_blank" rel="noopener">Python str vs unicode types</a><br>[3] <a href="https://liguangming.com/how-to-use-utf-8-with-python" target="_blank" rel="noopener">怎么在Python里使用UTF-8编码</a><br>[4] <a href="https://www.v2ex.com/t/163786" target="_blank" rel="noopener">有关 Python 2 和 Sublime Text 中文 Unicode 编码问题的分析与理解</a><br>[5] <a href="http://www.evanjones.ca/python-utf8.html" target="_blank" rel="noopener">How to Use UTF-8 with Python</a><br>[6] <a href="https://stackoverflow.com/questions/2596714/why-does-python-print-unicode-characters-when-the-default-encoding-is-ascii" target="_blank" rel="noopener">Why does Python print unicode characters when the default encoding is ASCII?</a><br>[7] <a href="https://gist.github.com/x7hub/178c87f323fbad57ff91" target="_blank" rel="noopener">Python2字符编码问题小结</a><br>[8] <a href="https://stackoverflow.com/questions/447107/what-is-the-difference-between-encode-decode" target="_blank" rel="noopener">What is the difference between encode/decode?</a><br>[9] <a href="https://stackoverflow.com/questions/18193305/python-unicode-equal-comparison-failed" target="_blank" rel="noopener">Python unicode equal comparison failed</a><br>[10] <a href="https://stackoverflow.com/questions/16471332/how-can-i-compare-a-unicode-type-to-a-string-in-python" target="_blank" rel="noopener">How can I compare a unicode type to a string in python?</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>How to Make Slides with CSS</title>
<link href="/posts/43236/"/>
<content type="html"><![CDATA[<p><a href="https://github.com/impress/impress.js" target="_blank" rel="noopener">impress.js</a> is a presentation framework based on the power of CSS3 transforms and transitions in modern browsers and inspired by the idea behind <a href="https://prezi.com/" target="_blank" rel="noopener">prezi.com</a>.</p><p>CSS is supported by <code>impress</code> to style slides.</p><p><a href="http://impress.github.io/impress.js/#/bored" target="_blank" rel="noopener">Offical demo</a></p><hr><h3 id="Startting"><a href="#Startting" class="headerlink" title="Startting"></a>Startting</h3><p>To use this library, you need to download codes from GitHub, and include <code>impress.js</code> at the end of HTML file.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/impress.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="undefined">impress().init();</span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><hr><h3 id="HTML-class-elements"><a href="#HTML-class-elements" class="headerlink" title="HTML class elements"></a>HTML class elements</h3><p>Every single slide has to be tagged with <code>class="step"</code>, and then <code>impress.js</code> will render it.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"imagination"</span> <span class="attr">class</span>=<span class="string">"step"</span> <span class="attr">data-x</span>=<span class="string">"6700"</span> <span class="attr">data-y</span>=<span class="string">"-300"</span> <span class="attr">data-scale</span>=<span class="string">"6"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>the only <span class="tag"><<span class="name">b</span>></span>limit<span class="tag"></<span class="name">b</span>></span> is your <span class="tag"><<span class="name">b</span> <span class="attr">class</span>=<span class="string">"imagination"</span>></span>imagination<span class="tag"></<span class="name">b</span>></span><span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"source"</span> <span class="attr">class</span>=<span class="string">"step"</span> <span class="attr">data-x</span>=<span class="string">"6300"</span> <span class="attr">data-y</span>=<span class="string">"2000"</span> <span class="attr">data-rotate</span>=<span class="string">"20"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>want to know more?<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">q</span>></span><span class="tag"><<span class="name">a</span> <span class="attr">href</span>=<span class="string">"http://github.com/bartaz/impress.js"</span>></span>use the source<span class="tag"></<span class="name">a</span>></span>, Luke!<span class="tag"></<span class="name">q</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"one"</span> <span class="attr">class</span>=<span class="string">"step"</span> <span class="attr">data-x</span>=<span class="string">"6000"</span> <span class="attr">data-y</span>=<span class="string">"4000"</span> <span class="attr">data-z</span>=<span class="string">"-3000"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>one more thing...<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p><code>data-x</code>, <code>data-y</code> are coordinates for a single slide. (0,0) is screen center.<br><code>data-scale</code> defines the scaling multiplier of elements. <code>data-scale="6"</code> means 6 times larger than others.<br><code>data-rotate</code> represents the amount of clockwise rotation of the element relative to 360 degrees.<br><code>data-z</code> represents depth distance of elements. <code>data-z="-3000"</code> means that element is positioned far away from the camera (by 3000px). This is useful to show hierarchical relations between slides.</p><hr><h3 id="Style-slides"><a href="#Style-slides" class="headerlink" title="Style slides"></a>Style slides</h3><h4 id="Font-family-and-background"><a href="#Font-family-and-background" class="headerlink" title="Font family and background"></a>Font family and background</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">font-family</span>: <span class="string">'PT Sans'</span>, sans-serif;</span><br><span class="line"> <span class="attribute">min-height</span>: <span class="number">740px</span>;</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">rgb</span>(215, 215, 235);</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">-webkit-gradient</span>(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(225, 225, 225)), <span class="built_in">to</span>(rgb(200, 210, 200)));</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">-webkit-radial-gradient</span>(rgb(225, 225, 225), <span class="built_in">rgb</span>(200, 210, 200));</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">-moz-radial-gradient</span>(rgb(225, 225, 225), <span class="built_in">rgb</span>(200, 210, 200));</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">-ms-radial-gradient</span>(rgb(225, 225, 225), <span class="built_in">rgb</span>(200, 210, 200));</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">-o-radial-gradient</span>(rgb(225, 225, 225), <span class="built_in">rgb</span>(200, 210, 200));</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">radial-gradient</span>(rgb(225, 225, 225), <span class="built_in">rgb</span>(200, 210, 200));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Links-format"><a href="#Links-format" class="headerlink" title="Links format"></a>Links format</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">a</span> {</span><br><span class="line"> <span class="attribute">color</span>: inherit;</span><br><span class="line"> <span class="attribute">text-decoration</span>: none;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">0</span> <span class="number">0.1em</span>;</span><br><span class="line"> <span class="comment">/*background: rgba(255,255,255,0.5);*/</span></span><br><span class="line"> <span class="attribute">text-shadow</span>: -<span class="number">1px</span> -<span class="number">1px</span> <span class="number">2px</span> <span class="built_in">rgba</span>(100,100,100,0.9);</span><br><span class="line"> <span class="attribute">border-radius</span>: <span class="number">0.2em</span>;</span><br><span class="line"> <span class="attribute">-webkit-transition</span>: <span class="number">0.5s</span>;</span><br><span class="line"> <span class="attribute">-moz-transition</span>: <span class="number">0.5s</span>;</span><br><span class="line"> <span class="attribute">-ms-transition</span>: <span class="number">0.5s</span>;</span><br><span class="line"> <span class="attribute">-o-transition</span>: <span class="number">0.5s</span>;</span><br><span class="line"> <span class="attribute">transition</span>: <span class="number">0.5s</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">a</span><span class="selector-pseudo">:hover</span>,</span><br><span class="line"><span class="selector-tag">a</span><span class="selector-pseudo">:focus</span> {</span><br><span class="line"> <span class="attribute">background</span>: <span class="built_in">rgba</span>(255,255,255,1);</span><br><span class="line"> <span class="attribute">text-shadow</span>: -<span class="number">1px</span> -<span class="number">1px</span> <span class="number">2px</span> <span class="built_in">rgba</span>(100,100,100,0.5);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Global-style"><a href="#Global-style" class="headerlink" title="Global style"></a>Global style</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.step</span> {</span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">900px</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">40px</span>;</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">20px</span> auto;</span><br><span class="line"> <span class="attribute">-webkit-box-sizing</span>: border-box;</span><br><span class="line"> <span class="attribute">-moz-box-sizing</span>: border-box;</span><br><span class="line"> <span class="attribute">-ms-box-sizing</span>: border-box;</span><br><span class="line"> <span class="attribute">-o-box-sizing</span>: border-box;</span><br><span class="line"> <span class="attribute">box-sizing</span>: border-box;</span><br><span class="line"> <span class="attribute">font-family</span>: <span class="string">'PT Serif'</span>, georgia, serif;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">48px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">1.5</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Transperent-inactive-step"><a href="#Transperent-inactive-step" class="headerlink" title="Transperent inactive step"></a>Transperent inactive step</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.impress-enabled</span> <span class="selector-class">.step</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">opacity</span>: <span class="number">0.3</span>;</span><br><span class="line"> <span class="attribute">-webkit-transition</span>: opacity <span class="number">1s</span>;</span><br><span class="line"> <span class="attribute">-moz-transition</span>: opacity <span class="number">1s</span>;</span><br><span class="line"> <span class="attribute">-ms-transition</span>: opacity <span class="number">1s</span>;</span><br><span class="line"> <span class="attribute">-o-transition</span>: opacity <span class="number">1s</span>;</span><br><span class="line"> <span class="attribute">transition</span>: opacity <span class="number">1s</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.impress-enabled</span> <span class="selector-class">.step</span><span class="selector-class">.active</span> { <span class="attribute">opacity</span>: <span class="number">1</span> }</span><br></pre></td></tr></table></figure><h4 id="Normal-slide-style"><a href="#Normal-slide-style" class="headerlink" title="Normal slide style"></a>Normal slide style</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.slide</span> {</span><br><span class="line"> <span class="attribute">display</span>: block;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">900px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">700px</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">40px</span> <span class="number">60px</span>;</span><br><span class="line"> <span class="attribute">background-color</span>: white;</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="built_in">rgba</span>(0, 0, 0, .3);</span><br><span class="line"> <span class="attribute">border-radius</span>: <span class="number">10px</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">2px</span> <span class="number">6px</span> <span class="built_in">rgba</span>(0, 0, 0, .1);</span><br><span class="line"> <span class="attribute">color</span>: <span class="built_in">rgb</span>(102, 102, 102);</span><br><span class="line"> <span class="attribute">text-shadow</span>: <span class="number">0</span> <span class="number">2px</span> <span class="number">2px</span> <span class="built_in">rgba</span>(0, 0, 0, .1);</span><br><span class="line"> <span class="attribute">font-family</span>: <span class="string">'Open Sans'</span>, Arial, sans-serif;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">30px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">36px</span>;</span><br><span class="line"> <span class="attribute">letter-spacing</span>: -<span class="number">1px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="States-styling"><a href="#States-styling" class="headerlink" title="States styling"></a>States styling</h4><p><code>.future</code> class is added to all elements that havn’t been visited yet. <code>.present</code> class is added to the <code>step</code> currently on show. <code>.past</code> class is added to all the elements have been visited. </p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.past</span> {</span><br><span class="line"> <span class="attribute">display</span>: none;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="3D-clickable-in-Chrome"><a href="#3D-clickable-in-Chrome" class="headerlink" title="3D clickable in Chrome"></a>3D clickable in Chrome</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.impress-enabled</span> { <span class="attribute">pointer-events</span>: none }</span><br><span class="line"><span class="selector-class">.impress-enabled</span> <span class="selector-id">#impress</span> { <span class="attribute">pointer-events</span>: auto }</span><br></pre></td></tr></table></figure><h4 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#overview</span> { <span class="attribute">display</span>: none }</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* make other steps visible and give them a pointer cursor using the `impress-on-` class.</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="selector-class">.impress-on-overview</span> <span class="selector-class">.step</span> {</span><br><span class="line"> <span class="attribute">opacity</span>: <span class="number">1</span>;</span><br><span class="line"> <span class="attribute">cursor</span>: pointer;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><hr><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="https://github.com/impress/impress.js/blob/master/DOCUMENTATION.md" target="_blank" rel="noopener">impress.js API documentation</a></p>]]></content>
<categories>
<category> CSS </category>
</categories>
</entry>
<entry>
<title>How to Use Raphaël to Create Responsive SVG</title>
<link href="/posts/21614/"/>
<content type="html"><![CDATA[<p><a href="http://dmitrybaranovskiy.github.io/raphael/" target="_blank" rel="noopener">Raphaël</a> is a small JavaScript library that should simplify your work with vector graphics on the web.<br>It uses <a href="https://en.wikipedia.org/wiki/Scalable_Vector_Graphics" target="_blank" rel="noopener">SVG</a> for creating graphics.</p><hr><h3 id="SVG-and-Canvas"><a href="#SVG-and-Canvas" class="headerlink" title="SVG and Canvas"></a>SVG and Canvas</h3><p>SVG(Scalable Vector Graphics) is an XML-based image format that is used to define two-dimensional <strong>vector</strong> based graphics for the Web. It is scalability, can be printed with high quality at any resolution.</p><p>Canvas is <strong>raster</strong> based image format, like bitmaps, used to visual images on the fly.</p><p>SVG and Canvas have several methods for drawing paths, boxes, circles, text, and graphic images.</p><ul><li><p>SVG:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">svg</span> <span class="attr">width</span>=<span class="string">"100"</span> <span class="attr">height</span>=<span class="string">"100"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">circle</span> <span class="attr">cx</span>=<span class="string">"50"</span> <span class="attr">cy</span>=<span class="string">"50"</span> <span class="attr">r</span>=<span class="string">"40"</span> <span class="attr">stroke</span>=<span class="string">"green"</span> <span class="attr">stroke-width</span>=<span class="string">"4"</span> <span class="attr">fill</span>=<span class="string">"yellow"</span> /></span></span><br><span class="line"><span class="tag"></<span class="name">svg</span>></span></span><br></pre></td></tr></table></figure></li><li><p>Canvas:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> c = <span class="xml"><span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"built_in"</span>></span>document.getElementById("myCanvas");</span></span><br><span class="line"><span class="xml">var ctx = c.getContext("2d");</span></span><br><span class="line"><span class="xml">ctx.moveTo(0,0);</span></span><br><span class="line"><span class="xml">ctx.lineTo(200,100);</span></span><br><span class="line"><span class="xml">ctx.stroke();</span></span><br></pre></td></tr></table></figure></li></ul><p>SVG can be drawn by other generators, like Illustrator or some online generator. After finished, codes can be included in HTML file. It can be mofified by script and CSS. Canvas image is using JS as a pen to draw something on webpage. It can be modified only by script.</p><hr><h3 id="Raphael-elementary"><a href="#Raphael-elementary" class="headerlink" title="Raphaël elementary"></a>Raphaël elementary</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Each of the following examples create a canvas</span></span><br><span class="line"><span class="comment">// that is 320px wide by 200px high.</span></span><br><span class="line"><span class="comment">// Canvas is created at the viewport’s 10,50 coordinate.</span></span><br><span class="line"><span class="keyword">var</span> paper = Raphael(<span class="number">10</span>, <span class="number">50</span>, <span class="number">320</span>, <span class="number">200</span>);</span><br><span class="line"><span class="comment">// Canvas is created at the top left corner of the #diagram element</span></span><br><span class="line"><span class="comment">// (or its top right corner in dir="rtl" elements)</span></span><br><span class="line"><span class="keyword">var</span> paper = Raphael(<span class="built_in">document</span>.getElementById(<span class="string">"diagram"</span>), <span class="number">320</span>, <span class="number">200</span>);</span><br><span class="line"><span class="comment">// Same as above</span></span><br><span class="line"><span class="keyword">var</span> paper = Raphael(<span class="string">"diagram"</span>, <span class="number">320</span>, <span class="number">200</span>);</span><br><span class="line"><span class="comment">// Image dump</span></span><br><span class="line"><span class="keyword">var</span> set = Raphael([<span class="string">"diagram"</span>, <span class="number">320</span>, <span class="number">200</span>, {</span><br><span class="line"> type: <span class="string">"rect"</span>,</span><br><span class="line"> x: <span class="number">10</span>,</span><br><span class="line"> y: <span class="number">10</span>,</span><br><span class="line"> width: <span class="number">25</span>,</span><br><span class="line"> height: <span class="number">25</span>,</span><br><span class="line"> stroke: <span class="string">"#f00"</span></span><br><span class="line">}, {</span><br><span class="line"> type: <span class="string">"text"</span>,</span><br><span class="line"> x: <span class="number">30</span>,</span><br><span class="line"> y: <span class="number">40</span>,</span><br><span class="line"> text: <span class="string">"Dump"</span></span><br><span class="line">}]);</span><br></pre></td></tr></table></figure><hr><h3 id="Method-1"><a href="#Method-1" class="headerlink" title="Method 1"></a>Method 1</h3><p>Getting window size, and set every graphic parameters into relative length: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> windowWidth = $(<span class="built_in">window</span>).width();</span><br><span class="line"><span class="keyword">var</span> windowHeight = $(<span class="built_in">window</span>).height();</span><br><span class="line"><span class="comment">// parameters for graphic</span></span><br><span class="line"><span class="keyword">var</span> viewboxLength = (windowWidth > windowHeight ? windowHeight : windowWidth)*<span class="number">0.9</span>;</span><br><span class="line"><span class="keyword">var</span> centerX = viewboxLength/<span class="number">2</span>;</span><br><span class="line"><span class="keyword">var</span> centerY = viewboxLength/<span class="number">2</span>;</span><br><span class="line"><span class="keyword">var</span> radius = viewboxLength/<span class="number">5</span>;</span><br><span class="line"><span class="keyword">var</span> storkeWidthG = viewboxLength/<span class="number">20</span>;</span><br><span class="line"><span class="keyword">var</span> paper = Raphael(<span class="string">'diagram'</span>, viewboxLength, viewboxLength), <span class="comment">// Raphael('DOM container', width, height)</span></span><br><span class="line"> rad = radius, <span class="comment">//radius of first arc</span></span><br><span class="line"> defaultText = <span class="string">'Spatial-temporal analysis'</span>,</span><br><span class="line"> speed = <span class="number">250</span>;</span><br></pre></td></tr></table></figure><hr><h3 id="Method-2"><a href="#Method-2" class="headerlink" title="Method 2"></a>Method 2</h3><p>Raphaël supplies with <code>.setViewBox(x, y, w, h, fit)</code> to adjust SVG size.<br><code>x</code>(number) new x position, default is 0.<br><code>y</code>(number) new y position, default is 0.<br><code>w</code>(number) new width of the canvas<br><code>h</code>(number) new height of the canvas<br><code>fit</code>(boolean) <code>true</code> if you want graphics to fit into new boundary box</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> windowWidth = $(<span class="built_in">window</span>).width();</span><br><span class="line"><span class="keyword">var</span> windowHeight = $(<span class="built_in">window</span>).height();</span><br><span class="line"><span class="keyword">var</span> paper = Raphael(<span class="string">'diagram'</span>, viewboxLength, viewboxLength), <span class="comment">// Raphael('DOM container', width, height)</span></span><br><span class="line"> rad = radius, <span class="comment">//radius of first arc</span></span><br><span class="line"> defaultText = <span class="string">'Spatial-temporal analysis'</span>,</span><br><span class="line"> speed = <span class="number">250</span>;</span><br><span class="line"><span class="comment">// where svg size is adjusted</span></span><br><span class="line">paper.setViewBox(x, y, windowWidth, windowHeight, <span class="literal">true</span>);</span><br></pre></td></tr></table></figure><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://stackoverflow.com/questions/11176396/how-can-i-scale-raphael-js-elements-on-window-resize-using-jquery" target="_blank" rel="noopener">How Can i scale Raphael js elements on window resize using jquery</a><br>[2] <a href="https://www.sitepoint.com/canvas-vs-svg-choosing-the-right-tool-for-the-job/" target="_blank" rel="noopener">What is HTML5 Canvas?</a><br>[3] <a href="http://dmitrybaranovskiy.github.io/raphael/reference.html" target="_blank" rel="noopener">Raphaël Reference</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
</entry>
<entry>
<title>Postgres Load Data and Query</title>
<link href="/posts/5297/"/>
<content type="html"><![CDATA[<h3 id="Load-data"><a href="#Load-data" class="headerlink" title="Load data"></a>Load data</h3><p><a href="https://github.com/pudo/pgcsv" target="_blank" rel="noopener"><code>pgcsv</code></a> is used for load <code>csv</code> data into <code>Postgres</code>. </p><p>Input <code>bash</code> in ternimal:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ pip install pgcsv</span><br><span class="line">$ pgcsv --db postgresql://localhost/database new_table csv_file.csv</span><br></pre></td></tr></table></figure><p>With <code>pgcvs</code> default data type would be <code>text</code>.</p><hr><h3 id="Query"><a href="#Query" class="headerlink" title="Query"></a>Query</h3><p>Login database in ternimal: </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -d database</span><br></pre></td></tr></table></figure><p>List all current tables: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\d</span><br></pre></td></tr></table></figure><p>Getting infomation of a table: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\d+ tablename</span><br></pre></td></tr></table></figure><p>Checking top 1000 recordes: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> * <span class="keyword">from</span> whole_year <span class="keyword">limit</span> <span class="number">1000</span>;</span><br></pre></td></tr></table></figure><p>Counting row number: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="keyword">count</span>(*) <span class="keyword">from</span> whole;</span><br></pre></td></tr></table></figure><p>Combining tables: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> table1 <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> table2;</span><br></pre></td></tr></table></figure><p>Exclud some rows from extra table: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">FROM</span> tabA </span><br><span class="line"><span class="keyword">WHERE</span> <span class="keyword">id</span> <span class="keyword">not</span> <span class="keyword">in</span> (<span class="keyword">SELECT</span> <span class="keyword">id</span> <span class="keyword">FROM</span> tabB);</span><br></pre></td></tr></table></figure><hr><h3 id="Alter"><a href="#Alter" class="headerlink" title="Alter"></a><a href="#Alter" title="Alter"></a>Alter</h3><h4 id="Rename"><a href="#Rename" class="headerlink" title="Rename"></a><a href="#Rename" title="Rename"></a>Rename</h4><p>Table rename: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> distributors <span class="keyword">RENAME</span> <span class="keyword">TO</span> suppliers;</span><br></pre></td></tr></table></figure><h4 id="Convert-data-type"><a href="#Convert-data-type" class="headerlink" title="Convert data type"></a>Convert data type</h4><p><code>postgres</code> numeric types</p><table><thead><tr><th>Name</th><th style="text-align:center">Storage Size</th><th style="text-align:right">Range</th></tr></thead><tbody><tr><td>small int</td><td style="text-align:center">2 bytes</td><td style="text-align:right">-32768 to +32767</td></tr><tr><td>integer</td><td style="text-align:center">4 bytes</td><td style="text-align:right">-2147483648 to +2147483647</td></tr><tr><td>bigint</td><td style="text-align:center">8 bytes</td><td style="text-align:right">-9223372036854775808 to +9223372036854775807</td></tr><tr><td>decimal</td><td style="text-align:center">variable</td><td style="text-align:right">up to 131072 digits before the decimal point; up to 16383 digits after the decimal point</td></tr><tr><td>numeric</td><td style="text-align:center">variable</td><td style="text-align:right">up to 131072 digits before the decimal point; up to 16383 digits after the decimal point</td></tr><tr><td>double</td><td style="text-align:center">precision</td><td style="text-align:right">8 bytes 15 decimal digits precision</td></tr></tbody></table><hr><p><code>Text</code> to <code>numeric</code> </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> whole <span class="keyword">ALTER</span> <span class="keyword">COLUMN</span> wgs84latitude <span class="keyword">TYPE</span> <span class="built_in">numeric</span>(<span class="number">17</span>,<span class="number">15</span>) <span class="keyword">USING</span> wgs84latitude::<span class="built_in">numeric</span>(<span class="number">17</span>,<span class="number">15</span>);</span><br></pre></td></tr></table></figure><p><code>numeric{m,d}</code>, where <code>m</code> is the total digits and <code>d</code> is the number of digits after the decimal.</p><hr><h3 id="Create-new-table"><a href="#Create-new-table" class="headerlink" title="Create new table"></a>Create new table</h3><p>Create new table from exist tables. </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> firstSeason <span class="keyword">AS</span> <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> whole <span class="keyword">WHERE</span> createdatunixtime <= <span class="number">1396310399</span>;</span><br></pre></td></tr></table></figure><hr><h3 id="Drop-table"><a href="#Drop-table" class="headerlink" title="Drop table"></a>Drop table</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> table1, table2;</span><br></pre></td></tr></table></figure><hr><h3 id="Select-difference"><a href="#Select-difference" class="headerlink" title="Select difference"></a>Select difference</h3><p>IF you have tables A and B, both with colum C, here are the records, which are present in table A but not in B: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> A.*</span><br><span class="line"><span class="keyword">FROM</span> A</span><br><span class="line"> <span class="keyword">LEFT</span> <span class="keyword">JOIN</span> B <span class="keyword">ON</span> (A.C = B.C)</span><br><span class="line"><span class="keyword">WHERE</span> B.C <span class="keyword">IS</span> <span class="literal">NULL</span></span><br></pre></td></tr></table></figure><p>To get all the differences with a single query, a full join must be used, like this: </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> A.*, B.*</span><br><span class="line"><span class="keyword">FROM</span> A</span><br><span class="line"> <span class="keyword">FULL</span> <span class="keyword">JOIN</span> B <span class="keyword">ON</span> (A.C = B.C)</span><br><span class="line"><span class="keyword">WHERE</span> A.C <span class="keyword">IS</span> <span class="literal">NULL</span> <span class="keyword">OR</span> B.C <span class="keyword">IS</span> <span class="literal">NULL</span></span><br></pre></td></tr></table></figure><hr><h3 id="Export-data"><a href="#Export-data" class="headerlink" title="Export data"></a>Export data</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">COPY tablename to 'absolute file path.csv' delimiters',';</span><br></pre></td></tr></table></figure><h3 id="References"><a href="#References" class="headerlink" title="References"></a>References</h3><p>[1] <a href="https://www.postgresql.org/docs/9.1/static/sql-altertable.html" target="_blank" rel="noopener">PostgreSQL 9.1.24 Documentation</a><br>[2] <a href="https://www.techonthenet.com/postgresql/datatypes.php" target="_blank" rel="noopener">PostgreSQL: Data Types</a><br>[3] <a href="https://stackoverflow.com/questions/13170570/change-type-of-varchar-field-to-integer-cannot-be-cast-automatically-to-type-i" target="_blank" rel="noopener">Change type of varchar field to integer: “cannot be cast automatically to type integer”</a><br>[4] <a href="https://stackoverflow.com/questions/1120109/export-postgres-table-to-csv-file-with-headings" target="_blank" rel="noopener">Export Postgres table to CSV file with headings</a><br>[5] <a href="https://stackoverflow.com/questions/8119297/postgresql-export-resulting-data-from-sql-query-to-excel-csv" target="_blank" rel="noopener">PostgreSQL: export resulting data from SQL query to Excel/CSV</a><br>[6] <a href="https://stackoverflow.com/questions/2077807/sql-query-to-return-differences-between-two-tables" target="_blank" rel="noopener">sql query to return differences between two tables</a></p>]]></content>
<categories>
<category> Database </category>
</categories>
</entry>
<entry>
<title>Hot Keys for Vim</title>
<link href="/posts/13963/"/>
<content type="html"><![CDATA[<h3 id="Hot-keys"><a href="#Hot-keys" class="headerlink" title="Hot keys"></a>Hot keys</h3><p>Just some Vim essential notes for learning use. :)</p><hr><ul><li>Open a file <code>vim 'filename'</code></li><li>Close a file <code>:q</code></li><li>Force quit a file without save <code>:q!</code></li><li>Save file <code>:w</code></li><li>Save and quit <code>:wq</code></li></ul><p>Under <code>COMMAND</code> mode:</p><ul><li>Left <code>h</code></li><li>Down <code>j</code></li><li>Up <code>k</code></li><li>Right <code>l</code></li><li>Next page: <code>control + b(back)</code></li><li>Previous page: <code>control + f(front)</code></li></ul><p><code>INSERT</code> mode:</p><ul><li>Enter <code>insert</code> mode <code>i</code></li><li>Quit <code>esc</code></li></ul><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://coolshell.cn/articles/5426.html" target="_blank" rel="noopener">简明 VIM 练级攻略</a></p>]]></content>
</entry>
<entry>
<title>Convert Datetime To Timestamp in Python</title>
<link href="/posts/40441/"/>
<content type="html"><![CDATA[<h3 id="What-is-Timestamp"><a href="#What-is-Timestamp" class="headerlink" title="What is Timestamp"></a>What is Timestamp</h3><p>The unix time stamp is a way to track time as a running total of seconds. This count starts at the Unix Epoch on January 1st, 1970 at UTC. </p><p>It should also be pointed out that this point in time technically does not change no matter where you are located on the globe.</p><hr><h3 id="Convert-String-date-to-Timestamp"><a href="#Convert-String-date-to-Timestamp" class="headerlink" title="Convert String date to Timestamp"></a>Convert String date to Timestamp</h3><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> division</span><br><span class="line"><span class="keyword">import</span> datetime</span><br><span class="line"></span><br><span class="line">td = datetime.datetime(<span class="number">2014</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">06</span>,<span class="number">0</span>,<span class="number">02</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">totimestamp</span><span class="params">(dt, epoch=datetime.datetime<span class="params">(<span class="number">1970</span>,<span class="number">1</span>,<span class="number">1</span>)</span>)</span>:</span></span><br><span class="line"> td = dt - epoch</span><br><span class="line"> <span class="comment"># return td.total_seconds()</span></span><br><span class="line"> <span class="keyword">return</span> (td.microseconds + (td.seconds + td.days * <span class="number">86400</span>) * <span class="number">10</span>**<span class="number">6</span>) / <span class="number">10</span>**<span class="number">6</span> </span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> totimestamp(td)</span><br><span class="line"></span><br><span class="line"><span class="comment">#######################################################################</span></span><br><span class="line"><span class="comment"># result</span></span><br><span class="line"><span class="comment"># 1388556002.0</span></span><br></pre></td></tr></table></figure><p><strong>WRONG VERSION</strong><br><a href="https://docs.python.org/2/library/time.html" target="_blank" rel="noopener"><code>time</code></a> module is for time access and conversions.<br><a href="https://docs.python.org/2/library/datetime.html#module-datetime" target="_blank" rel="noopener"><code>datetime</code></a> module is for basic date and time types. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> datetime</span><br><span class="line"></span><br><span class="line"><span class="comment"># default time duration, formatting: "DD/MM/YYYY"</span></span><br><span class="line">mDateStart = <span class="string">'01/01/2014 06:00:02'</span> <span class="comment"># 1388505600</span></span><br><span class="line">mDateEnd = <span class="string">'02/01/2014'</span> <span class="comment"># 1388592000</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># date 'DD/MM/YYYY HH:MM:SS'</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">date2Unix</span><span class="params">(date)</span>:</span></span><br><span class="line"> unixTime = time.mktime(datetime.datetime.strptime(date, <span class="string">"%d/%m/%Y %H:%M:%S"</span>).timetuple()) <span class="comment"># DO NOT USE IT WITH UTC DATE</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> unixTime</span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> date2Unix(mDateStart)</span><br><span class="line"></span><br><span class="line"><span class="comment">#########################################################################</span></span><br><span class="line"><span class="comment"># result</span></span><br><span class="line"><span class="comment"># 1388552402.0</span></span><br></pre></td></tr></table></figure><p><code>datetime.strptime()</code> return a <code>datetime</code> parsed accroding to <code>format</code>.<br><code>.utctimetuple()</code> complete time obj with full 9-tuple, default adding numbers as <code>0</code>, equivalent to <code>time.struct_time((d.year, d.month, d.day, 0, 0, 0, d.weekday(), yday, -1))</code><br><code>time.mktime()</code> takes argument as full 9-tuple time obj, and returns a floating point number.</p><blockquote><p><code>mktime()</code> may return a wrong result if <code>d</code> corresponds to <a href="https://stackoverflow.com/questions/12165691/python-datetime-with-timezone-to-epoch/12166400#comment39565270_12166400" target="_blank" rel="noopener">an ambiguous local time (e.g., during DST transition)</a> or if <code>d</code> is a past(future) date when the utc offset might have been different and the C <code>mktime()</code> has no access to the <a href="http://www.iana.org/time-zones/repository/tz-link.html" target="_blank" rel="noopener">tz database</a> on the given platform.</p></blockquote><hr><h3 id="Python-Timezone"><a href="#Python-Timezone" class="headerlink" title="Python Timezone"></a>Python Timezone</h3><p><a href="https://pypi.python.org/pypi/pytz" target="_blank" rel="noopener"><code>pytz</code></a> module can be used for time localization, date arithmetic and etc.<br><code>pytz.country_timezones('country code')</code> could return a list of time zone names. We can new a <code>tzinfo</code> with <code>pytz.timezone('time zone name')</code>. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>>> </span>timeZone = pytz.country_timezones(<span class="string">'cn'</span>)</span><br><span class="line"><span class="meta">>>> </span>pytz.timezone(timeZone[<span class="number">0</span>])</span><br><span class="line"><DstTzInfo <span class="string">'Asia/Shanghai'</span> LMT+<span class="number">8</span>:<span class="number">06</span>:<span class="number">00</span> STD></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>pytz.timezone(timeZone[<span class="number">1</span>])</span><br><span class="line"><DstTzInfo <span class="string">'Asia/Harbin'</span> LMT+<span class="number">8</span>:<span class="number">27</span>:<span class="number">00</span> STD></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>pytz.timezone(timeZone[<span class="number">2</span>])</span><br><span class="line"><DstTzInfo <span class="string">'Asia/Chongqing'</span> LMT+<span class="number">7</span>:<span class="number">06</span>:<span class="number">00</span> STD></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>pytz.timezone(timeZone[<span class="number">3</span>])</span><br><span class="line"><DstTzInfo <span class="string">'Asia/Urumqi'</span> LMT+<span class="number">5</span>:<span class="number">50</span>:<span class="number">00</span> STD></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>pytz.timezone(timeZone[<span class="number">4</span>])</span><br><span class="line"><DstTzInfo <span class="string">'Asia/Kashgar'</span> LMT+<span class="number">5</span>:<span class="number">04</span>:<span class="number">00</span> STD></span><br><span class="line"></span><br><span class="line"><span class="meta">>>> </span>tz = pytz.timezone(pytz.country_timezones(<span class="string">'tw'</span>)[<span class="number">0</span>])</span><br><span class="line"><span class="meta">>>> </span>tz</span><br><span class="line"><DstTzInfo <span class="string">'Asia/Taipei'</span> CST+<span class="number">8</span>:<span class="number">00</span>:<span class="number">00</span> STD></span><br></pre></td></tr></table></figure><p>The wired thing is, there’s always a time offset between any Chinese local times and Beijing local time. But when it comes to Taipei local time, it’s the same with Beijing local time. Then we can use Taipei time as a alternative.</p><hr><h3 id="Local-time-2-UTC-time"><a href="#Local-time-2-UTC-time" class="headerlink" title="Local time 2 UTC time"></a>Local time 2 UTC time</h3><p><code>UTCtime = Localtime - timezone</code><br>E.g. Beijing local time 18:00, UTCtime = 18:00 - (+ 08:00) = 10:00 + 00:00, so UTC time is 10:00. </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"># argument1 should be String 'DD/MM/YYYY', zoneName e.g. 'Asia/Shanghai', 'Asia/Taipei'</span><br><span class="line"></span><br><span class="line">def locT2utcT(time, zoneName):</span><br><span class="line"></span><br><span class="line"> local = pytz.timezone (zoneName)</span><br><span class="line"></span><br><span class="line"> naiveTime = datetime.datetime.strptime(time, "%d/%m/%Y %H:%M:%S")</span><br><span class="line"></span><br><span class="line"> local_dt = local.localize(naiveTime, is_dst=None)</span><br><span class="line"></span><br><span class="line"> utc_dt = local_dt.astimezone(pytz.utc)</span><br><span class="line"></span><br><span class="line"> utc_dt = utc_dt.strftime ("%d/%m/%Y %H:%M:%S")</span><br><span class="line"></span><br><span class="line"> return utc_dt</span><br></pre></td></tr></table></figure><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://www.unixtimestamp.com/" target="_blank" rel="noopener">Epoch Unix Time Stamp Converter</a><br>[2] <a href="https://stackoverflow.com/questions/9637838/convert-string-date-to-timestamp-in-python" target="_blank" rel="noopener">StackOverFlow: Convert string date to timestamp in Python</a><br>[3] <a href="https://www.keakon.net/2010/12/14/%E7%94%A8datetime%E5%92%8Cpytz%E6%9D%A5%E8%BD%AC%E6%8D%A2%E6%97%B6%E5%8C%BA" target="_blank" rel="noopener">用datetime和pytz来转换时区</a><br>[4] <a href="https://stackoverflow.com/questions/8777753/converting-datetime-date-to-utc-timestamp-in-python" target="_blank" rel="noopener">StackOverFlow: Converting datetime.date to UTC timestamp in Python</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>Using Geojson to Draw a Map</title>
<link href="/posts/41737/"/>
<content type="html"><![CDATA[<h3 id="Why-Leaflet"><a href="#Why-Leaflet" class="headerlink" title="Why Leaflet"></a>Why Leaflet</h3><p>Leaflet is an open-source JavaScript library, which supply so many plugins we can use for map making.<br>Based on Leaflet, geojson is even more friendly to geo-data visualization. <a href="http://leafletjs.com/plugins.html" target="_blank" rel="noopener">Tutorials</a> are easy to follow.</p><hr><h3 id="Draw-Points"><a href="#Draw-Points" class="headerlink" title="Draw Points"></a>Draw Points</h3><p>Firstly, we include JavaScript packages: </p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">'https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.js'</span>></span><span class="javascript"><span <span class="class"><span class="keyword">class</span></span>=<span class="string">"xml"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">href</span>=<span class="string">'https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.css'</span> <span class="attr">rel</span>=<span class="string">'stylesheet'</span> /></span></span><br></pre></td></tr></table></figure><p>Then draw base map, we use <code>Mapbox</code> in this case: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// using Leaflet API</span></span><br><span class="line"></span><br><span class="line">L.mapbox.accessToken = <span class="string">'your token'</span>;</span><br><span class="line"><span class="keyword">var</span> map = L.mapbox.map(<span class="string">'map'</span>)</span><br><span class="line"> .setView([<span class="number">31.22</span>, <span class="number">121.48</span>], <span class="number">10</span> )</span><br><span class="line"> .addLayer(L.mapbox.tileLayer(<span class="string">'mapbox.dark'</span>));</span><br></pre></td></tr></table></figure><p>Setting for points’ propoties: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> geojsonMarkerOptions = {</span><br><span class="line"> radius: <span class="number">8</span>,</span><br><span class="line"> fillColor: <span class="string">"#ff0000"</span>,</span><br><span class="line"> color: <span class="string">"#000"</span>,</span><br><span class="line"> weight: <span class="number">1</span>,</span><br><span class="line"> opacity: <span class="number">1</span>,</span><br><span class="line"> fillOpacity: <span class="number">0.5</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>Then load geojson file and parse it. <code>L.geoJSON</code> will parse our geojson file, create a geojson layer. <code>pointToLayer</code> is a function used for points visualizaiotn. The first augment <code>feature</code> is means <code>feature</code>s in geojson, the second augment <code>latlng</code> stands for location information included in geojson. If geojson file is nicely formatted, then location will be automatically parsed here. Default is to spawn a marker. </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">$.getJSON(<span class="string">"filepath.geojson"</span>,<span class="function"><span class="keyword">function</span>(<span class="params">Data</span>)</span>{</span><br><span class="line">L.geoJSON(Data, {</span><br><span class="line"> pointToLayer: <span class="function"><span class="keyword">function</span> (<span class="params">feature, latlng</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> L.circleMarker(latlng, geojsonMarkerOptions);</span><br><span class="line"> }</span><br><span class="line">}).addTo(map);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><img src="/images/geojsonPoints.png" alt="Points"></p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://bl.ocks.org/nickpeihl/c8ecb33fcc47dbd4b08e336e6a70aad6" target="_blank" rel="noopener">Heatmap example using Open Data from San Juan County WA and Mapbox-GL.js</a><br>[2] <a href="http://leafletjs.com/reference-1.0.3.html#geojson" target="_blank" rel="noopener">Leaflet API Reference</a></p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
</entry>
<entry>
<title>Convert CSV to Geojson in Python</title>
<link href="/posts/56646/"/>
<content type="html"><![CDATA[<h3 id="What-is-Geojson"><a href="#What-is-Geojson" class="headerlink" title="What is Geojson"></a>What is Geojson</h3><p>According to wikipedia, GeoJSON is an open standard format designed for representing simple geographical features, along with their non-spatial attributes, based on JavaScript Object Notation.</p><p>Simply, Geojson is a JavaScript friendly geo-related data format, which uauslly contain points, polylines, polygons and other properties.It’s easy to to make visualization on webpage. There are so many packages supply API for geojson, <a href="leafletjs.com">Leaflet</a>, <a href="https://www.mapbox.com/" target="_blank" rel="noopener">MapBox</a>, and etc. And of course you can easily parse it with <code>jQuery</code>.</p><p>Geojson is stick on its format. There’s websites where you can check the format.Here’s an example from offical <a href="https://tools.ietf.org/html/rfc7946" target="_blank" rel="noopener">website</a>. </p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"FeatureCollection"</span>,</span><br><span class="line"> <span class="attr">"features"</span>: [{</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Feature"</span>,</span><br><span class="line"> <span class="attr">"geometry"</span>: {</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Point"</span>,</span><br><span class="line"> <span class="attr">"coordinates"</span>: [<span class="number">102.0</span>, <span class="number">0.5</span>]</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"properties"</span>: {</span><br><span class="line"> <span class="attr">"prop0"</span>: <span class="string">"value0"</span></span><br><span class="line"> }</span><br><span class="line"> }, {</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Feature"</span>,</span><br><span class="line"> <span class="attr">"geometry"</span>: {</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"LineString"</span>,</span><br><span class="line"> <span class="attr">"coordinates"</span>: [</span><br><span class="line"> [<span class="number">102.0</span>, <span class="number">0.0</span>],</span><br><span class="line"> [<span class="number">103.0</span>, <span class="number">1.0</span>],</span><br><span class="line"> [<span class="number">104.0</span>, <span class="number">0.0</span>],</span><br><span class="line"> [<span class="number">105.0</span>, <span class="number">1.0</span>]</span><br><span class="line"> ]</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"properties"</span>: {</span><br><span class="line"> <span class="attr">"prop0"</span>: <span class="string">"value0"</span>,</span><br><span class="line"> <span class="attr">"prop1"</span>: <span class="number">0.0</span></span><br><span class="line"> }</span><br><span class="line"> }, {</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Feature"</span>,</span><br><span class="line"> <span class="attr">"geometry"</span>: {</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"Polygon"</span>,</span><br><span class="line"> <span class="attr">"coordinates"</span>: [</span><br><span class="line"> [</span><br><span class="line"> [<span class="number">100.0</span>, <span class="number">0.0</span>],</span><br><span class="line"> [<span class="number">101.0</span>, <span class="number">0.0</span>],</span><br><span class="line"> [<span class="number">101.0</span>, <span class="number">1.0</span>],</span><br><span class="line"> [<span class="number">100.0</span>, <span class="number">1.0</span>],</span><br><span class="line"> [<span class="number">100.0</span>, <span class="number">0.0</span>]</span><br><span class="line"> ]</span><br><span class="line"> ]</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"properties"</span>: {</span><br><span class="line"> <span class="attr">"prop0"</span>: <span class="string">"value0"</span>,</span><br><span class="line"> <span class="attr">"prop1"</span>: {</span><br><span class="line"> <span class="attr">"this"</span>: <span class="string">"that"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }]</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><hr><h3 id="Convertation"><a href="#Convertation" class="headerlink" title="Convertation"></a>Convertation</h3><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> csv</span><br><span class="line"></span><br><span class="line"><span class="comment"># Read in raw data from csv</span></span><br><span class="line">rawData = csv.reader(open(<span class="string">'filename.csv'</span>, <span class="string">'rb'</span>), dialect=<span class="string">'excel'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># the template. where data from the csv will be formatted to geojson</span></span><br><span class="line">template = \</span><br><span class="line"> <span class="string">''' \</span></span><br><span class="line"><span class="string"> { "type" : "Feature",</span></span><br><span class="line"><span class="string"> "geometry" : {</span></span><br><span class="line"><span class="string"> "type" : "Point",</span></span><br><span class="line"><span class="string"> "coordinates" : [%s, %s]},</span></span><br><span class="line"><span class="string"> "properties" : { "id" : %s, "unixTime" : "%s", "msgtext" : "%s", "userID": "%s"}</span></span><br><span class="line"><span class="string"> },</span></span><br><span class="line"><span class="string"> '''</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># the head of the geojson file</span></span><br><span class="line">output = \</span><br><span class="line"> <span class="string">''' \</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">{ "type" : "Feature Collection",</span></span><br><span class="line"><span class="string"> "features" : [</span></span><br><span class="line"><span class="string"> '''</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># loop through the csv by row skipping the first</span></span><br><span class="line">iter = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> row <span class="keyword">in</span> rawData:</span><br><span class="line"> <span class="comment"># iter += 1</span></span><br><span class="line"> <span class="comment"># if iter >= 2:</span></span><br><span class="line"> id = row[<span class="number">2</span>]</span><br><span class="line"> lat = row[<span class="number">5</span>]</span><br><span class="line"> lon = row[<span class="number">6</span>]</span><br><span class="line"> unixTime = row[<span class="number">1</span>]</span><br><span class="line"> msgtext = row[<span class="number">3</span>]</span><br><span class="line"> userID = row[<span class="number">4</span>]</span><br><span class="line"> <span class="comment"># output += template % (row[0], row[2], row[1], row[3], row[4])</span></span><br><span class="line"> output += template % (lon, lat, id, unixTime, msgtext, userID)</span><br><span class="line"></span><br><span class="line"><span class="comment"># the tail of the geojson file</span></span><br><span class="line">output += \</span><br><span class="line"> <span class="string">''' \</span></span><br><span class="line"><span class="string"> ]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">}</span></span><br><span class="line"><span class="string"> '''</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># opens an geoJSON file to write the output</span></span><br><span class="line">outFileHandle = open(<span class="string">"filename.geojson"</span>, <span class="string">"w"</span>)</span><br><span class="line">outFileHandle.write(output)</span><br><span class="line">outFileHandle.close()</span><br></pre></td></tr></table></figure><hr><h3 id="Validation"><a href="#Validation" class="headerlink" title="Validation"></a>Validation</h3><p>It’s very important to make sure your json file in a nice formatting. And one more important thing, don’t forget to remove <code>,</code> in geojson file aftet the last <code>Feature</code> manully. </p><p>Some online validators can easily reach. <a href="https://jsonformatter.curiousconcept.com/#" target="_blank" rel="noopener">JSON Formatter</a></p><p>Some special characters will couse invalid of geojson, e.g. @:~{} and etc. So you would like to remove them before visualization.</p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://www.andrewdyck.com/how-to-convert-csv-data-to-geojson/" target="_blank" rel="noopener">How to convert CSV data to geoJSON</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
</entry>
<entry>
<title>「译」JavaScript对象生命周期(Eloquent JavaScript 第六章)</title>
<link href="/posts/24857/"/>
<content type="html"><![CDATA[<p>此文翻译《Eloquent Javascript》中第六章,<a href="http://eloquentjavascript.net/06_object.html" target="_blank" rel="noopener">The Secret Life of Objects</a>,侵删。<br>该书有中文译本出版。此译文仅作交流学习之用。</p><hr><blockquote><p>面向对象的编程语言的问题在于,它们携带了一些隐形的环境。你只是想要一根香蕉,但你得到的是一个拿着香蕉的猴子,和一整个丛林。<br>—— Joe Armstrong, interviewed in Coders at Work</p></blockquote><hr><h3 id="历史"><a href="#历史" class="headerlink" title="历史"></a>历史</h3><p>就像大多数编程故事一样,这个故事也从一个复杂的问题开始。讲道理,把一个复杂的问题分割为很多个小问题,它就变得可控了。这些“小问题”就叫做<code>对象</code>。<br>一个对象就像是一个坚硬的外壳,它隐藏了晦涩的内部信息,给我们提供的了一些旋钮和连接器,在这里就是使用对象的<code>接口</code>(比如不同的方法)。这样的机制能让我们忽略其复杂的内部工作原理,使用相对简单的接口。<br><img src="/images/tra_object1.jpg" alt="对象"><br>举个例子,你可以想象一个对象在电脑屏幕的一个区域提供接口,你就可以在屏幕的这个区域写字或者画画。至于这些形状是如何变为像素点的具体过程,就隐藏在对象内部了。在这里,为了使用这个对象,你需要了解它的一些方法,比如<code>drawCircle</code>。<br>在1970和80年代,这个思想最初进入应用。在1990年代,这个概念随着面向对象编程技术革命被炒得很热。一夜之间,很多人跳出来说只有面向对象才是正确的编程方式,没有对象的语言都是垃圾。<br>狂热终将导致不切实际的愚蠢,那时候就已经出现了一些<code>对象</code>的反对派。现在在某些圈子里,<code>对象</code>的名声并不好。<br>相对于理论派,我更倾向于实践主义。面向对象还有很多有用的概念,最重要的就是<code>封装</code>(用于区分内部复杂性和外部接口)。很值得学习。<br>这一章主要讲的就是JavaScript中的对象,和一些经典的面向对象的使用技术。</p><hr><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><p><code>方法</code>就是包含函数的简单属性。下面是一个简单的方法: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> rabbit = {};</span><br><span class="line">rabbit.speak = <span class="function"><span class="keyword">function</span>(<span class="params">line</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"The rabbit says '"</span> + line + <span class="string">"'"</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">rabbit.speak(<span class="string">"I'm alive."</span>);</span><br><span class="line"><span class="comment">// → The rabbit says 'I'm alive.'</span></span><br></pre></td></tr></table></figure><p>通常情况下,当一个对象的方法被调用时,总是需要做事情的。当一个函数被当作方法<code>object.method()</code>调用时(被当作一个属性来查找,而且立即执行),函数体内的特殊变量<code>this</code>就会指向被调用的对象。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">speak</span>(<span class="params">line</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"The "</span> + <span class="keyword">this</span>.type + <span class="string">" rabbit says '"</span> +</span><br><span class="line"> line + <span class="string">"'"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> whiteRabbit = {<span class="attr">type</span>: <span class="string">"white"</span>, <span class="attr">speak</span>: speak};</span><br><span class="line"><span class="keyword">var</span> fatRabbit = {<span class="attr">type</span>: <span class="string">"fat"</span>, <span class="attr">speak</span>: speak};</span><br><span class="line"></span><br><span class="line">whiteRabbit.speak(<span class="string">"Oh my ears and whiskers, "</span> +</span><br><span class="line"> <span class="string">"how late it's getting!"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// → The white rabbit says 'Oh my ears and whiskers, how</span></span><br><span class="line"><span class="comment">// late it's getting!'</span></span><br><span class="line">fatRabbit.speak(<span class="string">"I could sure use a carrot right now."</span>);</span><br><span class="line"><span class="comment">// → The fat rabbit says 'I could sure use a carrot</span></span><br><span class="line"><span class="comment">// right now.'</span></span><br></pre></td></tr></table></figure><p>这段代码使用<code>this</code>关键词用于输出正在说话的兔子的类型。回想一下<code>apply</code>和<code>bind</code>方法,它们的第一个参数都可以用来模拟方法的调用。第一个参数实际上是给<code>this</code>传值。<br>还有一个和<code>apply</code>类似的方法,叫做<code>call</code>。它也调用了方法中包含的函数,但是它传递的是更普遍的参数,而不是一个数组。类似于<code>apply</code>和<code>bind</code>,<code>call</code>也给<code>this</code>传递了特殊的值。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">speak.apply(fatRabbit, [<span class="string">"Burp!"</span>]);</span><br><span class="line"><span class="comment">// → The fat rabbit says 'Burp!'</span></span><br><span class="line">speak.call({<span class="attr">type</span>: <span class="string">"old"</span>}, <span class="string">"Oh my."</span>);</span><br><span class="line"><span class="comment">// → The old rabbit says 'Oh my.'</span></span><br></pre></td></tr></table></figure><hr><h3 id="原型"><a href="#原型" class="headerlink" title="原型"></a>原型</h3><p>仔细看: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> empty = {};</span><br><span class="line"><span class="built_in">console</span>.log(empty.toString);</span><br><span class="line"><span class="comment">// → function toString(){…}</span></span><br><span class="line"><span class="built_in">console</span>.log(empty.toString());</span><br><span class="line"><span class="comment">// → [object Object]</span></span><br></pre></td></tr></table></figure><p>我从空对象里输出了一个值。神奇!<br>好吧,这并不是真的。我只是保留了JavaScript对象的工作信息。<code>对象</code>除了很多属性之外,几乎所有的<code>对象</code>都有<code>原型</code>。<code>原型</code>是另外一个作为属性回退的<code>源对象</code>。当请求一个对象不存在的属性时,就会在它的<code>原型</code>里寻找,再去原型的原型里寻找,以此类推。<br>所以控对象的原型是什么呢?就是几乎所有原型的祖先<code>Object.prototyp</code>。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span>.getPrototypeOf({}) ==</span><br><span class="line"> <span class="built_in">Object</span>.prototype);</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span>.getPrototypeOf(<span class="built_in">Object</span>.prototype));</span><br><span class="line"><span class="comment">// → null</span></span><br></pre></td></tr></table></figure><p>如你所料,<code>Object.getPrototypeOf</code>函数返回的是对象的原型。<br>JavaScript的原型关系是一个树状结构,这个树的根节点就是<code>Object.prototype</code>。它提供的一些方法,几乎在所有的对象中都可以使用,比如<code>toString</code>,作用是把对象作为字符串输出。<br>很多对象的直接原型都不是<code>Object.prototype</code>,但他们有自己的原型,提供他们自己的默认属性。函数的原型是<code>Function.prototype</code>,数组的原型是<code>Array.prototype</code>。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span>.getPrototypeOf(<span class="built_in">isNaN</span>) ==</span><br><span class="line"> <span class="built_in">Function</span>.prototype);</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span>.getPrototypeOf([]) ==</span><br><span class="line"> <span class="built_in">Array</span>.prototype);</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>以上的原型对象也有自己的原型,通常是<code>Object.prototype</code>。所以间接地,还是提供了比如<code>toString</code>这样的方法。<br>显然,<code>Object.getPrototypeOf</code>函数返回的是一个对象的原型。你可以使用<code>Object.create</code>创建新的原型。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> protoRabbit = {</span><br><span class="line"> speak: <span class="function"><span class="keyword">function</span>(<span class="params">line</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"The "</span> + <span class="keyword">this</span>.type + <span class="string">" rabbit says '"</span> +</span><br><span class="line"> line + <span class="string">"'"</span>);</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> killerRabbit = <span class="built_in">Object</span>.create(protoRabbit);</span><br><span class="line">killerRabbit.type = <span class="string">"killer"</span>;</span><br><span class="line">killerRabbit.speak(<span class="string">"SKREEEE!"</span>);</span><br><span class="line"><span class="comment">// → The killer rabbit says 'SKREEEE!'</span></span><br></pre></td></tr></table></figure><p><code>兔子原型</code>就像一个容器,存放了所有兔子共有的属性。一个具体的兔子,比如本例中的killer rabbit,从它的原型中继承共有属性,但这个对象只包含了它自己的属性。</p><hr><h3 id="构造器"><a href="#构造器" class="headerlink" title="构造器"></a>构造器</h3><p>一个创建对象的更方便的方法,就是使用一个共有的原型<code>constructor</code>。在JavaScript中,在函数前面加上关键词<code>new</code>,会被当作一个构造器处理。构造器的<code>this</code>变量会绑定给一个新的对象,调用后会返回这个新对象,除非是指定返回别的对象例外。<br>利用<code>new</code>新建的对象,称做构造器的实例化。<br>下面是一个兔子简单的构造器。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Rabbit</span>(<span class="params">type</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.type = type;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> killerRabbit = <span class="keyword">new</span> Rabbit(<span class="string">"killer"</span>);</span><br><span class="line"><span class="keyword">var</span> blackRabbit = <span class="keyword">new</span> Rabbit(<span class="string">"black"</span>);</span><br><span class="line"><span class="built_in">console</span>.log(blackRabbit.type);</span><br><span class="line"><span class="comment">// → black</span></span><br></pre></td></tr></table></figure><p>构造器(或者说全体函数)都会自动获得<code>prototype</code>这个属性,默认值为空,空对象继承自<code>Object.prototype</code>。任何一个由这个构造器实例化的对象都有原型。所以给兔子添加、<code>speak</code>方法,我们可以利用它的构造器简化: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Rabbit.prototype.speak = <span class="function"><span class="keyword">function</span>(<span class="params">line</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"The "</span> + <span class="keyword">this</span>.type + <span class="string">" rabbit says '"</span> +</span><br><span class="line"> line + <span class="string">"'"</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">blackRabbit.speak(<span class="string">"Doom..."</span>);</span><br><span class="line"><span class="comment">// → The black rabbit says 'Doom...'</span></span><br></pre></td></tr></table></figure><p>了解原型和构造器之间的区别是很重要的,还有对象获得原型的方式。<code>原型</code>通过构造器给定,获取对象的原型要使用<code>Object.getPrototypeOf</code>。构造器的原型是<code>Function.prototype</code>,因为构造器本质是函数。它的原型属性用于指定它实例化的对象,但它自己的原型不是这个。</p><hr><h3 id="重写"><a href="#重写" class="headerlink" title="重写"></a>重写</h3><p>当你给对象添加一个属性的时候,不论这个属性是不是来自于原型,这个属性都添加给了这个对象本身,由此它就有了自己的属性。如果原型中含有相同名称的属性,那么原型中的属性就不再影响该对象。原型本身的属性没有被改变。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Rabbit.prototype.teeth = <span class="string">"small"</span>;</span><br><span class="line"><span class="built_in">console</span>.log(killerRabbit.teeth);</span><br><span class="line"><span class="comment">// → small</span></span><br><span class="line">killerRabbit.teeth = <span class="string">"long, sharp, and bloody"</span>;</span><br><span class="line"><span class="built_in">console</span>.log(killerRabbit.teeth);</span><br><span class="line"><span class="comment">// → long, sharp, and bloody</span></span><br><span class="line"><span class="built_in">console</span>.log(blackRabbit.teeth);</span><br><span class="line"><span class="comment">// → small</span></span><br><span class="line"><span class="built_in">console</span>.log(Rabbit.prototype.teeth);</span><br><span class="line"><span class="comment">// → small</span></span><br></pre></td></tr></table></figure><p>下面的图就是代码运行后,它内部处理的情况。<code>Rabbit</code>和<code>Object</code>原型就是<code>killerRabbit</code>的后备资源,当找不到它自己的属性时,就会顺着向上查找。<br><img src="/images/tra_object2.svg" alt="兔子原型"><br>重写属性也是原型的一个很有用的地方。如同例子中的兔子牙齿,在非特殊的对象中从原型中继承标准值,也允许特殊对象有自己不同的属性。<br>这一功能也使得数组原型具有不同的<code>toString</code>方法。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Array</span>.prototype.toString ==</span><br><span class="line"> <span class="built_in">Object</span>.prototype.toString);</span><br><span class="line"><span class="comment">// → false</span></span><br><span class="line"><span class="built_in">console</span>.log([<span class="number">1</span>, <span class="number">2</span>].toString());</span><br><span class="line"><span class="comment">// → 1,2</span></span><br></pre></td></tr></table></figure><p>调用数组的<code>toString</code>方法,返回值类似于调用<code>.join(",")</code>,在返回的数组中每个值之间添加逗号。数组直接调用<code>Object.prototype.toString</code>返回的是一个不同的字符串。函数并没有数组的概念,所以返回值是“object”再加它的数据类型,然后放在中括号中。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span>.prototype.toString.call([<span class="number">1</span>, <span class="number">2</span>]));</span><br><span class="line"><span class="comment">// → [object Array]</span></span><br></pre></td></tr></table></figure><hr><h3 id="原型实例化"><a href="#原型实例化" class="headerlink" title="原型实例化"></a>原型实例化</h3><p>基于原型给所有的对象添加属性或者方法随时都可以进行。举个例子,这个功能在给兔子添加跳舞方法就很必要。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Rabbit.prototype.dance = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"The "</span> + <span class="keyword">this</span>.type + <span class="string">" rabbit dances a jig."</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">killerRabbit.dance();</span><br><span class="line"><span class="comment">// → The killer rabbit dances a jig.</span></span><br></pre></td></tr></table></figure><p>这个功能很方便,但也会造成问题。在之前的章节,我们使用对象作为连接名字和给定值的方式。下面是<a href="http://eloquentjavascript.net/04_data.html#object_map" target="_blank" rel="noopener">第四章</a>的一个例子: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> map = {};</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">storePhi</span>(<span class="params">event, phi</span>) </span>{</span><br><span class="line"> map[event] = phi;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">storePhi(<span class="string">"pizza"</span>, <span class="number">0.069</span>);</span><br><span class="line">storePhi(<span class="string">"touched tree"</span>, <span class="number">-0.081</span>);</span><br></pre></td></tr></table></figure><p>我们可以在<code>for/in</code>循环中遍历对象中所有的phi值,并且使用<code>in</code>测试某个名字是否存在。但不幸的是,对象的原型会导致错误。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Object</span>.prototype.nonsense = <span class="string">"hi"</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> name <span class="keyword">in</span> map)</span><br><span class="line"> <span class="built_in">console</span>.log(name);</span><br><span class="line"><span class="comment">// → pizza</span></span><br><span class="line"><span class="comment">// → touched tree</span></span><br><span class="line"><span class="comment">// → nonsense</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"nonsense"</span> <span class="keyword">in</span> map);</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"toString"</span> <span class="keyword">in</span> map);</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Delete the problematic property again</span></span><br><span class="line"><span class="keyword">delete</span> <span class="built_in">Object</span>.prototype.nonsense;</span><br></pre></td></tr></table></figure><p>这完全是错误的,在我们的数据集里就没有叫做“nonsense”的名字,而且肯定也没有“toString”。<br>奇怪的是,<code>for/in</code>循环中也没有出现<code>toString</code>,但是在<code>in</code>操作中返回的是<code>true</code>。这是因为JavaScript区分了可枚举和不可枚举属性。<br>通过<code>Object.defineProperty</code>我们可以自定义不可枚举属性,可以使我们控制创建的属性。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Object</span>.defineProperty(<span class="built_in">Object</span>.prototype, <span class="string">"hiddenNonsense"</span>,</span><br><span class="line"> {<span class="attr">enumerable</span>: <span class="literal">false</span>, <span class="attr">value</span>: <span class="string">"hi"</span>});</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> name <span class="keyword">in</span> map)</span><br><span class="line"> <span class="built_in">console</span>.log(name);</span><br><span class="line"><span class="comment">// → pizza</span></span><br><span class="line"><span class="comment">// → touched tree</span></span><br><span class="line"><span class="built_in">console</span>.log(map.hiddenNonsense);</span><br><span class="line"><span class="comment">// → hi</span></span><br></pre></td></tr></table></figure><p>现在这个属性是存在的,但不会出现在循环里了。这点很好。但是<code>in</code>操作时对象的<code>Object.prototype</code>还是有问题的。为了解决这个问题,我们可以使用<code>hasOwnProperty</code>方法。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(map.hasOwnProperty(<span class="string">"toString"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br></pre></td></tr></table></figure><p>这个方法能绕过它自身的属性,查看它包含的属性。这个信息比<code>in</code>操作返回的信息更有用。<br>当你担心有人混淆了原型时(在自己的程序中加入别人的代码),我推荐你这样写<code>for/in</code>循环: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> name <span class="keyword">in</span> map) {</span><br><span class="line"> <span class="keyword">if</span> (map.hasOwnProperty(name)) {</span><br><span class="line"> <span class="comment">// ... this is an own property</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><hr><h3 id="无原型对象"><a href="#无原型对象" class="headerlink" title="无原型对象"></a>无原型对象</h3><p>但是兔子问题不止于此。如果有人在我们的<code>map</code>中添加一个名称为<code>hasOwnProperty</code>的对象,并且把它的值设为42呢?那么<code>map.hasOwnProperty</code>调用的是它自身的属性,并且返回一个数值,而不是函数。<br>在这样的情况下,原型就成了一个阻碍,我们希望不存在原型。我们知道<code>Object.create</code>函数可以让我们创建自定义原型的对象。你可以指定它的原型为<code>null</code>,这样就创建了一个没有原型的新对象。对于像<code>map</code>这样的对象,任何只都可以作为它的属性,那么无原型对象正是我们需要的。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> map = <span class="built_in">Object</span>.create(<span class="literal">null</span>);</span><br><span class="line">map[<span class="string">"pizza"</span>] = <span class="number">0.069</span>;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"toString"</span> <span class="keyword">in</span> map);</span><br><span class="line"><span class="comment">// → false</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"pizza"</span> <span class="keyword">in</span> map);</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>这样就好多了!我们不需要再通过笨办法,用<code>hasOwnProperty</code>去判断对象自身的属性。现在不管谁对<code>Object.prototype</code>做了什么,我们都可以安全的使用<code>for/in</code>循环。</p><hr><h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>当你对一个对象调用<code>String</code>函数时(转化一个值为字符串),它会去调用<code>toString</code>方法返回一个新建的字符串。有一些对象自定义了<code>toString</code>方法,返回比<code>[object Object]</code>更有用的信息。<br>这只是这个强大用途的一个小小例子。当编写一段代码用以处理特定接口的对象时(本例中是<code>toString</code>方法),任何可用于支持这个接口的代码都可以接入,并且运行良好。<br>这个机制叫做<code>多态</code>,当然不涉及任何形态的变化。只要符合接口的要求,多态代码支持传入不同数据类型。</p><hr><h3 id="表格处理"><a href="#表格处理" class="headerlink" title="表格处理"></a>表格处理</h3><p>我将会给出一个更深入的例子来讲解普遍意义上面向对象的多态机制。例子是这样的:给定一个数组,创建一个格式化的字符串,要求行列对齐。比如: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">name height country</span><br><span class="line">------------ ------ -------------</span><br><span class="line">Kilimanjaro 5895 Tanzania</span><br><span class="line">Everest 8848 Nepal</span><br><span class="line">Mount Fuji 3776 Japan</span><br><span class="line">Mont Blanc 4808 Italy/France</span><br><span class="line">Vaalserberg 323 Netherlands</span><br><span class="line">Denali 6168 United States</span><br><span class="line">Popocatepetl 5465 Mexico</span><br></pre></td></tr></table></figure><p>我们建立表格的流程是这样,构建函数先输入每个单元格的宽和高,然后用这个信息确定行列的宽和高。然后构建函数去构建正确大小的单元格,最后把结果保存到一个字符串里。<br>这个格式化程序使用一个设计优良的接口和单元格对象通信。这样,这个程序支持的单元格并没有预先设定好。我们可以稍后再增加单元格格式,比如如果接口支持的话,不用改变程序,我们也可以给表头添加下划线。<br>以下为接口:</p><ul><li><code>minHeight()</code>返回的是一行的最小高度。</li><li><code>minWidth()</code>返回的是一个单元格的最小宽度。</li><li><code>draw(width, height)</code>返回的是一个<code>height</code>长度的数组,每一个都包含对应字符串的<code>width</code>长度。这就代表了单元格的内容。</li></ul><p>这里我会使用很多高阶数组方法,因为很合适这个例子。<br>程序的第一行用于计算一个单元格的最小列宽和行高。变量<code>row</code>保存的是一个嵌套的数组,每一个数组都代表一行单元格。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">rowHeights</span>(<span class="params">rows</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> rows.map(<span class="function"><span class="keyword">function</span>(<span class="params">row</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> row.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">max, cell</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.max(max, cell.minHeight());</span><br><span class="line"> }, <span class="number">0</span>);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">colWidths</span>(<span class="params">rows</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> rows[<span class="number">0</span>].map(<span class="function"><span class="keyword">function</span>(<span class="params">_, i</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> rows.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">max, row</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.max(max, row[i].minWidth());</span><br><span class="line"> }, <span class="number">0</span>);</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以下划线(_)开头的命名的变量,或者命名为单个的下划线,只是为了提高可读性,表示这个不使用这个参数。<br><code>rowHeights</code>函数不难理解,使用<code>reduce</code>去计算一行单元格的最大高度值,然后使用<code>map</code>去对每一行执行这个计算。<br><code>colWidths</code>略有一点变量所以稍微有点难理解,因为外层的数组是代表每一行的数组,并不是每一列。之前没有提到,传递给<code>map</code>(或者类似<code>forEach</code>,<code>filter</code>这样的函数)的第二个参数,是当前元素的索引。通过映射第一行的元素,而且只映射第二个参数,<code>colWidths</code>给每一列索引建立一个数组。调用<code>reduce</code>运算的是外层的每一行数组,用于提出改行最宽的单元格和它的索引。<br>下面是绘制表格的代码: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">drawTable</span>(<span class="params">rows</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> heights = rowHeights(rows);</span><br><span class="line"> <span class="keyword">var</span> widths = colWidths(rows);</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">drawLine</span>(<span class="params">blocks, lineNo</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> blocks.map(<span class="function"><span class="keyword">function</span>(<span class="params">block</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> block[lineNo];</span><br><span class="line"> }).join(<span class="string">" "</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">drawRow</span>(<span class="params">row, rowNum</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> blocks = row.map(<span class="function"><span class="keyword">function</span>(<span class="params">cell, colNum</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> cell.draw(widths[colNum], heights[rowNum]);</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> blocks[<span class="number">0</span>].map(<span class="function"><span class="keyword">function</span>(<span class="params">_, lineNo</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> drawLine(blocks, lineNo);</span><br><span class="line"> }).join(<span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> rows.map(drawRow).join(<span class="string">"\n"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>drawTable</code>这个函数调用了内部帮助函数<code>drawRow</code>去绘制每一行,然后在每一行末添加换行符。<br>首先<code>drawRow</code>函数把单元格对象转变为<code>blocks</code>,就是以行为单位,分割为包含单元格内容的字符串数组。一个只包含数字3376的单元格,转换后就是像[“3776”]这样的单个元素,带有下划线的单元格可能被转换为数组[“name”, “——“]。<br>一个block中的每一行的高度都相等,在最后的输出中应该保持相邻的位置。<code>drawRow</code>第二次调用<code>map</code>,从最左边的block开始逐行绘制输出表格。并且在逐行绘制的同时,记录下表格里最宽的那行。然后在每一行末添加换行符,把整行当作是<code>drawRow</code>的返回值。<br><code>drawLine</code>函数用于提取block数组中相邻的行,并且在行之间添加一个空格,这样每列之间就有了一个字符间隔的空格。<br>现在我们为包含字符的单元格写一个构造函数,实现了单元格的接口。构造函数用<code>split</code>方法把字符串分割为数组。在字符串中,<code>split</code>函数在每个传入参数出现的地方,都会将字符串分割,并且返回每个小部分组成的数组。<code>minWidth</code>函数返回这个数组最宽的行。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">repeat</span>(<span class="params">string, times</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> result = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < times; i++)</span><br><span class="line"> result += string;</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">TextCell</span>(<span class="params">text</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.text = text.split(<span class="string">"\n"</span>);</span><br><span class="line">}</span><br><span class="line">TextCell.prototype.minWidth = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.text.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">width, line</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.max(width, line.length);</span><br><span class="line"> }, <span class="number">0</span>);</span><br><span class="line">};</span><br><span class="line">TextCell.prototype.minHeight = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.text.length;</span><br><span class="line">};</span><br><span class="line">TextCell.prototype.draw = <span class="function"><span class="keyword">function</span>(<span class="params">width, height</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> result = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < height; i++) {</span><br><span class="line"> <span class="keyword">var</span> line = <span class="keyword">this</span>.text[i] || <span class="string">""</span>;</span><br><span class="line"> result.push(line + repeat(<span class="string">" "</span>, width - line.length));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>这段代码使用了一个叫<code>repeat</code>的帮助函数,它用于构建一个重复的字符串,重复的内容是第一个参数,重复次数为第二个参数。<code>draw</code>方法给每一行添加了一个padding,使得每一行长度相同。<br>我们试着用以上方法创建一个 5 × 5 的棋盘格。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> rows = [];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</span><br><span class="line"> <span class="keyword">var</span> row = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> j = <span class="number">0</span>; j < <span class="number">5</span>; j++) {</span><br><span class="line"> <span class="keyword">if</span> ((j + i) % <span class="number">2</span> == <span class="number">0</span>)</span><br><span class="line"> row.push(<span class="keyword">new</span> TextCell(<span class="string">"##"</span>));</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> row.push(<span class="keyword">new</span> TextCell(<span class="string">" "</span>));</span><br><span class="line"> }</span><br><span class="line"> rows.push(row);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(drawTable(rows));</span><br><span class="line"><span class="comment">// → ## ## ##</span></span><br><span class="line"><span class="comment">// ## ##</span></span><br><span class="line"><span class="comment">// ## ## ##</span></span><br><span class="line"><span class="comment">// ## ##</span></span><br><span class="line"><span class="comment">// ## ## ##</span></span><br></pre></td></tr></table></figure><p>这是可行的!但是由于每个单元格大小相等,格式化表格的函数实际上没有做任何事。<br>我们在这里使用的山脉数据可以在<a href="http://eloquentjavascript.net/code/mountains.js" target="_blank" rel="noopener">这里下载</a>。<br>我们需要使用下划线强调一下第一行,也就是列名。这不是大问题,我们只需要写一个带有下划线类型的单元格。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">UnderlinedCell</span>(<span class="params">inner</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.inner = inner;</span><br><span class="line">}</span><br><span class="line">UnderlinedCell.prototype.minWidth = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.inner.minWidth();</span><br><span class="line">};</span><br><span class="line">UnderlinedCell.prototype.minHeight = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.inner.minHeight() + <span class="number">1</span>;</span><br><span class="line">};</span><br><span class="line">UnderlinedCell.prototype.draw = <span class="function"><span class="keyword">function</span>(<span class="params">width, height</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.inner.draw(width, height - <span class="number">1</span>)</span><br><span class="line"> .concat([repeat(<span class="string">"-"</span>, width)]);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>带有下划线的单元格还包含另一个单元格。它需要获取内部单元格的大小(通过调用<code>minWidth</code>和<code>minHeight</code>方法),但是最后单元格高度需要加1,因为下划线也占了一行。<br>绘制这样一个单元格很简单,我们在原先的内容下增加下划线就可以了。<br>有了绘制下划线的函数,现在我们可以写一个为我们的数据集绘制单元格的函数。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">dataTable</span>(<span class="params">data</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> keys = <span class="built_in">Object</span>.keys(data[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">var</span> headers = keys.map(<span class="function"><span class="keyword">function</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> UnderlinedCell(<span class="keyword">new</span> TextCell(name));</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">var</span> body = data.map(<span class="function"><span class="keyword">function</span>(<span class="params">row</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> keys.map(<span class="function"><span class="keyword">function</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> TextCell(<span class="built_in">String</span>(row[name]));</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> [headers].concat(body);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(drawTable(dataTable(MOUNTAINS)));</span><br><span class="line"><span class="comment">// → name height country</span></span><br><span class="line"><span class="comment">// ------------ ------ -------------</span></span><br><span class="line"><span class="comment">// Kilimanjaro 5895 Tanzania</span></span><br><span class="line"><span class="comment">// … etcetera</span></span><br></pre></td></tr></table></figure><p>标准的<code>Object.keys</code>函数返回一个对象,带有名称的数组。表格第一行必须包含有下划线单元格,表示列的名称。然后下面就是所有数据集中的数据内容,我们通过映射所有数据的<code>key</code>,来确保每一行的单元格顺序不出错。<br>输出的数据格式如上,除了没有<code>height</code>这列没有正确对齐。我们等一下会讲到这一点。</p><hr><h3 id="获取器和设置器"><a href="#获取器和设置器" class="headerlink" title="获取器和设置器"></a>获取器和设置器</h3><p>指定接口的时候,是可以包含不是方法的属性。我们可以定义<code>minHeight</code>和<code>minWidth</code>只返回数字。但这就要求在构造函数中做运算,实际上这一部分代码并不是和构造这个对象很相关。会造成一些问题,比如带有下划线单于格的内部单元格发生了改变,那么下划线单元格的大小也会改变。<br>这就导致有一些人从不在接口中传递非方法的属性。相比于直接获取一个单一的数值属性,他们更倾向于使用<code>getSomething</code>和<code>setSomething</code>方法去读写属性。这种办法也有缺点,就是你需要写(或者读)一些额外的代码。<br>幸运的是,JavaScript提供了一个两全其美的办法。我们可以这样设定,从外部看起来像是传递数值,但实际上传递了一个相关联的方法。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> pile = {</span><br><span class="line"> elements: [<span class="string">"eggshell"</span>, <span class="string">"orange peel"</span>, <span class="string">"worm"</span>],</span><br><span class="line"> get height() {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.elements.length;</span><br><span class="line"> },</span><br><span class="line"> set height(value) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Ignoring attempt to set height to"</span>, value);</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(pile.height);</span><br><span class="line"><span class="comment">// → 3</span></span><br><span class="line">pile.height = <span class="number">100</span>;</span><br><span class="line"><span class="comment">// → Ignoring attempt to set height to 100</span></span><br></pre></td></tr></table></figure><p>从字面上理解,<code>get</code>或者<code>set</code>可以用于指定读写属性值时候调用的函数。你也可以给已经存在的对象添加这样的属性,比如<code>Object.defineProperty</code>给原型添加属性(之前使用过这个方法创建了不可枚举属性)。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Object</span>.defineProperty(TextCell.prototype, <span class="string">"heightProp"</span>, {</span><br><span class="line"> get: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="keyword">return</span> <span class="keyword">this</span>.text.length; }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> cell = <span class="keyword">new</span> TextCell(<span class="string">"no\nway"</span>);</span><br><span class="line"><span class="built_in">console</span>.log(cell.heightProp);</span><br><span class="line"><span class="comment">// → 2</span></span><br><span class="line">cell.heightProp = <span class="number">100</span>;</span><br><span class="line"><span class="built_in">console</span>.log(cell.heightProp);</span><br><span class="line"><span class="comment">// → 2</span></span><br></pre></td></tr></table></figure><p>你还可以用一个类似<code>set</code>的属性,在对象中传递给<code>defineProperty</code>,去定义一些方法。当定义了获取器但没有定义设置器,就会忽略写入的方法。</p><hr><h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><p>绘制表格的练习已经接近完成了。再加上数字列右侧对齐能提高可读性。我们需要再创建另一个类似<code>TextCell</code>的单元格,但不是给右边添加空白,而是加在左边,使得他们能够右对齐。<br>我们现在写一个新的构造函数,在原型中包含三个方法。但是原型自身也可以有原型,所以我们就可以通过一个聪明的方式去构建。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">RTextCell</span>(<span class="params">text</span>) </span>{</span><br><span class="line"> TextCell.call(<span class="keyword">this</span>, text);</span><br><span class="line">}</span><br><span class="line">RTextCell.prototype = <span class="built_in">Object</span>.create(TextCell.prototype);</span><br><span class="line">RTextCell.prototype.draw = <span class="function"><span class="keyword">function</span>(<span class="params">width, height</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> result = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < height; i++) {</span><br><span class="line"> <span class="keyword">var</span> line = <span class="keyword">this</span>.text[i] || <span class="string">""</span>;</span><br><span class="line"> result.push(repeat(<span class="string">" "</span>, width - line.length) + line);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>我们复用了<code>TextCell</code>中的<code>minHeight</code>和<code>minWidth</code>方法。<code>RTextCell</code>和<code>TextCell</code>基本相同,只是<code>draw</code>方法博阿含的函数不同。<br>这种模式叫做<code>继承</code>。可以使我们使用相对少量的代码对已有的数据类型做小部分的改变。典型的就是新的构造函数会调用旧的构造函数,使用<code>call</code>方法为了传递给新的对象<code>this</code>值。一旦这个构造函数被调用,我们就认为旧的对象类型的所有属性都被添加进新的对象。实例化的继承对象也有权限调用其原型的原型的属性。最终,我们可以通过添加新的原型重写某些属性。<br>现在,我们在<code>dataTable</code>使用<code>RTextCell</code>作为单元格函数,它的值就是一个数值,那我们就得到的一开始想要的表格。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">dataTable</span>(<span class="params">data</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> keys = <span class="built_in">Object</span>.keys(data[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">var</span> headers = keys.map(<span class="function"><span class="keyword">function</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> UnderlinedCell(<span class="keyword">new</span> TextCell(name));</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">var</span> body = data.map(<span class="function"><span class="keyword">function</span>(<span class="params">row</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> keys.map(<span class="function"><span class="keyword">function</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> value = row[name];</span><br><span class="line"> <span class="comment">// This was changed:</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> value == <span class="string">"number"</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RTextCell(<span class="built_in">String</span>(value));</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> TextCell(<span class="built_in">String</span>(value));</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> [headers].concat(body);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(drawTable(dataTable(MOUNTAINS)));</span><br><span class="line"><span class="comment">// → … beautifully aligned table</span></span><br></pre></td></tr></table></figure><p>继承是面向对象的基础的一部分,同样还有封装和多态。但是通常封装和多态都是被赞赏的,而继承存在争议。<br>原因是继承经常会和多态混淆,宣称是一个很强大的工具,但实际上经常被使用得很差。封装和多态可以分离代码片段,减少程序中代码的混乱程度,而继承基本上就是把代码联合在一起,增加混乱度。<br>如上,你可以不用继承实现多态。我不是告诉你要完全避免继承,我自己在我程序中也会经常用到继承。但是你要把它当作是一个减少定义代码量的小技巧,而不是组织代码原则。拓展<code>类型</code>更好的方式是通过组合,比如<code>UnderlinedCell</code>就是通过存储在一个属性中,在自己的方法中调用存储的属性这种方式,建立在另一个单元格对象之上。</p><hr><h3 id="INSTANCEOF运算符"><a href="#INSTANCEOF运算符" class="headerlink" title="INSTANCEOF运算符"></a>INSTANCEOF运算符</h3><p>有时候需要要知道一个对象是不是源于一个特定的构造函数,因此,JavaScript提供了二进制运算符<code>instanceof</code>。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> RTextCell(<span class="string">"A"</span>) <span class="keyword">instanceof</span> RTextCell);</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> RTextCell(<span class="string">"A"</span>) <span class="keyword">instanceof</span> TextCell);</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> TextCell(<span class="string">"A"</span>) <span class="keyword">instanceof</span> RTextCell);</span><br><span class="line"><span class="comment">// → false</span></span><br><span class="line"><span class="built_in">console</span>.log([<span class="number">1</span>] <span class="keyword">instanceof</span> <span class="built_in">Array</span>);</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>这个运算符会逐级检查继承。<code>RTextCell</code>就是<code>TextCell</code>的一个实例化,因为<code>RTextCell.prototype</code>源于<code>TextCell.prototype</code>。这个操作符也可以被用于标准构造函数例如<code>Array</code>。几乎所有的对象都是<code>Object</code>的实例化。</p><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>所以对象要比我最初描绘的复杂得多。他们有原型,同时原型又是另一个对象。而且只要原型对象中存在的属性,在继承对象中即使定义这个属性,它也会包含这个属性。简单对象的原型是<code>Object.prototype</code>。<br>构造函数通常都是以大写字母开头的一类函数,可以被<code>new</code>操作符来创建新的对象。新对象的原型可以在构造函数的<code>prototype</code>属性中找到。这一点可以好好利用,你可以把某一类型所有值都共享的属性放进他们的原型中。给定一个对象和构造函数,<code>instanceof</code>操作符可以判断该对象是否来源于制定构造函数。<br>有关对象很有用的一件事,就是去给它指定一个接口,然后告诉使用代码的人他们应该通过这个接口去和对象交互。剩余的构成你代码的细节部分都<code>封装</code>,隐藏在接口后面。<br>说到接口,谁说一个接口只能给一种对象应用?给不同的对象可以使用同一个接口,编写能够适用于多种对象的接口的代码,就叫做多态。这一点很有用。<br>当有多个数据类型它们的区别只在很小的细节部分,使用旧数据类型的原型去构建新数据类型的原型就很有用,而且可以在新的构造函数中调用旧的构造函数。这就能使得新的对象类似就的对象,但是你可以根据需求添加或重写属性。</p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
</entry>
<entry>
<title>How to Find Substrings in Python</title>
<link href="/posts/49020/"/>
<content type="html"><![CDATA[<p><code>.find()</code> function is used for find a substring in a string, and will return location index. E.g. <code>-1</code> means no such substirng in this string.</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> io</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> codecs</span><br><span class="line"></span><br><span class="line">keyword = <span class="string">u'车'</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getKeyWeibo</span><span class="params">(filename)</span>:</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">with</span> codecs.open(filename,<span class="string">'r'</span>,encoding=<span class="string">'utf8'</span>) <span class="keyword">as</span> cfg:</span><br><span class="line"> cfglist = cfg.readlines()</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(cfglist)):</span><br><span class="line"> <span class="keyword">if</span> cfglist[i].find(keyword) > <span class="number">0</span>:</span><br><span class="line"> f.write(cfglist[i]+<span class="string">'\n'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">except</span> Exception, e:</span><br><span class="line"> <span class="keyword">print</span> e</span><br><span class="line"> <span class="keyword">print</span> <span class="string">'Please check checkboard.cfg,looks like something configured wrong.'</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Python </category>
</categories>
<tags>
<tag> text processing </tag>
</tags>
</entry>
<entry>
<title>How to Install PostgreSQL on a MAC</title>
<link href="/posts/63404/"/>
<content type="html"><![CDATA[<h3 id="Installation"><a href="#Installation" class="headerlink" title="Installation"></a>Installation</h3><p>Environment: macOS Sierra 10.12.4.</p><p>Install this database with ternimal:</p><ol><li><p>Install with <code>brew</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install postgresql</span><br></pre></td></tr></table></figure></li><li><p>After <code>brew</code> installation, initialization of DB</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">initdb /usr/<span class="built_in">local</span>/var/postgres</span><br></pre></td></tr></table></figure></li><li><p>Start server</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pg_ctl -D /usr/<span class="built_in">local</span>/var/postgres -l /usr/<span class="built_in">local</span>/var/postgres/server.log start</span><br></pre></td></tr></table></figure></li></ol><hr><h3 id="Database-and-user-creation"><a href="#Database-and-user-creation" class="headerlink" title="Database and user creation"></a>Database and user creation</h3><p>There is no users after installation, use command:</p><ol><li><p>Create your first database</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">createdb</span><br></pre></td></tr></table></figure></li><li><p>Login PostgreSQL console</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql</span><br></pre></td></tr></table></figure><p>Using <code>\l</code> could list all the information by name, owner, encoding, collate, Ctype and access privileges. <code>\q</code> for quit. </p><p>After database creation, users are also needed to be created.</p></li><li><p>Create postgres user</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">USER</span> postgres <span class="keyword">WITH</span> <span class="keyword">PASSWORD</span> <span class="string">'password'</span>;</span><br></pre></td></tr></table></figure></li><li><p>Delete default database</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DROP</span> <span class="keyword">DATABASE</span> postgres;</span><br></pre></td></tr></table></figure></li><li><p>Create a database under user <em>postgres</em></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">DATABASE</span> postgres OWNER postgres;</span><br></pre></td></tr></table></figure></li><li><p>Grant all privileges for user <em>postgres</em></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GRANT</span> ALL <span class="keyword">PRIVILEGES</span> <span class="keyword">ON</span> <span class="keyword">DATABASE</span> postgres <span class="keyword">to</span> postgres;</span><br></pre></td></tr></table></figure></li><li><p>Change attribute of <em>postgres</em></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">ROLE</span> postgres CREATEDB;</span><br></pre></td></tr></table></figure></li></ol><p>Now you can use <em>postgres</em> to login, and magege databases under this user.</p><hr><h3 id="Login-console-as-a-user"><a href="#Login-console-as-a-user" class="headerlink" title="Login console as a user"></a>Login console as a user</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -U [user] -d [database] -h [host] -p [port]</span><br></pre></td></tr></table></figure><p>Login by <code>psql</code>, in fact, it’s under default setting. </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">user: current mac user</span><br><span class="line">database: database with the same name of user</span><br><span class="line">host: localhost</span><br><span class="line">port: as default port 5432</span><br></pre></td></tr></table></figure><p>Login user <em>postgres</em> </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -U postgres -d postgres</span><br></pre></td></tr></table></figure><hr><h3 id="Common-console-commands"><a href="#Common-console-commands" class="headerlink" title="Common console commands"></a>Common console commands</h3><table><thead><tr><th>command</th><th>meaning</th></tr></thead><tbody><tr><td>\h</td><td>help, e.g. \h select</td></tr><tr><td>\?</td><td>list commands</td></tr><tr><td>\l</td><td>list databases</td></tr><tr><td>\c [database_name]</td><td>connect a database</td></tr><tr><td>\d</td><td>list all the tables of current database</td></tr><tr><td>\d [database_name]</td><td>list all the tables of a database</td></tr><tr><td>\u</td><td>list all the users</td></tr><tr><td>\e</td><td>open editor</td></tr><tr><td>\conninfo</td><td>print information of current DB and connection</td></tr><tr><td>\password [user]</td><td>change user psw</td></tr><tr><td>\q</td><td>quit</td></tr></tbody></table><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://www.jianshu.com/p/10ced5145d39" target="_blank" rel="noopener">Mac安装PostgreSQL</a><br>[2] <a href="https://www.postgresql.org/docs/9.0/static/index.html" target="_blank" rel="noopener">PostgreSQL 9.0.23 Documentation</a></p>]]></content>
<categories>
<category> Database </category>
</categories>
<tags>
<tag> installation </tag>
</tags>
</entry>
<entry>
<title>Markdown Tools with Sublime</title>
<link href="/posts/58389/"/>
<content type="html"><![CDATA[<h3 id="Explorer-entensions"><a href="#Explorer-entensions" class="headerlink" title="Explorer entensions"></a>Explorer entensions</h3><ul><li>Markdown here<br><a href="http://markdown-here.com/" target="_blank" rel="noopener">Markdown here</a> is an cross plantform extension for Chrome, Safari, Firefox and Thunderbird. It can help you write your email with markdown language quickly.<br>I am using Chrome extension for gmail. As long as I wrote my email in gmail interface, just hit <code>Markdownhere</code> button, then a nice formatted email will be there. That’s awesome.</li></ul><p><img src="/images/markdownhere.png" alt="email in markdown"></p><p><img src="/images/markdownhere2.png" alt="email after hit"></p><hr><h3 id="Sublime-Packages"><a href="#Sublime-Packages" class="headerlink" title="Sublime Packages"></a>Sublime Packages</h3><p><a href="https://github.com/SublimeText-Markdown/MarkdownEditing" target="_blank" rel="noopener"><code>MarkdownEditing</code></a> and <a href="https://github.com/timonwong/OmniMarkupPreviewer" target="_blank" rel="noopener"><code>OmniMarkupPreviewer</code></a> are two handy toos for markdown writing with Sublime.</p><h4 id="Installation"><a href="#Installation" class="headerlink" title="Installation"></a>Installation</h4><ol><li>Install package control on your sublime</li><li>Open package control pallet (<code>cmd</code>+<code>Shift</code>+<code>p</code> on Mac)</li><li>Type <code>install package</code> and hit Return</li><li>Type <code>MarkdownEditing</code> and then <code>OmniMarkupPreviewer</code> to install those two packages respectively.</li><li>Restart Sublime.</li></ol><h4 id="Essentials"><a href="#Essentials" class="headerlink" title="Essentials"></a>Essentials</h4><p><code>cmd</code>+<code>alt</code>+<code>o</code> preview in browser.</p><p><code>cmd</code>+<code>alt</code>+<code>r</code> Creates or pastes the contents of the clipboard as a reference link.</p><p><code>cmd</code>+<code>alt</code>+<code>b</code> <strong>bold</strong>.</p><p><code>cmd</code>+<code>alt</code>+<code>i</code> <em>italic</em>.</p><hr><h4 id="OmniMarkupPreviewer-404"><a href="#OmniMarkupPreviewer-404" class="headerlink" title="OmniMarkupPreviewer 404"></a>OmniMarkupPreviewer 404</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">'buffer_id(34) is not valid (closed or unsupported file format)'</span><br></pre></td></tr></table></figure><p>Go to:<br>Sublime Text > Preferences > Package Settings > OmniMarkupPreviewer > Settings - User<br>Paste the following to remove the strikeout package. </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "renderer_options-MarkdownRenderer": {</span><br><span class="line"> "extensions": ["tables", "fenced_code", "codehilite"]</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://www.jianshu.com/p/335b7d1be39e#" target="_blank" rel="noopener">介绍Sublime3下两款Markdown插件</a></p><p>[2] <a href="http://stackoverflow.com/questions/35798823/omnimarkuppreviewer-404" target="_blank" rel="noopener">OmniMarkupPreviewer 404</a></p>]]></content>
<categories>
<category> Sublime </category>
</categories>
<tags>
<tag> tools </tag>
</tags>
</entry>
<entry>
<title>「译」JavaScript正则表达式应用(Eloquent JavaScript 第九章)</title>
<link href="/posts/52949/"/>
<content type="html"><![CDATA[<p>此文翻译《Eloquent Javascript》中第九章,<a href="http://eloquentjavascript.net/09_regexp.html" target="_blank" rel="noopener">Regular Expressions</a>,侵删。<br>该书有中文译本出版。此译文仅作交流学习之用。</p><hr><blockquote><p>有人说,当我遇到一个问题的时候,我会说,我知道用正则表达式解决。那么他们就有两个问题了。<br>—— Jamie Zawinski<br>Yuan-Ma说,当你收获粮食时,需要更多的力量。当你获得一个问题的答案时,需要更多的代码。<br>—— Master Yuan-Ma, The Book of Programming</p></blockquote><p>编程工具和技术成长之路一直是混乱的,革命性的。它并不总是最优秀最聪明的那个获胜,而是那些能保证功能运行正常的最后才能活下来。举个例子,那些能够很好的和别的技术结合的编程工具。<br>在这章里,我会讲符合上述的一个工具,即正则表达式。正则表达式是一种描述字符串规律的方法。这是一个小且独立的语言,是JavaScript还有很多别的语言的一部分, 是个好用的小工具。<br>正则表达式很奇怪,但同时非常好用。它语法很神奇,JavaScript提供的接口也很笨拙。但不妨碍它是一个功能强大的字符串检索和处理工具。正确的理解正则表达式能让你成为一个更高效的程序员。</p><hr><h3 id="创建一个正则表达式"><a href="#创建一个正则表达式" class="headerlink" title="创建一个正则表达式"></a>创建一个正则表达式</h3><p>一个正则表达式就一个对象,可以通过<code>RegExp</code>构造函数创建,或者是作为一个斜杠<code>/</code>包围的文字值来写入。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> re1 = <span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">"abc"</span>);</span><br><span class="line"><span class="keyword">var</span> re2 = <span class="regexp">/abc/</span>;</span><br></pre></td></tr></table></figure><p>这两个正则表达式的对象<code>模式</code>相同:字母a后面跟着b,b后面跟着c。<br>使用<code>RegExp</code>构造函数时,<code>模式</code>被写为正常的字符串,所以对反斜杠也适用。<br>第二行中把表达式写在两个斜杠中间,对反斜杠的处理会有所不同。首先,因为斜杠代表一个<code>模式</code>的结束,所以就需要在<code>模式</code>内部的斜杠前加一个反斜杠。另外,如果斜杠不是某个特殊符号的一部分,它也会被保留下来,并且会改变<code>模式</code>的含义。比如<code>\n</code>。还有一些字符比如问号和加号,他们在正则表达式中有特殊的含义。如果这些符号需要作为字符串的一部分,也需要在这些字符前加反斜杠。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> eighteenPlus = <span class="regexp">/eighteen\+/</span>;</span><br></pre></td></tr></table></figure><p>书写正确的正则表达式反斜杠转义,就需要知道正则表达式中每一个特殊符号的含义。但就目前来看还不太现实,所以在任何非字母,数字,或者空格的字符前加上反斜杠。</p><hr><h3 id="匹配测试"><a href="#匹配测试" class="headerlink" title="匹配测试"></a>匹配测试</h3><p>正则表达式对象拥有自己一系列的方法。最简单的就是<code>test</code>。给它传递一个字符串,它会返回一个布尔值,用于表示这个字符串是否包含符合表达式的<code>模式</code>。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/abc/</span>.test(<span class="string">"abcde"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/abc/</span>.test(<span class="string">"abxde"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br></pre></td></tr></table></figure><p>一个只由非特殊符号组成的表达式,只用于表示这个字符串序列。如果<code>abc</code>出现在字符串的任何位置,<code>test</code>都会返回<code>true</code>。</p><hr><h3 id="匹配一组字符串"><a href="#匹配一组字符串" class="headerlink" title="匹配一组字符串"></a>匹配一组字符串</h3><p>测试一个字符串是否包含<code>abc</code>和调用<code>indexOf</code>的功能类似。正则表达式的功能更为强大,能够检测会更复杂的<code>模式</code>。<br>假设我们想要匹配任何数字。在正则表达式中,把字符放在方括号内,就表示会匹配方括号内的任何字符。<br>下面的两个式子都表示匹配任意数字: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/[0123456789]/</span>.test(<span class="string">"in 1992"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/[0-9]/</span>.test(<span class="string">"in 1992"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>在方括号内,两个字符之间加<code>-</code>表示一定范围内的字符,顺序等同于Unicode编码。0-9在这个编码中就是以数字从小到大排列(编码48-57),所以<code>[0-9]</code>就表示从0到9的任意数字。<br>正则表达式中还有内置的简写字符串,用于表示一些常用的匹配项。</p><table><thead><tr><th>Expression</th><th>Meaning</th></tr></thead><tbody><tr><td>\d</td><td>Any digit character</td></tr><tr><td>\w</td><td>An alphanumeric character (“word character”)</td></tr><tr><td>\s</td><td>Any whitespace character (space, tab, newline, and similar)</td></tr><tr><td>\D</td><td>A character that is not a digit</td></tr><tr><td>\W</td><td>A nonalphanumeric character</td></tr><tr><td>\S</td><td>A nonwhitespace character</td></tr><tr><td>.</td><td>Any character except for newline</td></tr></tbody></table><p>所以我们可以用一下格式去匹配时间字符串,30-01-2003 15:20: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> dateTime = <span class="regexp">/\d\d-\d\d-\d\d\d\d \d\d:\d\d/</span>;</span><br><span class="line"><span class="built_in">console</span>.log(dateTime.test(<span class="string">"30-01-2003 15:20"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(dateTime.test(<span class="string">"30-jan-2003 15:20"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br></pre></td></tr></table></figure><p>这个表达式包含很多反斜杠,制造了太多背景噪音,让人很难去理解这个表达式多传递的<code>模式</code>。我们稍后会讲一个稍微升级一点的版本。<br>反斜杠也可以用在方括号中间。举个例子,<code>[\d.]</code>表示任何数字或者句点字符。但要注意句点符号,当它出现在方括号内部时,就失去了它的特殊含义。其他的特殊含义字符也类似,比如<code>+</code>。<br>为了反向验证字符串,就是待验证的字符串中不能出现正则表达式的<code>模式</code>,可以在中括号中添加一个插入符。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> notBinary = <span class="regexp">/[^01]/</span>;</span><br><span class="line"><span class="built_in">console</span>.log(notBinary.test(<span class="string">"1100100010100110"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br><span class="line"><span class="built_in">console</span>.log(notBinary.test(<span class="string">"1100100010200110"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><hr><h3 id="重复部分模式"><a href="#重复部分模式" class="headerlink" title="重复部分模式"></a>重复部分模式</h3><p>现在你已经知道了如何匹配单个数字,那么一个数字字符串(多余一个数字的数)该如何匹配呢?<br>当你在正则表达式后面加一个加号<code>+</code>时,表示这个元素可能重复出现。所以,<code>/\d+/</code>匹配的是一个或多于一个数字的字符串。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/'\d+'/</span>.test(<span class="string">"'123'"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/'\d+'/</span>.test(<span class="string">"''"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/'\d*'/</span>.test(<span class="string">"'123'"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/'\d*'/</span>.test(<span class="string">"''"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>星号<code>*</code>的含义与之类似,但也匹配出现0次的<code>模式</code>。任何结尾出现星号的表达式永远会匹配,如果字符湖惨重没有出现匹配的<code>模式</code>,就是0匹配实例。<br>问号的含义是<code>模式</code>的一部分为可选,即可以出现0次或一次。在下面的例子中,字符<code>u</code>可以出现,但它没有出现的时候同样匹配。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> neighbor = <span class="regexp">/neighbou?r/</span>;</span><br><span class="line"><span class="built_in">console</span>.log(neighbor.test(<span class="string">"neighbour"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(neighbor.test(<span class="string">"neighbor"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>如果要指定一个<code>模式</code>的出现次数,需要用到花括号。在元素后面加上<code>{4}</code>,就表示该元素必须要出现4次。当然也可以指定出现次数的范围,<code>{2,4}</code>表示该元素出现至少2次至多4次。<br>下面的例子就是时间<code>模式</code>的另一种表示方法,可以匹配单个或两个数字的日期,月份还有时间。并且增加了可读性。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> dateTime = <span class="regexp">/\d{1,2}-\d{1,2}-\d{4} \d{1,2}:\d{2}/</span>;</span><br><span class="line"><span class="built_in">console</span>.log(dateTime.test(<span class="string">"30-1-2003 8:45"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>你还可以指定一个开放的范围,在花括号中,省略逗号后面的数字。<code>{5,}</code>表示出现超过5次。</p><hr><h3 id="分组表达式"><a href="#分组表达式" class="headerlink" title="分组表达式"></a>分组表达式</h3><p>如果需要一次使用多个操作符,如<code>*</code>或者<code>+</code>,可使用括号。只要后续的操作符是相关联的,正则表达式中被括号括起来的部分就可以算作一个单独的元素。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> cartoonCrying = <span class="regexp">/boo+(hoo+)+/i</span>;</span><br><span class="line"><span class="built_in">console</span>.log(cartoonCrying.test(<span class="string">"Boohoooohoohooo"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>第一个和第二个<code>+</code>只表示<code>boo</code>和<code>hoo</code>中的第二个<code>o</code>,第三个<code>+</code>表示的是<code>hoo+</code>这个整体,检测的是一个或多个整体。<br>在表达式最后的<code>i</code>表示该表达式大小写不敏感,虽然表达式中都是小写,但还是可以检测到字符串中的<code>B</code>。</p><hr><h3 id="匹配和分组"><a href="#匹配和分组" class="headerlink" title="匹配和分组"></a>匹配和分组</h3><p><code>test</code>方法绝对是正则表达式匹配最简单的方式,它只告诉你是否匹配,没有更多的信息。正则表达式还有一个<code>exec</code>方法,如果没有找到匹配项会返回<code>null</code>,反之返回找到的匹配项。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> match = <span class="regexp">/\d+/</span>.exec(<span class="string">"one two 100"</span>);</span><br><span class="line"><span class="built_in">console</span>.log(match);</span><br><span class="line"><span class="comment">// → ["100"]</span></span><br><span class="line"><span class="built_in">console</span>.log(match.index);</span><br><span class="line"><span class="comment">// → 8</span></span><br></pre></td></tr></table></figure><p><code>exec</code>返回的对象有<code>index</code>属性,可以告诉我们匹配项的位置。除了这个,这个对象同时也是一个字符串,第一个元素就是我们想要找的匹配项。<br>字符串对象也有一个功能相似的<code>match</code>方法。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">"one two 100"</span>.match(<span class="regexp">/\d+/</span>));</span><br><span class="line"><span class="comment">// → ["100"]</span></span><br></pre></td></tr></table></figure><p>当正则表达式中包含有圆括号括起来的子表达式时,所有匹配的项会作为数组返回。全部匹配的项会做为数组的第一个元素。第二个元素部分匹配,以此类推。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> quotedText = <span class="regexp">/'([^']*)'/</span>;</span><br><span class="line"><span class="built_in">console</span>.log(quotedText.exec(<span class="string">"she said 'hello'"</span>));</span><br><span class="line"><span class="comment">// → ["'hello'", "hello"]</span></span><br></pre></td></tr></table></figure><p>当一个字符串中完全没有可匹配的项时,那么输出值会是<code>undefined</code>。类似地,当某项多次匹配时,数组的最后一个元素是最后一个匹配项。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/bad(ly)?/</span>.exec(<span class="string">"bad"</span>));</span><br><span class="line"><span class="comment">// → ["bad", undefined]</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/(\d)+/</span>.exec(<span class="string">"123"</span>));</span><br><span class="line"><span class="comment">// → ["123", "3"]</span></span><br></pre></td></tr></table></figure><p>分组在提取部分字符串的时候非常有用。如果我们不只是想要验证字符串时候包含一个日期,而是同时想提取这个日期并且作为对象返回。我们可以用圆括号包含数字模式,使用<code>exec</code>返回日期数值。<br>我们绕了一圈终于要讨论一下JavaScript中日期和时间的存储方式。</p><hr><h3 id="时间类型"><a href="#时间类型" class="headerlink" title="时间类型"></a>时间类型</h3><p>JavaScript中有一个标准的日期对象,或者说是时间点,叫做<code>Data</code>。如果你<code>new</code>一个日期对象,将会得到当前日期和时间。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> <span class="built_in">Date</span>());</span><br><span class="line"><span class="comment">// → Wed Dec 04 2013 14:24:57 GMT+0100 (CET)</span></span><br></pre></td></tr></table></figure><p>你也可以创建一个特定的时间对象。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> <span class="built_in">Date</span>(<span class="number">2009</span>, <span class="number">11</span>, <span class="number">9</span>));</span><br><span class="line"><span class="comment">// → Wed Dec 09 2009 00:00:00 GMT+0100 (CET)</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> <span class="built_in">Date</span>(<span class="number">2009</span>, <span class="number">11</span>, <span class="number">9</span>, <span class="number">12</span>, <span class="number">59</span>, <span class="number">59</span>, <span class="number">999</span>));</span><br><span class="line"><span class="comment">// → Wed Dec 09 2009 12:59:59 GMT+0100 (CET)</span></span><br></pre></td></tr></table></figure><p>JavaScript按照惯例月份从0开始(所以12月是11),但是日期是从1开始。这一点很让人混淆,需要注意。<br>最后四个参数(小时,分钟,秒钟,还有毫秒)是可选项,默认值为0。<br>时间戳是一个毫秒为单位的数字,从1970年开始算起,1970年之前是负值(遵循Unix time约定,大概是1970年规定的)。<code>getTime</code>方法可以返回特定时间的时间戳数字。你可以想象,这个数字非常大。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> <span class="built_in">Date</span>(<span class="number">2013</span>, <span class="number">11</span>, <span class="number">19</span>).getTime());</span><br><span class="line"><span class="comment">// → 1387407600000</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> <span class="built_in">Date</span>(<span class="number">1387407600000</span>));</span><br><span class="line"><span class="comment">// → Thu Dec 19 2013 00:00:00 GMT+0100 (CET)</span></span><br></pre></td></tr></table></figure><p>如果给<code>Date</code>构造函数传递一个参数,这个参数就会被当作这样的毫秒数值。通过创建一个新的<code>Date</code>对象并调用<code>getTime</code>,或者是<code>Date.now</code>,就可以得到当前的毫秒数。<br><code>Date</code>对象提供<code>getFullYear</code>,<code>getMonth</code>,<code>getDate</code>,<code>getHours</code>, <code>getMinutes</code>和<code>getSeconds</code>方法,用于提取相应的值。还有<code>getYear</code>会返回相对不那么有用的两位数的年份,例如94或者14。<br>将我们感兴趣的子表达式用小括号括起来,我们就可以很容易的从一个字符串里提取日期对象了。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">findDate</span>(<span class="params">string</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> dateTime = <span class="regexp">/(\d{1,2})-(\d{1,2})-(\d{4})/</span>;</span><br><span class="line"> <span class="keyword">var</span> match = dateTime.exec(string);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Date</span>(<span class="built_in">Number</span>(match[<span class="number">3</span>]),</span><br><span class="line"> <span class="built_in">Number</span>(match[<span class="number">2</span>]) - <span class="number">1</span>,</span><br><span class="line"> <span class="built_in">Number</span>(match[<span class="number">1</span>]));</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(findDate(<span class="string">"30-1-2003"</span>));</span><br><span class="line"><span class="comment">// → Thu Jan 30 2003 00:00:00 GMT+0100 (CET)</span></span><br></pre></td></tr></table></figure><hr><h3 id="字和字符串的边界"><a href="#字和字符串的边界" class="headerlink" title="字和字符串的边界"></a>字和字符串的边界</h3><p>不幸的是,<code>findDate</code>也会从字符串”100-1-30000”提取出无意义的日期00-1-3000。这样的匹配可能会发正在字符串的任一位置,在这种情况下,它会从第二个字符开始,在倒数第二个字符结束。<br>如果我们想要强制扫面整个字符串,我们可以加上标签<code>^</code>和<code><div class="post-content"。插入符会从输入的开端开始匹配,美元符号表示匹配结尾。所以</code>/^\d+$/<code>匹配连续的一个或者一串数字,</code>/^!/<code>匹配任意带有感叹号开端的字符串,</code>/x^/<code>不能匹配任何字符串(因为字符串开始之前不可能有x)。 如果相反,我们只想要确保一个词语的开始和结束字符,我们可以使用</code>\b`。字符边界可以是开头或者结尾。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/cat/</span>.test(<span class="string">"concatenate"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="regexp">/\bcat\b/</span>.test(<span class="string">"concatenate"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br></pre></td></tr></table></figure><p>注意边界符并不代表一个实际的字符。它只是强制正则表达式去匹配相应的模式。</p><hr><h3 id="选择模式"><a href="#选择模式" class="headerlink" title="选择模式"></a>选择模式</h3><p>如果我们想要找到一段文字不仅包含一个数字,还跟着例如<code>pig</code>,<code>cow</code>或者<code>chicken</code>,或者它们的复数形式。<br>我们可以写三个正则表达式,然后一个一个测试,但有更简洁的办法。管道字符<code>|</code>表示它两侧的表达式都可以作为备选。如下: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> animalCount = <span class="regexp">/\b\d+ (pig|cow|chicken)s?\b/</span>;</span><br><span class="line"><span class="built_in">console</span>.log(animalCount.test(<span class="string">"15 pigs"</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(animalCount.test(<span class="string">"15 pigchickens"</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br></pre></td></tr></table></figure><p>圆括号可以用来限制模式应用的部分,你也可以在两个模式之间接连使用多个选择表达式。</p><hr><h3 id="匹配机制"><a href="#匹配机制" class="headerlink" title="匹配机制"></a>匹配机制</h3><p>正则表达式可以看作流程图。以下例子是前面的家畜表达式:<br><img src="/images/regexp1.svg" alt="判断机制"><br>如果我们的表达式能顺利从左到右找到一个通路,就可以找到一个匹配的字符串。我们保存字符串里的一个当前位置,通过没个检验盒的时候,我们只验证当前位置之后的部分是否与标准匹配。<br>所以当我们试图用正则表达式验证<code>the 3 pigs</code>的时候,我们的处理流程是这样:</p><ul><li>在第四个位置,是一个词语边界,所以我们通过了第一个检验盒。</li><li>仍旧是第四个位置,我们找到了一个数字,所以可以通过第二个检验盒。</li><li>在第五个位置,有一条路径循环返回到第二个检验盒(数字)之前,剩下的部分继续在流程中向前走到空格位。因为字符串中含有空格,不是数字,所以我们通过了第二条路。</li><li>当前位置是第六位(从<code>pigs</code>开始),位于流程的三通分支处。我们这里没有<code>cow</code>或者<code>chicken</code>,但是有<code>cow</code>,所以可以通过这一分支。</li><li>在第九位置,三通分支之后,有一条路是跳过<code>s</code>直接指向最后的词语边界,还有一条路可以匹配<code>s</code>。我们这里又一个<code>s</code>,并不是一个词语边界,所以我们通过<code>s</code>这个检验盒。</li><li>现在我们位于第十位(字符串终点),并且只能匹配一个词语边界。字符串末尾是一个词语边界,所以我们能够顺利通过这个检验,并匹配这个字符串。</li></ul><p>概念上来讲,正则表达式匹配字符串的机制是这样:它从字符串头部开始寻找匹配。在以上例子中,字符串首位是一个词语边界,但其后没有数字,所以在第二个检验盒位置失败了。然后就移向字符串中的第二个字符,继续从这里查找匹配项,以此类推,直到找到一个匹配项,或者移动到字符串末尾,判断该字符串中不包含任何匹配项。</p><hr><h3 id="回溯"><a href="#回溯" class="headerlink" title="回溯"></a>回溯</h3><p>正则表达式<code>/\b([01]+b|\d+|[\da-f]+h)\b/</code>匹配的是一个二进制数字后面加一个<code>b</code>,或者没有任何附加项的任意十进制数,或者一个十六进制数后面加一个<code>h</code>。下面是对应的流程图:<br><img src="/images/regexp2.svg" alt="流程图"><br>在匹配这个表达式的时候,通常在没有包含二进制数字的时候进入最上面的分支。举个例子,当检验<code>103</code>的时候,只有当<code>3</code>进入分支后才能判断匹配不符。这个字符串是符合我们检验标准的,但不符合当前第一个检验标准。<br>所以匹配器需要<code>回溯</code>。当进入一个分支时,它记录下当前的匹配位置(在本例中,从字符串初始位置开始,只通过了第一个词语边界检验盒),如果当前检验不能通过,执行回溯并且试着去匹配下一分支。对于字符串<code>103</code>来说,在检验到第三个字符之后,它会去匹配十进制数字分支。这个分支是检验成功的,然后根据需求返回。<br>一旦找到一个全匹配项,匹配器就结束工作。这意味着如果一个字符串能够匹配多个分支,只通过第一个匹配的检验盒(顺序按照正则表达式书写的顺序)。<br><code>回溯</code>也出现在重复运算符比如<code>+</code>和<code>*</code>中。如果你用<code>/^.*x/</code>去匹配<code>abcxe</code>,<code>.*</code>会首先试着去匹配整个字符串。然后匹配器才会知道在<code>模式</code>中还有<code>x</code>需要匹配。由于没有位于字符串末尾的<code>x</code>,所以星号会尝试寻找少一个字符的匹配项。但是匹配器没有在<code>abcx</code>之后找到<code>x</code>,所以它又<code>回溯</code>,星号的匹配项就是<code>abc</code>。现在找到了正确匹配的<code>x</code>,成功返回0-4位。<br>包含很多<code>回溯</code>的正则表达式也是可行的,当一个模式可以匹配不同的规则时使用。举个例子,当我们对于二进制表达式存疑时,我们可以写成<code>/([01]+)+b/</code>。<br><img src="/images/regexp3.svg" alt="流程图"><br>如果待匹配项是一串很长的二进制字符,而且后面没有<code>b</code>,这个匹配器会首先在数字内部循环。然后才知道字符串中没有<code>b</code>,然后<code>回溯</code>原位,再进入外面一层的循环,再失败,继续回溯到内循环。它会通过两个循环一直寻找所有可能的匹配项。这就意味着每增加一个字符,多一倍工作量。即便只是几个字符,匹配过程会一直继续下去。</p><hr><h3 id="替换方法"><a href="#替换方法" class="headerlink" title="替换方法"></a>替换方法</h3><p>字符串变量有内置方法<code>replace</code>,可以用于替换字符串中的部分字符。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">"papa"</span>.replace(<span class="string">"p"</span>, <span class="string">"m"</span>));</span><br><span class="line"><span class="comment">// → mapa</span></span><br></pre></td></tr></table></figure><p>其中第一个变量也可以是正则表达式,符合正则表达式的字符将会被替换。增则表达式中的<code>g</code>选项,指定的是所有符合正则表达式的字符串将会被替换,不仅仅是第一个。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">"Borobudur"</span>.replace(<span class="regexp">/[ou]/</span>, <span class="string">"a"</span>));</span><br><span class="line"><span class="comment">// → Barobudur</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"Borobudur"</span>.replace(<span class="regexp">/[ou]/g</span>, <span class="string">"a"</span>));</span><br><span class="line"><span class="comment">// → Barabadar</span></span><br></pre></td></tr></table></figure><p>通过给<code>replace</code>添加参数,或者使用<code>replaceAll</code>方法替换所有匹配项,都是可行的。但还有一些情况,只能用合适的正则表达式来计算。<br>正则表达式真正的强大的地方,在于我们可以使用分组去替换字符串。举个例子,我们有一个包含名字的很长的字符串,每个名字占一行,格式是<code>Lastname,Firstname</code>。如果我们想要去掉中间的逗号变成<code>Firstname Lastname</code>这样的格式,我们可以这样做: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(</span><br><span class="line"> <span class="string">"Hopper, Grace\nMcCarthy, John\nRitchie, Dennis"</span></span><br><span class="line"> .replace(<span class="regexp">/([\w ]+), ([\w ]+)/g</span>, <span class="string">"$2 $1"</span>));</span><br><span class="line"><span class="comment">// → Grace Hopper</span></span><br><span class="line"><span class="comment">// John McCarthy</span></span><br><span class="line"><span class="comment">// Dennis Ritchie</span></span><br></pre></td></tr></table></figure><p>表达式中的的<code>$1</code>和<code>$2</code>表示圆括号的匹配项。<code>$1</code>表示第一个匹配项,<code>$2</code>表示第二个,以此类推。全部的匹配项可表示为<code>><</code>。<br>除了字符串之外,还可以给<code>replace</code>传递一个函数作为第二个参数。对于每一个替换项,每一个匹配项都会作为参数调用这个函数,返回值会作为一个新的字符串。<br>下面是一个简单的例子: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> s = <span class="string">"the cia and fbi"</span>;</span><br><span class="line"><span class="built_in">console</span>.log(s.replace(<span class="regexp">/\b(fbi|cia)\b/g</span>, <span class="function"><span class="keyword">function</span>(<span class="params">str</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> str.toUpperCase();</span><br><span class="line">}));</span><br><span class="line"><span class="comment">// → the CIA and FBI</span></span><br></pre></td></tr></table></figure><p>下面是一个更有意思的例子: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> stock = <span class="string">"1 lemon, 2 cabbages, and 101 eggs"</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">minusOne</span>(<span class="params">match, amount, unit</span>) </span>{</span><br><span class="line"> amount = <span class="built_in">Number</span>(amount) - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (amount == <span class="number">1</span>) <span class="comment">// only one left, remove the 's'</span></span><br><span class="line"> unit = unit.slice(<span class="number">0</span>, unit.length - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (amount == <span class="number">0</span>)</span><br><span class="line"> amount = <span class="string">"no"</span>;</span><br><span class="line"> <span class="keyword">return</span> amount + <span class="string">" "</span> + unit;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(stock.replace(<span class="regexp">/(\d+) (\w+)/g</span>, minusOne));</span><br><span class="line"><span class="comment">// → no lemon, 1 cabbage, and 100 eggs</span></span><br></pre></td></tr></table></figure><p>这个函数传入一个字符串作为参数,找到所有的数次和量词一起出现的组合,返回一个把数量减一的字符串。<br>(\d+)分组返回的是<code>amount</code>变量,(\w+)分组返回的是<code>unit</code>变量。函数中转换<code>amount</code>为数字变量,这个转换的前提是它作为<code>\d+</code>的匹配项,函数中还为0和1的情况设置了不同的处理机制。</p><hr><h3 id="贪婪"><a href="#贪婪" class="headerlink" title="贪婪"></a>贪婪</h3><p>用<code>replace</code>方法写一个能够去掉JavaScript代码中注释的函数是很难的。下面是一个简单的尝试: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">stripComments</span>(<span class="params">code</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> code.replace(<span class="regexp">/\/\/.*|\/\*[^]*\*\//g</span>, <span class="string">""</span>);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(stripComments(<span class="string">"1 + /* 2 */3"</span>));</span><br><span class="line"><span class="comment">// → 1 + 3</span></span><br><span class="line"><span class="built_in">console</span>.log(stripComments(<span class="string">"x = 10;// ten!"</span>));</span><br><span class="line"><span class="comment">// → x = 10;</span></span><br><span class="line"><span class="built_in">console</span>.log(stripComments(<span class="string">"1 /* a */+/* b */ 1"</span>));</span><br><span class="line"><span class="comment">// → 1 1</span></span><br></pre></td></tr></table></figure><p>在<code>|</code>算子之前的部分,匹配的是非新行的双斜杠后面的任意字符。需要注意的是多行注释。我们使用<code>[^]</code>(任意非空字符串)去匹配任意字符。这里不能只用一个<code>.</code>,因为块级注释可以跨行,而<code>.</code>不能跨行检索。<br>但是之前的代码还是出错了,为什么呢?<br>就像之前<code>回溯</code>中讲过的,表达式中的<code>[^]*</code>会尽可能多的匹配。如果下一部分不能匹配模式,那么匹配器会回退一个字符并且重新开始检索匹配项。在本例中,匹配器先识图匹配整个字符串,然后回溯。在回溯四个字符之后,<code>*/</code>找到了匹配项。这并不是我们想要的结果,原本的意图是找到简单的注释,而不是在整个代码中找到注释的结束符。<br>由于这样的机制,我们可以说重复算子(+,<em>,?和{})具有贪婪属性,意味着这样的算子会尽可能多的匹配,并且回溯。如果你在这些算子后面接了<code>?</code> (+?, </em>?, ??, {}?),这些算子就不再贪婪,而是尽可能少的去匹配,只有在不符合最小匹配的时候才去查找更多的匹配项。<br>这就是我们在本例中想要的结果。星号需要查找的是最小的<code>*/</code>匹配项,只需要找到一个注释块。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">stripComments</span>(<span class="params">code</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> code.replace(<span class="regexp">/\/\/.*|\/\*[^]*?\*\//g</span>, <span class="string">""</span>);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(stripComments(<span class="string">"1 /* a */+/* b */ 1"</span>));</span><br><span class="line"><span class="comment">// → 1 + 1</span></span><br></pre></td></tr></table></figure><p>正则表达式的很多bug就是,在该使用非贪婪算子的时候使用了贪婪算子。使用重复算子的时候,优先考虑非贪婪算子。</p><hr><h3 id="动态创建正则表达式对象"><a href="#动态创建正则表达式对象" class="headerlink" title="动态创建正则表达式对象"></a>动态创建正则表达式对象</h3><p>当你在写代码的时候,总有一些时候,你会不知道确切的要匹配的模式。比如说你想要在一个字符串中找出用户名,并用下划线标示。因为只有在程序跑起来之后才能知道用户名,所以你不可能用结合斜杠的查找方法。<br>但是你可以用一个正则表达式构造函数去做这件事,这里给出一个例子: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name = <span class="string">"harry"</span>;</span><br><span class="line"><span class="keyword">var</span> text = <span class="string">"Harry is a suspicious character."</span>;</span><br><span class="line"><span class="keyword">var</span> regexp = <span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">"\\b("</span> + name + <span class="string">")\\b"</span>, <span class="string">"gi"</span>);</span><br><span class="line"><span class="built_in">console</span>.log(text.replace(regexp, <span class="string">"_$1_"</span>));</span><br><span class="line"><span class="comment">// → _Harry_ is a suspicious character.</span></span><br></pre></td></tr></table></figure><p>在这里我们使用双斜杠去表示<code>\b</code>边界符,因为这里我们写的是一个普通字符串,而不是一个斜杠包含的正则表达式。<code>RegExp</code>的第二个参数<code>gi</code>的意思是全局查找,而且大小写敏感。<br>但如果有个中二少年的名字是<code>dea+hl[]rd</code>,这就需要一个不敏感的正则表达式才能匹配,本例中检测不到这样的名字。<br>为了正常运行,我们在任何不确定的字符前都加上反斜杠。但是在任一字母前面加反斜杠,并不是一个好的习惯,比如<code>\b</code>和<code>\n</code>都有它们的特殊含义。但转义所有非字母或者空格都是安全的。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name = <span class="string">"dea+hl[]rd"</span>;</span><br><span class="line"><span class="keyword">var</span> text = <span class="string">"This dea+hl[]rd guy is super annoying."</span>;</span><br><span class="line"><span class="keyword">var</span> escaped = name.replace(<span class="regexp">/[^\w\s]/g</span>, <span class="string">"\\><"</span>);</span><br><span class="line"><span class="keyword">var</span> regexp = <span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">"\\b("</span> + escaped + <span class="string">")\\b"</span>, <span class="string">"gi"</span>);</span><br><span class="line"><span class="built_in">console</span>.log(text.replace(regexp, <span class="string">"_$1_"</span>));</span><br><span class="line"><span class="comment">// → This _dea+hl[]rd_ guy is super annoying.</span></span><br></pre></td></tr></table></figure><hr><h3 id="查找"><a href="#查找" class="headerlink" title="查找"></a>查找</h3><p>正则表达式没有内置字符串的<code>indexOf</code>方法,但是它有别的方法,<code>search</code>,并且该方法只能被正则表达式调用。类似于<code>indexOf</code>,<code>search</code>返回的是表达式找到的匹配项的第一个位置,-1表示没有匹配项。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">" word"</span>.search(<span class="regexp">/\S/</span>));</span><br><span class="line"><span class="comment">// → 2</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">" "</span>.search(<span class="regexp">/\S/</span>));</span><br><span class="line"><span class="comment">// → -1</span></span><br></pre></td></tr></table></figure><p>不友好的是,<code>search</code>方法不能指定偏移(<code>indexOf</code>的第二个参数是偏移量)。</p><hr><h3 id="LastIndex属性"><a href="#LastIndex属性" class="headerlink" title="LastIndex属性"></a><code>LastIndex</code>属性</h3><p><code>exec</code>方法同样也有没有提供一个方便的给定开始检索的属性,但提供了一个不太方便的办法。<br>正则表达式对象也有自己的属性。其中的一个属性就是<code>source</code>,它包含了原始字符串。另一个属性是<code>lastIndex</code>,在某些情况下,它能够控制下一个检索开始的位置。<br>如果要使用这些属性,必须开启全局选项,而且<code>exec</code>方法必须能找到匹配项。再说一句,一个更合理的方法是给<code>exec</code>多传递一个参数,但是JavaScript没有给正则表达式提供这样的接口。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> pattern = <span class="regexp">/y/g</span>;</span><br><span class="line">pattern.lastIndex = <span class="number">3</span>;</span><br><span class="line"><span class="keyword">var</span> match = pattern.exec(<span class="string">"xyzzy"</span>);</span><br><span class="line"><span class="built_in">console</span>.log(match.index);</span><br><span class="line"><span class="comment">// → 4</span></span><br><span class="line"><span class="built_in">console</span>.log(pattern.lastIndex);</span><br><span class="line"><span class="comment">// → 5</span></span><br></pre></td></tr></table></figure><p>如果匹配成功,<code>exec</code>自动更新<code>lastIndex</code>属性的值为匹配的后面一个位置。如果没有匹配项,<code>lastIndex</code>重新设置为0,同时新建的正则表达式这个属性也是0。<br>当使用全局正则表达式多次调用<code>exec</code>,自动更新<code>lastIndex</code>导致问题出现。你的正则表达式会从上一次调用之后的位置之后开始。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> digit = <span class="regexp">/\d/g</span>;</span><br><span class="line"><span class="built_in">console</span>.log(digit.exec(<span class="string">"here it is: 1"</span>));</span><br><span class="line"><span class="comment">// → ["1"]</span></span><br><span class="line"><span class="built_in">console</span>.log(digit.exec(<span class="string">"and now: 1"</span>));</span><br><span class="line"><span class="comment">// → null</span></span><br></pre></td></tr></table></figure><p>另一个有意思的全局反应就是,它改变了<code>match</code>方法对字符串的作用。当调用一个全局正则表达式,它不是像<code>exec</code>一样返回一个数组,<code>match</code>会返回所有匹配的字符串,并组成一个数组。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="string">"Banana"</span>.match(<span class="regexp">/an/g</span>));</span><br><span class="line"><span class="comment">// → ["an", "an"]</span></span><br></pre></td></tr></table></figure><p>所以要小心使用全局表达式。只在适当的时候使用,调用<code>replace</code>还有调用<code>lastIndex</code>的时候使用,通常也只有这两个地方会用到。</p><hr><h3 id="循环匹配"><a href="#循环匹配" class="headerlink" title="循环匹配"></a>循环匹配</h3><p>一种常见的模式就是用<code>lastIndex</code>和<code>exec</code>在循环体内扫描,找出匹配的字符串。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> input = <span class="string">"A string with 3 numbers in it... 42 and 88."</span>;</span><br><span class="line"><span class="keyword">var</span> number = <span class="regexp">/\b(\d+)\b/g</span>;</span><br><span class="line"><span class="keyword">var</span> match;</span><br><span class="line"><span class="keyword">while</span> (match = number.exec(input))</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Found"</span>, match[<span class="number">1</span>], <span class="string">"at"</span>, match.index);</span><br><span class="line"><span class="comment">// → Found 3 at 14</span></span><br><span class="line"><span class="comment">// Found 42 at 33</span></span><br><span class="line"><span class="comment">// Found 88 at 40</span></span><br></pre></td></tr></table></figure><p>这里使用了赋值表达式(=)。使用<code>match = number.exec(input)</code>,作为<code>while</code>成立的条件,每次迭代的时候执行匹配,把结果保存进变量,当没有匹配项的时候循环结束。</p><hr><h3 id="解析INI文件"><a href="#解析INI文件" class="headerlink" title="解析INI文件"></a>解析INI文件</h3><p>做为本章的总结,我们来看一个使用正则表达式的实际问题。想象我们正在编写一个可以自动从往上收集敌人信息的程序。(我们并不是真的在这里写这个程序,只是读取配置文件的部分,不好意思让你失望了)配置文件如下: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">searchengine=http://www.google.com/search?q=$1</span><br><span class="line">spitefulness=9.7</span><br><span class="line">; comments are preceded by a semicolon...</span><br><span class="line">; each section concerns an individual enemy</span><br><span class="line">[larry]</span><br><span class="line">fullname=Larry Doe</span><br><span class="line">type=kindergarten bully</span><br><span class="line">website=http://www.geocities.com/CapeCanaveral/11451</span><br><span class="line">[gargamel]</span><br><span class="line">fullname=Gargamel</span><br><span class="line">type=evil sorcerer</span><br><span class="line">outputdir=/home/marijn/enemies/gargamel</span><br></pre></td></tr></table></figure><p>具体的格式化规则(被广泛的使用,称做INI文件)如下:</p><ul><li>忽略空行和以分号开头的行</li><li>独立出[and]连接的句子</li><li>包含文数字后面加<code>=</code>的行,在当前部分增加一个设置</li><li>其他任何都是无效的</li></ul><p>我们的任务就是像上述要求把字符串转变成数组对象,每一项都有一个<code>name</code>属性,还有一个设置数组。每一个部分我们都需要这样一个对象,并且在开头还需要一个全局设置。<br>因为格式化需要逐行执行,开始就是需要把文件按行分割。在<a href="http://eloquentjavascript.net/06_object.html#split" target="_blank" rel="noopener">第六章</a>中我们讲过用<code>string.split("\n")</code>实现。但是在某些操作系统中,不仅使用换行符分割行,而是使用回车加换行符(”\r\n”)。正则表达式也可以作为<code>split</code>方法的参数,我们可以用正则表达式<code>/\r?\n/</code>去正确的分割<code>\n</code>或者<code>\r\n</code>换行的文件。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">parseINI</span>(<span class="params">string</span>) </span>{</span><br><span class="line"> <span class="comment">// Start with an object to hold the top-level fields</span></span><br><span class="line"> <span class="keyword">var</span> currentSection = {<span class="attr">name</span>: <span class="literal">null</span>, <span class="attr">fields</span>: []};</span><br><span class="line"> <span class="keyword">var</span> categories = [currentSection];</span><br><span class="line"> </span><br><span class="line"> string.split(<span class="regexp">/\r?\n/</span>).forEach(<span class="function"><span class="keyword">function</span>(<span class="params">line</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> match;</span><br><span class="line"> <span class="keyword">if</span> (<span class="regexp">/^\s*(;.*)?$/</span>.test(line)) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (match = line.match(<span class="regexp">/^\[(.*)\]$/</span>)) {</span><br><span class="line"> currentSection = {<span class="attr">name</span>: match[<span class="number">1</span>], <span class="attr">fields</span>: []};</span><br><span class="line"> categories.push(currentSection);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (match = line.match(<span class="regexp">/^(\w+)=(.*)$/</span>)) {</span><br><span class="line"> currentSection.fields.push({<span class="attr">name</span>: match[<span class="number">1</span>],</span><br><span class="line"> value: match[<span class="number">2</span>]});</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"Line '"</span> + line + <span class="string">"' is invalid."</span>);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> categories;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这行代码会逐行去运行,运行的时候不断更新“当前部分”。首先,它用表达式<code>/^\s*(;.*)?$/</code>检测该行是不是应该被忽略。你知道它怎么运行吗?在括号内部的部分匹配的是注释,<code>?</code>确保匹配行只包含空格。<br>如果该行不是注释,代码会去检测该行是不是开始了一个新的部分。如果是,它会新建一个对象,添加子变量。<br>最后有意思的部分就是,如果该行是常规文字,那么就添加到当前部分的对象。<br>如果某行不符合任一上述规则,函数抛出错误。<br>注意要经常使用<code>^</code>和<code><div class="post-content",确保表达式匹配的是整个行,而不只是其中一部分。如果不注意这些问题在大部分代码中也可以正常运行,但是有时会表现得很奇怪,这样的bug很难追踪。</code>if (match = string.match(…))<code>和</code>while<code>条件的功能类似。你经常不能确定调用是不是能够成功匹配,所以对于这个检验,结果对象只能从</code>if<code>条件内部获得。为了不破坏</code>if<code>的结构,在</code>if`条件内,我们将匹配结果赋值给一个变量,并且立即使用。</p><hr><h3 id="国际字符"><a href="#国际字符" class="headerlink" title="国际字符"></a>国际字符</h3><p>由于JavaScript最初设计简单,而且这一简单的设置再后来被当作标准确定下来,JavaScript中正则表达式对于非英语字符的处理很差。举个例子,对于JavaScript正则表达式,一个字母字符仅限于26个拉丁字母(包含大小写),还有下划线字符。像字符é或者β就不会匹配<code>\w</code>,而且会匹配<code>\W</code>(非字符类)。<br>由于一个奇怪的历史事件,<code>\s</code>没有这个问题,可以匹配所有标准Unicode空格字符,包括不间断空格和蒙古语元音分隔符。<br>在一些编程语言中,正则表达式有特殊的规则去匹配所有的Unicode字符,比如“all uppercase letters”, “all punctuation”, 或者 “control characters”。JavaScript也计划添加类似支持,但近期可能不会实现。</p><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>正则表达式是代表字符串中某个模式的对象,拥有自己的语法去表达某个模式。</p><table><thead><tr><th>Expression</th><th>Meaning</th></tr></thead><tbody><tr><td>/abc/</td><td>A sequence of characters</td></tr><tr><td>/[abc]/</td><td>Any character from a set of characters</td></tr><tr><td>/[^abc]/</td><td>Any character not in a set of characters</td></tr><tr><td>/[0-9]/</td><td>Any character in a range of characters</td></tr><tr><td>/x+/</td><td>One or more occurrences of the pattern x</td></tr><tr><td>/x+?/</td><td>One or more occurrences, nongreedy</td></tr><tr><td>/x*/</td><td>Zero or more occurrences</td></tr><tr><td>/x?/</td><td>Zero or one occurrence</td></tr><tr><td>/x{2,4}/</td><td>Between two and four occurrences</td></tr><tr><td>/(abc)/</td><td>A group</td></tr><tr><td>/\d/</td><td>Any digit character</td></tr><tr><td>/\w/</td><td>An alphanumeric character (“word character”)</td></tr><tr><td>/\s/</td><td>Any whitespace character</td></tr><tr><td>/./</td><td>Any character except newlines</td></tr><tr><td>/\b/</td><td>A word boundary</td></tr><tr><td>/^/</td><td>Start of input</td></tr><tr><td>/$/</td><td>End of input</td></tr></tbody></table><p>正则表达式含有<code>test</code>内置方法,可以检测给定的字符串是否匹配。还有<code>exec</code>方法,当检测到匹配项,返回一个数组包含所有的匹配项。这样的数组具有<code>index</code>属性,指向匹配项开始的位置。<br>相对于正则表达式,字符串对象有内置的<code>match</code>方法,还有<code>search</code>方法去检测一个匹配值,只返回第一个匹配值的位置。<code>replace</code>方法可以用一个字符串替换掉匹配项。另外,还可以传递一个函数作为<code>replace</code>的参数,会基于匹配文字和匹配组新建字符串。<br>正则表达式也有可选项,写在闭合斜杠后。<code>i</code>表示大小写不敏感,<code>g</code>表示全局匹配,这样就可以使<code>replace</code>方法不止替换第一项,而是替换所有匹配项。<br><code>RegExp</code>构造函数可以用作从字符串创建一个正则表达式值。<br>正则表达式非常强大但是不容易使用。它很大程度上简化了计算,但是也会由于应用的复杂导致失控。对正则表达式的初步了解是不够的,而一旦掌握它,你就会疯狂的爱上它并且想用它表示一切东西。</p>]]></content>
<categories>
<category> JavaScript </category>
</categories>
</entry>
<entry>
<title>3D Convex Hull</title>
<link href="/posts/16861/"/>
<content type="html"><![CDATA[<p>本方法适用于3D点云的凸包的提取,使用python实现。<br>这里用的方法是对quick hull做了一点小小的改进,主要分为两大块内容,<code>初始化</code>和<code>迭代</code>。<a id="more"></a></p><p><br></p><h3 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h3><h4 id="构建初始四面体"><a href="#构建初始四面体" class="headerlink" title="构建初始四面体"></a>构建初始四面体</h4><p>为了在初始化过程中构建一个相对比较大的四面体,我们需要分别找到6个最值点,分别是<code>X</code>,<code>Y</code>或者<code>Z</code>轴上的最大或者最小值点。找出6个点中距离最远的两个点,构建一条线。再找出距离这条线最远的点,构建一个面。再找出距离这个面最远的点,构建初始四面体。</p><h4 id="外部点分配"><a href="#外部点分配" class="headerlink" title="外部点分配"></a>外部点分配</h4><p>在这里,我们将所有点分为两类,即四面体内部点和外部点。内部点由于已经位于凸包内,所以在以后的过程中不予考虑。同时称外部点为激活点。对于每一个激活点,我们把它分配给第一个检测到的,在该点附近的面(可见的面)。这样每一个面就拥有属于自己的一个点集。</p><h4 id="初始点、面集"><a href="#初始点、面集" class="headerlink" title="初始点、面集"></a>初始点、面集</h4><p>构建初始激活点集,面集。</p><hr><h3 id="迭代"><a href="#迭代" class="headerlink" title="迭代"></a>迭代</h3><h4 id="检测每一个面的附属点"><a href="#检测每一个面的附属点" class="headerlink" title="检测每一个面的附属点"></a>检测每一个面的附属点</h4><p>检测每一个面是否有附属点,如果有的话继续迭代,虽然没有附属点的面不会被压入堆栈</p><h4 id="从该面的附属点集中找到最远点"><a href="#从该面的附属点集中找到最远点" class="headerlink" title="从该面的附属点集中找到最远点"></a>从该面的附属点集中找到最远点</h4><h4 id="找到最远点可见的所有面"><a href="#找到最远点可见的所有面" class="headerlink" title="找到最远点可见的所有面"></a>找到最远点可见的所有面</h4><p>这些可见的面必须是与当前面相邻,在这里这些面被称为light faces。把这些面存储起来,下一步使用。</p><h4 id="提取边缘线"><a href="#提取边缘线" class="headerlink" title="提取边缘线"></a>提取边缘线</h4><p>显然,从最远点看过去,所有的可见面会构成一个闭合的多边形。这里我们提取这个封闭多边形的边缘线,每一条边和最远点组成新的面。</p><h4 id="外部点分配-1"><a href="#外部点分配-1" class="headerlink" title="外部点分配"></a>外部点分配</h4><p>这一步骤和步骤1.2完全一样,而且同样凸包内部点直接可以忽略。</p><h4 id="新的面压入堆栈"><a href="#新的面压入堆栈" class="headerlink" title="新的面压入堆栈"></a>新的面压入堆栈</h4><p>没有附属点的面被忽略。</p><hr><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p><a href="https://github.com/ChenyuZuoo/GIS_analysis" target="_blank" rel="noopener">主要代码</a></p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://thomasdiewald.com/blog/?p=1888" target="_blank" rel="noopener">Convex Hull 3D – Quickhull Algorithm</a><br>[2] O’Rourke, J. (1998). Computational Geometry in C. Cambridge University Press, UK.<br>[3] <a href="https://github.com/gdgoldlion/Math-Note-for-Game-Dev/blob/master/%E7%AC%AC1%E7%AB%A0%EF%BC%9A%E5%90%91%E9%87%8F/1.8%20%E6%B7%B7%E5%90%88%E7%A7%AF.md" target="_blank" rel="noopener">混合积</a></p>]]></content>
<categories>
<category> Python </category>
</categories>
<tags>
<tag> algorithm </tag>
</tags>
</entry>
<entry>
<title>Mac下tomcat的安装与配置</title>
<link href="/posts/12396/"/>
<content type="html"><![CDATA[<h3 id="下载及安装"><a href="#下载及安装" class="headerlink" title="下载及安装"></a><a href="#下载及安装" title="下载及安装"></a>下载及安装</h3><p>下载并安装Java SE,下载对应版本的Tomcat,版本对应关系tomcat给出了<a href="http://tomcat.apache.org/whichversion.html" target="_blank" rel="noopener">文档</a>. 我下载之后把<code>apache-tomcat-7.0.75.zip</code>放在<code>Application</code>目录下,方便起见改名为<code>tomcat</code>。mac应该下载<code>tar.gz</code>文件,<code>zip</code>文件会报错。<br>查看java版本 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">java -version</span><br><span class="line">java version <span class="string">"1.8.0_121"</span></span><br><span class="line">Java(TM) SE Runtime Environment (build 1.8.0_121-b13)</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)</span><br></pre></td></tr></table></figure><hr><h3 id="JAVA-HOME配置"><a href="#JAVA-HOME配置" class="headerlink" title="JAVA_HOME配置"></a>JAVA_HOME配置</h3><p>检查JAVA_HOME<br>在terminal中查看JAVA_HOME地址 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/ <span class="built_in">echo</span> <span class="variable">$JAVA_HOME</span></span><br><span class="line">/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/</span><br></pre></td></tr></table></figure><p>本机下载安装的是Java1.8.0,JAVA_HOME地址有错,可以手动修改。 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vim /etc/profile</span><br></pre></td></tr></table></figure><p>然后按下<code>i</code>进入vim的插入模式,在文件尾部修改JAVA_HOME路径 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">JAVA_HOME=<span class="string">"/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/"</span></span><br><span class="line"><span class="built_in">export</span> JAVA_HOME</span><br><span class="line">CLASS_PATH=<span class="string">"<span class="variable">$JAVA_HOME</span>/lib"</span></span><br><span class="line">PATH=<span class="string">".<span class="variable">$PATH</span>:<span class="variable">$JAVA_HOME</span>/bin"</span></span><br></pre></td></tr></table></figure><p>然后<code>:wq!</code>保存退出。想要路径马上生效,输入 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> /etc/profile</span><br></pre></td></tr></table></figure><p>然后查看JAVA_HOME路径,或者<code>cd</code>到具体路径验证 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> <span class="variable">$JAVE_HOME</span></span><br></pre></td></tr></table></figure><hr><h3 id="运行tomcat服务"><a href="#运行tomcat服务" class="headerlink" title="运行tomcat服务"></a>运行tomcat服务</h3><p><code>cd</code>到tomcat的<code>bin</code>目录下 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./catalina.sh run</span><br></pre></td></tr></table></figure><p>如果JAVA_HOME有错误,会抛出如下问题。(修改方法见上文) </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">bin ./catalina.sh run</span><br><span class="line">Using CATALINA_BASE: /Users/zuochenyu/.Trash/tomcat</span><br><span class="line">Using CATALINA_HOME: /Users/zuochenyu/.Trash/tomcat</span><br><span class="line">Using CATALINA_TMPDIR: /Users/zuochenyu/.Trash/tomcat/temp</span><br><span class="line">Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/</span><br><span class="line">Using CLASSPATH: /Users/zuochenyu/.Trash/tomcat/bin/bootstrap.jar:/Users/zuochenyu/.Trash/tomcat/bin/tomcat-juli.jar</span><br><span class="line">./catalina.sh: line 366: /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home//bin/java: No such file or directory</span><br><span class="line">./catalina.sh: line 366: <span class="built_in">exec</span>: /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home//bin/java: cannot execute: No such file or directory</span><br></pre></td></tr></table></figure><p>如果出现错误 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">permission denied: ./catalina.sh</span><br></pre></td></tr></table></figure><p>首先请<code>pwd</code>检查当前路径是否正确,然后检查tomcat的版本号是否与java版本相对应。</p><hr><h3 id="查看网页"><a href="#查看网页" class="headerlink" title="查看网页"></a>查看网页</h3><p>tomcat默认的端口是8080,在浏览器中打开<code>http://localhost:8080/</code><br>看到的页面应该是这样<br><img src="/images/tomcat.png" alt="tomcat"></p><hr><h3 id="关闭服务"><a href="#关闭服务" class="headerlink" title="关闭服务"></a>关闭服务</h3><p>在terminal中<code>command+c</code>或者在tomcat<code>bin</code>目录下输入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./shutdown.sh</span><br></pre></td></tr></table></figure><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://www.jianshu.com/p/bd4e4937418b" target="_blank" rel="noopener">Mac OS X 搭建Java环境</a><br>[2] <a href="https://www.ntu.edu.sg/home/ehchua/programming/howto/Tomcat_HowTo.html" target="_blank" rel="noopener">How to Install Apache Tomcat 8 (on Windows, Mac OS, Ubuntu) and Get Started with Java Servlet Programming</a><br>[3] <a href="http://stackoverflow.com/questions/3092049/intellij-says-cannot-run-program-path-to-tomcat-bin-catalina-sh-error-13-per" target="_blank" rel="noopener">StackOverFlow: IntelliJ says ‘cannot run program ‘/path/to/tomcat/bin/catalina.sh’ error=13 permission denied</a></p>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> installation </tag>
</tags>
</entry>
<entry>
<title>Javac无法编译Servlet</title>
<link href="/posts/23246/"/>
<content type="html"><![CDATA[<p>编译环境:MAC OS</p><p>编译servlet需要servlet API,但servlet API不是JDK的一部分。如果直接用<code>javac</code>去编译会报错: <a id="more"></a></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">classes javac HelloServlet.java </span><br><span class="line">HelloServlet.java:<span class="number">3</span>: error: <span class="keyword">package</span> javax.servlet does not exist</span><br><span class="line"><span class="keyword">import</span> javax.servlet.*;</span><br><span class="line">^</span><br><span class="line">HelloServlet.java:<span class="number">4</span>: error: <span class="keyword">package</span> javax.servlet.http does not exist</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.*;</span><br><span class="line">^</span><br><span class="line">HelloServlet.java:<span class="number">6</span>: error: cannot find symbol</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloServlet</span> <span class="keyword">extends</span> <span class="title">HttpServlet</span> </span>{</span><br><span class="line"> ^</span><br><span class="line"> symbol: <span class="class"><span class="keyword">class</span> <span class="title">HttpServlet</span></span></span><br><span class="line">HelloServlet.java:8: error: cannot find symbol</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doGet</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span></span><br><span class="line"><span class="function"> ^</span></span><br><span class="line"><span class="function"> symbol: class HttpServletRequest</span></span><br><span class="line"><span class="function"> location: class HelloServlet</span></span><br><span class="line"><span class="function">HelloServlet.java:8: error: cannot find symbol</span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doGet</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span></span><br><span class="line"><span class="function"> ^</span></span><br><span class="line"><span class="function"> symbol: class HttpServletResponse</span></span><br><span class="line"><span class="function"> location: class HelloServlet</span></span><br><span class="line"><span class="function">HelloServlet.java:9: error: cannot find symbol</span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException, ServletException </span>{</span><br><span class="line"> ^</span><br><span class="line"> symbol: <span class="class"><span class="keyword">class</span> <span class="title">ServletException</span></span></span><br><span class="line"> location: class HelloServlet</span><br><span class="line">HelloServlet.java:<span class="number">7</span>: error: method does not override or implement a method from a supertype</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> ^</span><br><span class="line"><span class="number">7</span> errors</span><br></pre></td></tr></table></figure><p>Tomcat提供了一个备份文件<code><TOMCAT_HOME>/lib/servlet-api.jar</code>。在编译时候我们需要把这个<code>JAR</code>文件用<code>-cp</code>命令包含进来。 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Assume that Tomcat is installed in /Applications/tomcat</span></span><br><span class="line"><span class="comment">// Change directory to the source file</span></span><br><span class="line">cd /Applications/tomcat/webapps/hello/WEB-INF/classes</span><br><span class="line"></span><br><span class="line"><span class="comment">// Compile</span></span><br><span class="line">javac -cp .:/Applications/tomcat/lib/servlet-api.jar HelloServlet.java</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> error shooting </tag>
</tags>
</entry>
<entry>
<title>个人博客搜索引擎优化</title>
<link href="/posts/40228/"/>
<content type="html"><![CDATA[<h3 id="提交sitemap"><a href="#提交sitemap" class="headerlink" title="提交sitemap"></a>提交sitemap</h3><blockquote><p>站点地图是一种文件,您可以通过该文件列出您网站上的网页,从而将您网站内容的组织架构告知 Google 和其他搜索引擎。Googlebot 等搜索引擎网页抓取工具会读取此文件,以便更加智能地抓取您的网站。<br>此外,站点地图能够提供与其中所列网页相关的宝贵元数据:元数据是网页的相关信息,例如此网页的上次更新时间、更改频率及其重要性(与相应网站中的其他网址相较而言)。</p></blockquote><p>对于新建立的网站,Google和百度可能找不到,Googlebot或是百度的机器人必须先抓取到网站信息,才能把它收入到搜索索引中。创建sitemap并提交到Google或者百度,这是极其重要的一步。<br>提交sitemap之前首先要对网站进行验证,也就是所有者的证明。一般做法是下载官方验证文件,放在网站根目录下,就可以验证网站。对于hexo用户,在hexo编译过程中,会对下载的文件进行渲染,就会在页面内生成别的标签,不利于网站验证。所以需要在网站配置文件<code>_config.yml</code>中修改验证文件的渲染属性,比如我设置忽略渲染 </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">skip_render: [google2b659428d9daf7b6.html, baidu_verify_65gIf28eKK.html]</span><br></pre></td></tr></table></figure><p>另外2016年1月以后新建的GitHub Pages默认强制<code>https</code>,而百度站长工具不支持验证<code>https</code>的网站。错误信息为301: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">不到一分钟前xxx.github.io使用文件验证验证失败,原因:未知原因:301。</span><br><span class="line">问题分析&解决办法: 未知原因:301。</span><br></pre></td></tr></table></figure><h3 id="标题和元标签"><a href="#标题和元标签" class="headerlink" title="标题和元标签"></a>标题和元标签</h3><p>标题是很重要的一部分,告诉用户和搜索引擎网页的主题,<code><title></code>标签通常包含在<code><head></code>标签内。当然标题会作为搜索结果的一部分出现,避免标题和网页无关,避免类似<code>Untitled</code>或者<code>New Page 1</code>这种默认标题。避免使用冗长没什么用的标题,更不要在标题里堆砌关键词。<br><code><head></code>标签内还包含有<code><meta></code>标签,也就是元标签。网页的元标签可以由一两个词句或者段落组成。元标签不会出现在网页正文中,但是Google有可能会根据元标签来生成网页摘要。元标签应该精准的描述网页内容,而且最好为每一个网页创建不同的元标签(方便<code>site: operator</code>查询)。</p><h3 id="优化URL"><a href="#优化URL" class="headerlink" title="优化URL"></a>优化URL</h3><p>简单易读懂的URL能更有力的表达网页内容信息,有助于搜索引擎的抓取。应该避免冗长晦涩词语的出现,因为用户有可能会判断为不需要的信息,直接去掉一部分,导致URL失效。<br>避免多层子目录的嵌套,避免自动生成的类似<code>page1</code>这样和内容无关的页面名,避免大写。<br>另外还需要避免中文,有一些URL中的中文可能不被识别,导致失效。</p><h3 id="有利于检索的网站结构"><a href="#有利于检索的网站结构" class="headerlink" title="有利于检索的网站结构"></a>有利于检索的网站结构</h3><p>导航+层叠式的布局比较有利于用户和搜索引擎的检索。虽然Google返回的是一个特定页面,但是Google也会只能的去理解这一页究竟处在网站的什么位置。导航应该尽量精简有效,避免太过细分的网站结构,比如用户需要点击20次以上才能找到他们想要的内容。</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>尽量使用文字链接,一方面是便于搜索引擎抓取,另一方面某些flash或者JavaScript可能不被所有的设备支持。<br>给图片加上特定的文字描述,提高被检索几率。如果图片作为连接使用,一定要加上<code>alt</code>文本。<br>设置<code>rel=“nofollow”</code>打击垃圾留言。</p><hr><p>最后,出色的内容才是网站脱颖而出的关键!</p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://support.google.com/webmasters/answer/156184?hl=zh-Hans" target="_blank" rel="noopener">了解站点地图</a><br>[2] 《谷歌搜索引擎优化初学者指南》</p>]]></content>
<categories>
<category> Network </category>
</categories>
</entry>
<entry>
<title>「译」JavaScript高阶函数(Eloquent JavaScript 第五章)</title>
<link href="/posts/28467/"/>
<content type="html"><![CDATA[<p>此文翻译《Eloquent Javascript》中第五章,<a href="http://eloquentjavascript.net/05_higher_order.html" target="_blank" rel="noopener">Higher-Order Functions</a>,侵删。<br>该书有<a href="https://book.douban.com/subject/19933548/" target="_blank" rel="noopener">中文译本</a>出版。此译文仅作交流学习之用。</p><hr><blockquote><p>Tzu-li和Tzu-ssu在互相吹嘘他们最近程序的代码行数,Tzu-li说他写了20万行,而且注释不算在内,Tzu-ssu说,嘘,我的已经接近一百万行了。Yuan-Ma老师说,我最好的程序只有五百行。听到这里,Tzu-li和Tzu-ssu恍然大悟。<br>———— Master Yuan-Ma, The Book of Programming</p><p>软件设计的路有两条:一条是设计简单,使其显然没有缺陷;另一条是设计复杂,使其没有明显的缺陷。<br>———— C.A.R. Hoare, 1980 ACM Turing Award Lecture</p></blockquote><p>一个大的程序是非常消耗资源的,不是简单的因为搭建程序所消耗的时间。程序的大小总是和它的复杂性相关,太复杂的程序会让程序员们更加困惑。复杂的程序往往会带来更多的错误。足够大的程序,同样有足够大的空间去隐藏各种各样难以调试的错误。<br>我们先简单回顾一下序章中的两个代码段,第一段代码的含义显而易见,共6行: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> total = <span class="number">0</span>, count = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">while</span> (count <= <span class="number">10</span>) {</span><br><span class="line"> total += count;</span><br><span class="line"> count += <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(total);</span><br></pre></td></tr></table></figure><p>第二段代码依赖于两个外部函数,只有一行: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(sum(range(<span class="number">1</span>, <span class="number">10</span>)));</span><br></pre></td></tr></table></figure><p>哪个代码段更有可能含有错误呢?<br>如果我们把<code>sum</code>和<code>range</code>函数也算在内,第二段代码甚至会比第一段代码更长。但依旧,第二段代码的正确率更高。<br>第二段代码正确率高的原因在于,它在一句话内就包含了相应问题的解决方式。某个范围之内的求和问题本身,并不包括循环和计数器。它只包括数字范围和数字求和。<br>这句代码的定义中(<code>sum</code>和<code>range</code>函数),还是会包含循环,计数器,还有别的必要的细节。但是分开表达的每个函数,都是很简单的概念,这就比融合在一起的一个程序,出错的概率小很多。</p><hr><h3 id="抽象"><a href="#抽象" class="headerlink" title="抽象"></a>抽象</h3><p>在编程环境中,这些表达式通常被称为抽象。抽象能够隐藏掉细节,把问题抽象到一个更高的层次,更有利于探讨问题本身。<br>在编程过程中,我们不能总希望所有的“简单功能”(<code>sum</code>,<code>range</code>等)都已经存在。所以,有些人可能会按照自然计算的细节一步一步的让计算机实现某个功能。<br>对一个程序员来说,问题的解决需要需要变得“不那么自然”,需要意识到,把一个新的<code>概念</code>抽象为一个新的<code>功能</code>。</p><hr><h3 id="抽象字符串遍历"><a href="#抽象字符串遍历" class="headerlink" title="抽象字符串遍历"></a>抽象字符串遍历</h3><p>我们已经见过了很多次的常见函数,就是做抽象化很好的例子。但是有时候也具有一些不足。<br>在<a href="http://eloquentjavascript.net/04_data.html#data" target="_blank" rel="noopener">前面的章节</a>,这种类型的<code>for</code>循环已经出现过很多次: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> array = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < array.length; i++) {</span><br><span class="line"> <span class="keyword">var</span> current = array[i];</span><br><span class="line"> <span class="built_in">console</span>.log(current);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这段代码的意思是说,在<code>console</code>中打印字符串中的每个元素。但是在这段代码中,又引入了计数器<code>i</code>,控制打印次数的循环,还有一个额外的用于打印的变量<code>current</code>增加了复杂度。除了看起来不够整齐,还为潜在的错误提供了更多的空间。我们有可能会不小心错误的复用了变量<code>i</code>,<code>length</code>拼写错为<code>lenght</code>,混淆了<code>i</code>和<code>current</code>,或者别的错误。<br>那么你能想一下,怎么样把这个过程抽象为一个函数呢?<br>首先,创建一个遍历数组中每个元素,并且同时调用<code>console.log</code>的函数并不难。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">logEach</span>(<span class="params">array</span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < array.length; i++)</span><br><span class="line"> <span class="built_in">console</span>.log(array[i]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>但是如果除了遍历数组之外我们还想做点变的事情呢?既然“做某件事”可以被表示为一个函数,函数就相当于一个值,那我们就可以将要做的事变成函数值。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">forEach</span>(<span class="params">array, action</span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < array.length; i++)</span><br><span class="line"> action(array[i]);</span><br><span class="line">}</span><br><span class="line">forEach([<span class="string">"Wampeter"</span>, <span class="string">"Foma"</span>, <span class="string">"Granfalloon"</span>], <span class="built_in">console</span>.log);</span><br><span class="line"><span class="comment">// → Wampeter</span></span><br><span class="line"><span class="comment">// → Foma</span></span><br><span class="line"><span class="comment">// → Granfalloon</span></span><br></pre></td></tr></table></figure><p>(在某些浏览器中,并不可以这样调用<code>console.log</code>,可以用<code>alert</code>替代<code>console.log</code>)<br>通常情况下,你并不会传给<code>forEach</code>函数一些预定义函数,而是传入自己写的一些函数。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> numbers = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>], sum = <span class="number">0</span>;</span><br><span class="line">forEach(numbers, <span class="function"><span class="keyword">function</span>(<span class="params">number</span>) </span>{</span><br><span class="line"> sum += number;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(sum);</span><br><span class="line"><span class="comment">// → 15</span></span><br></pre></td></tr></table></figure><p>这段代码函数体单独占一块,看起来很类似经典的<code>for</code>循环。但是,现在这个函数体是位于函数值之内,作为<code>forEach</code>函数的一个参数。这也是为什么函数以括号和分号结尾的原因。<br>在这个模型下,我们可以为现在的元素(数字)指定变量名,就比手动一个一个从数组中读出来要好。<br>事实上,我们不需要自己去写<code>forEach</code>函数。在数组中<code>forEach</code>是一个标准方法。因为数组已经默认提供了方法所要的所有元素,那么<code>forEach</code>就只需要一个变量:每个变量需要执行的函数。<br>为了说明以上非常有用,我们先来回看<a href="http://eloquentjavascript.net/04_data.html#analysis" target="_blank" rel="noopener">前面章节</a>的一个函数。这个函数包含两个数组遍历的循环。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">gatherCorrelations</span>(<span class="params">journal</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> phis = {};</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> entry = <span class="number">0</span>; entry < journal.length; entry++) {</span><br><span class="line"> <span class="keyword">var</span> events = journal[entry].events;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < events.length; i++) {</span><br><span class="line"> <span class="keyword">var</span> event = events[i];</span><br><span class="line"> <span class="keyword">if</span> (!(event <span class="keyword">in</span> phis))</span><br><span class="line"> phis[event] = phi(tableFor(event, journal));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> phis;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用<code>forEach</code>函数会让代码更简洁清爽。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">gatherCorrelations</span>(<span class="params">journal</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> phis = {};</span><br><span class="line"> journal.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">entry</span>) </span>{</span><br><span class="line"> entry.events.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (!(event <span class="keyword">in</span> phis))</span><br><span class="line"> phis[event] = phi(tableFor(event, journal));</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> phis;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><hr><h3 id="高阶函数"><a href="#高阶函数" class="headerlink" title="高阶函数"></a>高阶函数</h3><p>基于别的函数实现的函数,一种是把其他函数作为参数传入,另一种是返回一个函数,我们把这样的函数叫做<code>高阶函数</code>。如果你已经把函数当作一个普通的值,那么高阶函数的存在也没有什么特殊意义可言。这个术语来自于数学,数学中对函数和数值的概念有很大差别。<br>高阶函数是我们不仅能够抽象数值,还可以抽象‘动作’。高阶函数有几种不同的表现方式,比如,它可以用作创建新的函数。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">greaterThan</span>(<span class="params">n</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">m</span>) </span>{ <span class="keyword">return</span> m > n; };</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> greaterThan10 = greaterThan(<span class="number">10</span>);</span><br><span class="line"><span class="built_in">console</span>.log(greaterThan10(<span class="number">11</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br></pre></td></tr></table></figure><p>它还可以用作改变别的函数。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">noisy</span>(<span class="params">f</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">arg</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"calling with"</span>, arg);</span><br><span class="line"> <span class="keyword">var</span> val = f(arg);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"called with"</span>, arg, <span class="string">"- got"</span>, val);</span><br><span class="line"> <span class="keyword">return</span> val;</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line">noisy(<span class="built_in">Boolean</span>)(<span class="number">0</span>);</span><br><span class="line"><span class="comment">// → calling with 0</span></span><br><span class="line"><span class="comment">// → called with 0 - got false</span></span><br></pre></td></tr></table></figure><p>甚至它可以用来改写函数的控制流。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">unless</span>(<span class="params">test, then</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (!test) then();</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">repeat</span>(<span class="params">times, body</span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < times; i++) body(i);</span><br><span class="line">}</span><br><span class="line">repeat(<span class="number">3</span>, <span class="function"><span class="keyword">function</span>(<span class="params">n</span>) </span>{</span><br><span class="line"> unless(n % <span class="number">2</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(n, <span class="string">"is even"</span>);</span><br><span class="line"> });</span><br><span class="line">});</span><br><span class="line"><span class="comment">// → 0 is even</span></span><br><span class="line"><span class="comment">// → 2 is even</span></span><br></pre></td></tr></table></figure><p>在以上情境中,我们在<a href="http://eloquentjavascript.net/03_functions.html#scoping" target="_blank" rel="noopener">第三章</a>中讨论过的词汇作用域规则会对我们很有帮助。在前面的例子中,变量<code>n</code>就是外部函数的一个参数。因为内部函数在外部函数的作用域之内,所以它可以使用<code>n</code>。内部函数可以调用其对应外部函数的参数,相当于是普通循环和条件判断的<code>{}</code>块的作用。还有一个重要的规则,内部函数中声明的变量,并不会在外部函数中结束其生命周期。这是一件非常有利的事。</p><hr><h3 id="参数传递"><a href="#参数传递" class="headerlink" title="参数传递"></a>参数传递</h3><p>之前我们定义的<code>noisy</code>函数,包含了其他函数的参数,是一个很大的设计缺陷。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">noisy</span>(<span class="params">f</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">arg</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"calling with"</span>, arg);</span><br><span class="line"> <span class="keyword">var</span> val = f(arg);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"called with"</span>, arg, <span class="string">"- got"</span>, val);</span><br><span class="line"> <span class="keyword">return</span> val;</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果<code>f</code>传进的参数大于1,那么这里只能获得第一个参数。我们可以给它的内部函数添加一系列参数(arg1, arg2, 等等),然后都传给<code>f</code>,但一共设置多少个参数比较合适我们并不知道。这个解决方法,同时会导致<code>argument.length</code>这个方法失效。所以我们最好是每次传递同样个数的参数,却并不知道原本有几个参数。<br>为了解决这类问题,JavaScript提供了<code>apply</code>方法。我们给它传入数组(或类数组)作为参数,它会调用相应参数的函数。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">transparentWrapping</span>(<span class="params">f</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> f.apply(<span class="literal">null</span>, <span class="built_in">arguments</span>);</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以上是一个没有任何实际用途的函数,但是清晰的展示了我们感兴趣的解决办法,这个函数是根据传入的每一个参数,返回<code>f</code>对应的方法。具体就是通过传递每个<code>argument</code>到<code>apply</code>来实现。第一个传给<code>apply</code>的参数,我们这里传的是<code>null</code>,模拟了一个会被调用的方法。我们在<a href="http://eloquentjavascript.net/06_object.html#call_method" target="_blank" rel="noopener">下一章</a>中会作说明。</p><hr><h3 id="JSON"><a href="#JSON" class="headerlink" title="JSON"></a>JSON</h3><p>在JavaScript中,高阶函数经常被用于处理数组中的各个元素。<code>forEach</code>方法的应用就是最典型的例子。数组中还有很多类似的方法。我们使用另一个数据集,来熟悉这些方法。<br>几年前,有人翻越了很多史料,编著了一本关于家族姓名的史书。我翻了一下希望找到有关骑士, 海盗和炼金术士的故事,但大部分都是讲弗拉明村民。只是自己感兴趣,我提取了自己直系祖先的信息,并把它制成一个计算机可读的文件。<br>文件如下: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {"name": "Emma de Milliano", "sex": "f",</span><br><span class="line"> "born": 1876, "died": 1956,</span><br><span class="line"> "father": "Petrus de Milliano",</span><br><span class="line"> "mother": "Sophia van Damme"},</span><br><span class="line"> {"name": "Carolus Haverbeke", "sex": "m",</span><br><span class="line"> "born": 1832, "died": 1905,</span><br><span class="line"> "father": "Carel Haverbeke",</span><br><span class="line"> "mother": "Maria van Brussel"},</span><br><span class="line"> ……</span><br><span class="line"> ……</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>这种格式的数据叫做JSON(JavaScript Object Notation),被广泛用作网络数据的存储和传输格式。<br>JSON很类似JavaScript中数组和对象的书写方式,当然也有一些限制。所有属性名称必须在双引号内部,而且只允许使用简单的数据表达式:不支持函数,变量,或者任何形式的计算。JSON中不能出现注释。<br>JavaScript中提供了相应的函数,<code>JSON.stringify</code>和<code>JSON.parse</code>,可以用作数据的格式转换。第一个函数是把JavaScript作为参数,返回JSON格式编码的字符串。第二个函数传入这样的字符串,解析为原本包含的信息。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> string = <span class="built_in">JSON</span>.stringify({<span class="attr">name</span>: <span class="string">"X"</span>, <span class="attr">born</span>: <span class="number">1980</span>});</span><br><span class="line"><span class="built_in">console</span>.log(string);</span><br><span class="line"><span class="comment">// → {"name":"X","born":1980}</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">JSON</span>.parse(string).born);</span><br><span class="line"><span class="comment">// → 1980</span></span><br></pre></td></tr></table></figure><p>变量<code>ANCESTRY_FILE</code>,包含了JSON格式的字符串,可以在<a href="http://eloquentjavascript.net/code/ancestry.js" target="_blank" rel="noopener">网上下载</a>。我们来看一下如何解码这个文件,里面包含了多少人。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ancestry = <span class="built_in">JSON</span>.parse(ANCESTRY_FILE);</span><br><span class="line"><span class="built_in">console</span>.log(ancestry.length);</span><br><span class="line"><span class="comment">// → 39</span></span><br></pre></td></tr></table></figure><hr><h3 id="数组过滤"><a href="#数组过滤" class="headerlink" title="数组过滤"></a>数组过滤</h3><p>为了找出数据集中,在1924年的年轻人,以下的方法也许会有帮助。它剔除了数组中不能满足条件的人。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">filter</span>(<span class="params">array, test</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> passed = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < array.length; i++) {</span><br><span class="line"> <span class="keyword">if</span> (test(array[i]))</span><br><span class="line"> passed.push(array[i]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> passed;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(filter(ancestry, <span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> person.born > <span class="number">1900</span> && person.born < <span class="number">1925</span>;</span><br><span class="line">}));</span><br><span class="line"><span class="comment">// → [{name: "Philibert Haverbeke", …}, …]</span></span><br></pre></td></tr></table></figure><p>这段代码使用<code>test</code>作为函数值的名称,填补了代码中的‘空隙’。数组中的每一个元素,都调用了<code>test</code>函数,它的返回值决定了该值是否继续留在数组内。<br>这里需要强调,是‘filter’函数建了一个能通过其过滤条件的新数组,而不是在已有的数组中删除元素。这个函数很纯净,不会修改原数组。<br>就像<code>forEach</code>,<code>filter</code>也是数组的标准方法之一。例子只是为了说明它内部的运作机制。从现在开始,我们应该这样使用: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(ancestry.filter(<span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> person.father == <span class="string">"Carel Haverbeke"</span>;</span><br><span class="line">}));</span><br><span class="line"><span class="comment">// → [{name: "Carolus Haverbeke", …}]</span></span><br></pre></td></tr></table></figure><hr><h3 id="使用Map函数转换"><a href="#使用Map函数转换" class="headerlink" title="使用Map函数转换"></a>使用Map函数转换</h3><p>假定我们现在手上有一组人名数据,从‘祖先’数组中过滤而来。但我们现在要的是只含有名字的数组,更方便读写。<br><code>map</code>方法是对数组中每个元素执行一个函数,并为返回值创建一个新的数组。新的数组和原数组长度相等,但是数组的每一个元素内容已经被执行的函数更新。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">map</span>(<span class="params">array, transform</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> mapped = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < array.length; i++)</span><br><span class="line"> mapped.push(transform(array[i]));</span><br><span class="line"> <span class="keyword">return</span> mapped;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> overNinety = ancestry.filter(<span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> person.died - person.born > <span class="number">90</span>;</span><br><span class="line">});</span><br><span class="line"><span class="built_in">console</span>.log(map(overNinety, <span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> person.name;</span><br><span class="line">}));</span><br><span class="line"><span class="comment">// → ["Clara Aernoudts", "Emile Haverbeke",</span></span><br><span class="line"><span class="comment">// "Maria Haverbeke"]</span></span><br></pre></td></tr></table></figure><p>有趣的是,岁数超过90岁的名单,和我们之前见过的名单(1920s的年轻人)一样,这恰恰是我的数据集中离我们最近的一代。我猜是医学已经发展了。<br>就像<code>filter</code>和<code>forEach</code>函数,<code>map</code>也是数组中的一个标准方法。</p><hr><h3 id="Reduce函数的总结"><a href="#Reduce函数的总结" class="headerlink" title="Reduce函数的总结"></a>Reduce函数的总结</h3><p>另一个常见的数组计算,就是从数组中得到一个值。我们一直在用的一个例子,数字求和就是一个实例。另一个例子就是找到数据集中最早出生的那个人。<br>高阶函数中这种计算模式叫做<code>reduce</code>。你可以把它当作是对数组的一种折叠,每次执行一个元素。当对数字求和的时候,最好是从0开始,对每一个元素进行操作,把每一个元素和当前的和进行加和。<br><code>reduce</code>函数的参数,除了数组、组合方法,还需要一个开始位置。这个方法稍微比<code>filter</code>和<code>map</code>复杂一点,所以多注意一下。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reduce</span>(<span class="params">array, combine, start</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> current = start;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < array.length; i++)</span><br><span class="line"> current = combine(current, array[i]);</span><br><span class="line"> <span class="keyword">return</span> current;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(reduce([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>], <span class="function"><span class="keyword">function</span>(<span class="params">a, b</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line">}, <span class="number">0</span>));</span><br><span class="line"><span class="comment">// → 10</span></span><br></pre></td></tr></table></figure><p>数组的标准方法<code>reduce</code>如上所示,还有一个方便的用途。如果你的数组至少包含两个元素,可以允许不写开始位置。该方法默认从数组第一个数值开始计算。<br>使用<code>reduce</code>从文件中找到年纪最大的祖先,可以使用代码段如下: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(ancestry.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">min, cur</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (cur.born < min.born) <span class="keyword">return</span> cur;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">return</span> min;</span><br><span class="line">}));</span><br><span class="line"><span class="comment">// → {name: "Pauwels van Haverbeke", born: 1535, …}</span></span><br></pre></td></tr></table></figure><hr><h3 id="可组合性"><a href="#可组合性" class="headerlink" title="可组合性"></a>可组合性</h3><p>考虑到我们之前的例子是用高级函数找到出生最早的人,代码还不至于这么差: </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> min = ancestry[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">1</span>; i < ancestry.length; i++) {</span><br><span class="line"> <span class="keyword">var</span> cur = ancestry[i];</span><br><span class="line"> <span class="keyword">if</span> (cur.born < min.born)</span><br><span class="line"> min = cur;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(min);</span><br><span class="line"><span class="comment">// → {name: "Pauwels van Haverbeke", born: 1535, …}</span></span><br></pre></td></tr></table></figure><p>下面的代码增加了几个变量,代码行数虽然超过两行,但仍容易理解。<br>高阶函数的的好处就体现在当你想要组合几个函数的时候。举个例子,我们查找一下数据集中男人和女人的平均年龄。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">average</span>(<span class="params">array</span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">plus</span>(<span class="params">a, b</span>) </span>{ <span class="keyword">return</span> a + b; }</span><br><span class="line"> <span class="keyword">return</span> array.reduce(plus) / array.length;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">age</span>(<span class="params">p</span>) </span>{ <span class="keyword">return</span> p.died - p.born; }</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">male</span>(<span class="params">p</span>) </span>{ <span class="keyword">return</span> p.sex == <span class="string">"m"</span>; }</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">female</span>(<span class="params">p</span>) </span>{ <span class="keyword">return</span> p.sex == <span class="string">"f"</span>; }</span><br><span class="line"><span class="built_in">console</span>.log(average(ancestry.filter(male).map(age)));</span><br><span class="line"><span class="comment">// → 61.67</span></span><br><span class="line"><span class="built_in">console</span>.log(average(ancestry.filter(female).map(age)));</span><br><span class="line"><span class="comment">// → 54.56</span></span><br></pre></td></tr></table></figure><p>(我们还需要自己定义<code>plus</code>有点蠢,但是JavaScript中的算子不是函数,不是某个值,所以我们不能像传递参数一样传递加号。)<br>在这里我们把各个函数组合起来(确定性别,计算平均数),而不是把所有的运算都糅合进一个大循环。我们可以一个一个执行,最终找到到问题的解决办法。<br>这对书写简洁优雅的代码非常重要,但是这样清晰的结构也有所代价。</p><hr><h3 id="成本"><a href="#成本" class="headerlink" title="成本"></a>成本</h3><p>在简洁优雅的代码生存的乐土里,还有一片乌云叫做<code>低效</code>。<br>程序处理数组的过程被优雅的分割为一系列小步骤,而且每次都计算出一个新的数组。但是创建这些中间数组非常耗资源。<br>比如说,给<code>forEach</code>传递函数去处理数组,字面上非常方便也容易理解。但是JavaScript中调用方程比简单的循环体更消耗资源。<br>还有很多的技巧帮我们提高代码的清晰度。<code>抽象</code>会给原始数据和我们想要做的计算中添加一个中间层,导致机器需要处理更多的工作。这也并不是一个铁律,还有很多语言可以支持构建抽象的同时不增加开销,甚至在JavaScript中,有经验的工程师可以构建出运行更快的<code>抽象</code>。但是这个问题很常见。<br>幸运的是,大部分计算机都快到飞起。如果你处理的是一个中等大小的数据集,或者是计算时间以人的时间为标准(用户单击鼠标的时间),那写一个需要运行半毫秒的解决方案,和写一个非常棒棒的只需要十分之一毫秒计算时间的解决方案,并没有太大区别。<br>持续跟踪程序中每一小块被调用的频率,会非常有帮助。如果有嵌套的循环(不管是直接嵌套,或者是外层循环调用一个函数,最终在内层函数中结束计算的),内层的代码段会被执行N<em>M次,在这里N表示外层循环次数,M表示内层循环次数。如果内层循环还包含别的需要运行P次的循环,整个代码段就会执行N</em>M*P次,以此类推。这样可能导致一个很长的运行时间,当一个程序非常慢的时候,问题通常会被追溯到一块非常小的代码段,通常位于一个内层循环中。</p><hr><h3 id="曾曾曾曾…(祖父)"><a href="#曾曾曾曾…(祖父)" class="headerlink" title="曾曾曾曾…(祖父)"></a>曾曾曾曾…(祖父)</h3><p>我的祖父菲力贝尔·哈伯贝克也在数据集中。从他开始往上,按血统我可以追溯到名单里年纪最大的人鲍维思·凡·哈伯贝克是不是我的直系祖先。如果他是的话,我很想知道理论上我有多少DNA来源于他。<br>为了能通过父母的名字获得代表这个人的对象,我们首先建立一个能把人和名字联系起来的对象。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> byName = {};</span><br><span class="line">ancestry.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> byName[person.name] = person;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(byName[<span class="string">"Philibert Haverbeke"</span>]);</span><br><span class="line"><span class="comment">// → {name: "Philibert Haverbeke", …}</span></span><br></pre></td></tr></table></figure><p>现在,问题就不止简单是从<code>father</code>这个属性里,往上数到鲍维思一共有多少个人。在这个族谱中还有一些人和他们的表兄弟结婚。这会导致家族中的基因有些地方出现重合,说明我遗传的基因数会多过$1/2^G$,G代表鲍维思和我之间的间隔代数。这个公式基于每一代都把基因稀释为1/2。<br>思考这个问题的合理方式,就是把他当作是一种<code>reduce</code>,不断重复的把一个数组从左至右压缩到,成为一个单个的值。在本问题中,我们也同样是要把数据结构沿着族谱压缩至一个值。这个数据的形式是一个家族树,而不是一个单一的列表。<br>这里我们的压缩方式,就是找出某个给定的人的祖先。可以通过递归完成:假设给定的人为A,我们先计算出A的父母,然后计算出A的祖父母,一次类推。原则上讲,我们需要找无限个人,但实际上我们的数据集是有限的,所以总会在某个地方停下来。我们需要给压缩函数设置一个阈值,用做判断不在目标列表里的人。在本例中,这个值就是0,表示这个人和我们给定的人不享有同源DNA。<br>给定一个人,一个查找父母的函数,一个阈值,<code>reduceAcestors</code>就会从族谱中计算出一个值。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reduceAncestors</span>(<span class="params">person, f, defaultValue</span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">valueFor</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (person == <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">return</span> defaultValue;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> f(person, valueFor(byName[person.mother]),</span><br><span class="line"> valueFor(byName[person.father]));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> valueFor(person);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>内部函数<code>valueFor</code>处理单个人,但通过递归,这个函数就可以调用自己计算这个人的父母的父母。结果是,通过这个人的对象,传值给<code>f</code>,最终把实际的值返回给这个人。<br>我们通过这个计算我祖父继承了多少鲍维思·凡·哈克贝尔的基因,并把这个数字除以4。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sharedDNA</span>(<span class="params">person, fromMother, fromFather</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (person.name == <span class="string">"Pauwels van Haverbeke"</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> (fromMother + fromFather) / <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> ph = byName[<span class="string">"Philibert Haverbeke"</span>];</span><br><span class="line"><span class="built_in">console</span>.log(reduceAncestors(ph, sharedDNA, <span class="number">0</span>) / <span class="number">4</span>);</span><br><span class="line"><span class="comment">// → 0.00049</span></span><br></pre></td></tr></table></figure><p>很显然名叫鲍维思·凡·哈克贝尔的人,和鲍维思·凡·哈克贝尔(数据集中只有一个人叫这个名字)基因的相似度是100%,所以该函数返回1。所有其他人都只享有从父母处继承的一半的鲍维思·凡·哈克贝尔的基因。<br>统计学角度来讲,我和这位16世纪的人的基因有0.05%的相似度。需要提醒的是这只是统计估计,并不是真实的数据。虽然这只是一个很小的数字,但是考虑到每个人携带30亿个碱基对,在生物学上,我有些部分就源自于鲍维思。<br>我们也可以不通过<code>reduceAncestor</code>来计算。通过把成块的计算方法(压缩族谱)分解为小函数(计算基因相似度),可以提高代码的清晰度,增加代码的复用度。举个例子,下面的代码能够找出某个人祖先中年龄超过70岁的比例(根据血统查找,所以有些人可能被重复计算)。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">countAncestors</span>(<span class="params">person, test</span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">combine</span>(<span class="params">current, fromMother, fromFather</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> thisOneCounts = current != person && test(current);</span><br><span class="line"> <span class="keyword">return</span> fromMother + fromFather + (thisOneCounts ? <span class="number">1</span> : <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> reduceAncestors(person, combine, <span class="number">0</span>);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">longLivingPercentage</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> all = countAncestors(person, <span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">var</span> longLiving = countAncestors(person, <span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (person.died - person.born) >= <span class="number">70</span>;</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> longLiving / all;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(longLivingPercentage(byName[<span class="string">"Emile Haverbeke"</span>]));</span><br><span class="line"><span class="comment">// → 0.129</span></span><br></pre></td></tr></table></figure><p>对这个结果不要太认真,我们的数据集没有普遍性。但是这段代码说明了<code>reduceAncestor</code>提供给我们一个计算族谱这种数据结构的很好用的代码段。</p><hr><h3 id="捆绑"><a href="#捆绑" class="headerlink" title="捆绑"></a>捆绑</h3><p><code>捆绑(binding)</code>是所有函数都有的一个方法,它会哈村建一个可以调用原函数的新函数,但是有一些参数已经被修改。<br>下面的代码展示了<code>捆绑</code>在例子中的应用。它定义了一个函数<code>isinSet</code>来判断一个人是否在一个给定的字符串之内。为了找出那些在特定数据集的人名对象,我们需要调用<code>filter</code>。我们可以写一个函数,<code>isInSet</code>作为其中一个参数,或者部分使用<code>isInSet</code>函数。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> theSet = [<span class="string">"Carel Haverbeke"</span>, <span class="string">"Maria van Brussel"</span>,</span><br><span class="line"> <span class="string">"Donald Duck"</span>];</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isInSet</span>(<span class="params">set, person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> set.indexOf(person.name) > <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(ancestry.filter(<span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> isInSet(theSet, person);</span><br><span class="line">}));</span><br><span class="line"><span class="comment">// → [{name: "Maria van Brussel", …},</span></span><br><span class="line"><span class="comment">// {name: "Carel Haverbeke", …}]</span></span><br><span class="line"><span class="built_in">console</span>.log(ancestry.filter(isInSet.bind(<span class="literal">null</span>, theSet)));</span><br><span class="line"><span class="comment">// → … same result</span></span><br></pre></td></tr></table></figure><p>调用<code>bind</code>返回的是以<code>theSet</code>作为第一个参数的<code>isInSet</code>函数,然后是任何绑定给函数的参数。<br>第一个参数,这个例子中传递的是<code>null</code>,用作调用方法的参数,类似于<code>apply</code>的第一个参数。我会在<a href="http://eloquentjavascript.net/06_object.html#call_method" target="_blank" rel="noopener">下一章</a>中给出详细的解释。</p><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>能够把函数作为值传给别的函数,不仅仅是一个小花招,而是JavaScript中非常实用的一个方面。这个设计能够让我们在写代码的时候留有一些‘空隙’,然后用函数值来填补这些‘空隙’。<br>数组中提供了很多高阶函数,<code>forEach</code>是针对数组中每个元素进行操作;<code>filter</code>会根据过滤的元素创建一个新数组;<code>map</code>用作给每个元素执行一个函数,并把结果创建为一个新的数组;<code>reduce</code>用于把所有元素合并为一个单一的值。<br>函数都有<code>apply</code>方法,用于对不同的参数调用不同的计算方式。同时还有一个<code>bind</code>方法,用于去创建某个部分使用另一个函数的函数。</p><hr><h3 id="练习"><a href="#练习" class="headerlink" title="练习"></a>练习</h3><h4 id="过滤"><a href="#过滤" class="headerlink" title="过滤"></a>过滤</h4><p>结合<code>reduce</code>和<code>concat</code>方法,能把多个数组结合成一个包含每个元素的单个数组。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> arrays = [[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], [<span class="number">4</span>, <span class="number">5</span>], [<span class="number">6</span>]];</span><br><span class="line"><span class="comment">// Your code here.</span></span><br><span class="line"><span class="comment">// → [1, 2, 3, 4, 5, 6]</span></span><br></pre></td></tr></table></figure><h4 id="母亲和孩子的年龄差"><a href="#母亲和孩子的年龄差" class="headerlink" title="母亲和孩子的年龄差"></a>母亲和孩子的年龄差</h4><p>使用本章的数据集,计算母亲和孩子的平均年龄差(母亲生小孩时的年龄)。可以使用本章中的<code>average</code>函数。<br>注意并非所有提到的母亲都在数据集当中。使用<code>byName</code>找到名字所对应的对象,可能会有帮助。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">average</span>(<span class="params">array</span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">plus</span>(<span class="params">a, b</span>) </span>{ <span class="keyword">return</span> a + b; }</span><br><span class="line"> <span class="keyword">return</span> array.reduce(plus) / array.length;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> byName = {};</span><br><span class="line"></span><br><span class="line">ancestry.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">person</span>) </span>{</span><br><span class="line"> byName[person.name] = person;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// Your code here.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// → 31.2</span></span><br></pre></td></tr></table></figure><h4 id="历史预期寿命"><a href="#历史预期寿命" class="headerlink" title="历史预期寿命"></a>历史预期寿命</h4><p>我们查找出数据集中寿命超过90岁的人,会发现这些人质存在在最后一代中。那我们再仔细研究一下这个现象。<br>计算并显示数据集中每个世纪的平均寿命。确定一个人属于哪个世纪的方法:卒年除以100,然后进位,比如<code>Math.ceil(person.died / 100)</code>。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">average</span>(<span class="params">array</span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">plus</span>(<span class="params">a, b</span>) </span>{ <span class="keyword">return</span> a + b; }</span><br><span class="line"> <span class="keyword">return</span> array.reduce(plus) / array.length;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Your code here.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// → 16: 43.5</span></span><br><span class="line"><span class="comment">// 17: 51.2</span></span><br><span class="line"><span class="comment">// 18: 52.8</span></span><br><span class="line"><span class="comment">// 19: 54.8</span></span><br><span class="line"><span class="comment">// 20: 84.7</span></span><br><span class="line"><span class="comment">// 21: 94</span></span><br></pre></td></tr></table></figure><p>附加分:写一个分组函数<code>groupBy</code>。<code>groupBy</code>函数应该接受两个参数,一个是数组,还有一个是函数,这个函数为每一个元素计算其分组,并返回带有名称的分好组的数据。</p><h4 id="every和some"><a href="#every和some" class="headerlink" title="every和some"></a>every和some</h4><p>每个数组都有标准方法<code>every</code>和<code>some</code>。两个都是断言函数,当我们给这两个函数传入数组作为参数,他们的返回是true或者false。就像 && 只有在两边的表达式都为真的时候才返回true,<code>every</code>只有在数组中所有元素都为真的时候才返回true。类似地,<code>some</code>在数组中任意元素为真时返回true。他们在不必要时不会做更多的计算,比如,如果<code>some</code>找到的第一个元素为真,就不会继续向后查找。<br>写两个函数,<code>every</code>和<code>some</code>,功能类似上述,但是这里数组作为一个参数。而不是数组中的一个方法。 </p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Your code here.</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(every([<span class="literal">NaN</span>, <span class="literal">NaN</span>, <span class="literal">NaN</span>], <span class="built_in">isNaN</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(every([<span class="literal">NaN</span>, <span class="literal">NaN</span>, <span class="number">4</span>], <span class="built_in">isNaN</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br><span class="line"><span class="built_in">console</span>.log(some([<span class="literal">NaN</span>, <span class="number">3</span>, <span class="number">4</span>], <span class="built_in">isNaN</span>));</span><br><span class="line"><span class="comment">// → true</span></span><br><span class="line"><span class="built_in">console</span>.log(some([<span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>], <span class="built_in">isNaN</span>));</span><br><span class="line"><span class="comment">// → false</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> JavaScript </category>
</categories>
</entry>
<entry>
<title>从前端配色问题的解决方案到一通胡扯</title>
<link href="/posts/7862/"/>
<content type="html"><![CDATA[<p>前端是最直接和用户交互的地方,色彩的选择是最直观摆到用户面前的整体感受,而我的APP或者做的网站都强烈的带有个人的审美风格。Technically speaking,我搭配的颜色并不丑,某种程度上还挺好看。但始终就像是一个二流歌手唱的歌曲,太过用力,感情太饱满,没有给观众更多的个人余地。而邓丽君的歌为什么那么多人喜欢?就是她的歌不带有太多的个人印记,不会改变听者原本的感情色彩。那么颜色的配比问题就该像是一流的歌手,不参杂任何设计者个人的印记。一流的设计,更多的是“退出”,不留痕迹的设计,像白水像空气,存在感很低重要度很高。<a id="more"></a><br>但作为一个非艺术类出身的coder,缺乏的就是长期美学的浸淫,缺少一种对美的直觉,对色彩的直觉。<br>如果不考虑时间成本,从文艺复兴开始,经过印象派,到蒙德里安的线条,可能安迪沃霍尔对现代媒体的传播有更广泛的影响。如果放我在普拉多博物馆待三天,每天面对无数鲁本斯的画作,接下来的一段时间我写的前端可能都会色彩丰富饱满,一派明艳浑圆。那直到有一天,我长期浸泡在各种博物馆,熟悉各种绘画艺术大师的杰作,摒弃过无数不堪入目的所谓“设计”,才能得到浑然天成,信手拈来的豪爽。但现实是我更愿意把这么多的时间用去coding。<br>所以作为N流前端coder,在没有颜色搭配灵感的时候,方法一就是<em>查找风格和手上项目风格符合的画作</em>,先确定色彩基调,选取几个主要的色调,设计其所占的百分比,然后带入具体的project里测试,微调。<br>当然还有更简单的方法,就是参考别人设计的颜色方案。<em>直接Google colour scheme</em>,在image里就有很多值得参考的方案。还有一些可以提供支持的网站,比如最近发现<em><a href="https://coolors.co/" target="_blank" rel="noopener">coolors网站</a>非常实用</em>,提供了很多种色彩搭配的方案,也可以根据用户选择的一个或多个颜色提供完整的色彩搭配方案。<br>最不济,直接参考现有的网站,或者App的色彩搭配。<br>通常在实际操作过程里,想要找到一个满意的色彩搭配方案,并不如想象中的那么容易和顺利,可能会为一个简单的网页或者APP花上一整个下午的时间,去一次次的调试确定好的方案,否定,再搭配,再测试。从色彩的直观感受,到色彩可被重复显示在不同终端(纸媒,显示器,投影等),中间靠着色彩学做支撑。这时候无聊的理论就变成并不是天才的,作为普通人类的我们的,追随天才的机票。</p><hr><p>Here comes the boring part, we can’t just skip it.</p><h3 id="色彩空间"><a href="#色彩空间" class="headerlink" title="色彩空间"></a>色彩空间</h3><h4 id="颜色叠加"><a href="#颜色叠加" class="headerlink" title="颜色叠加"></a>颜色叠加</h4><p><img src="/images/ColorMixing.png" alt="色光加色混合法"><br>一般来说以光源投射时所使用的色彩是属于“叠加型”的原色系统,此系统中包含了红、绿、蓝三种原色,亦称为“三原色”。使用这三种原色可以产生其他颜色,例如红色与绿色混合可以产生黄色或橙色,绿色与蓝色混合可以产生青色(Cyan),蓝色与红色混合可以产生紫色或品红色(Magenta)。当这三种原色以等比例叠加在一起时,会变成灰色;若将此三原色的强度均调至最大并且等量重叠时,则会呈现白色。<br>这套原色系统常被称为“RGB色彩空间”,亦即由红(R)绿(G)蓝(B)所组合出的色彩系统。<br>在显示器内,每一个像素点,都是由RGB三原色组成,RGB三种颜色的发光强度不同,合成了不同的颜色。当三个值都为0时,显示黑色;RGB都为255时,显示白色。</p><h4 id="颜色消减"><a href="#颜色消减" class="headerlink" title="颜色消减"></a>颜色消减</h4><p><img src="/images/SubtractiveColorMixing.png" alt="颜料减色混合法"><br>消减型原色又称为减色原色。一般来说以反射光源或颜料着色时所使用的色彩是属于“消减型”的原色系统,此系统中包含了黄色、青色(Cyan)、品红(Magenta)三种原色,是另一套“三原色”系统。在传统的颜料着色技术上,通常红、黄、蓝会被视为原色颜料,这种系统较受艺术家的欢迎。(现代的美术书已不采用这种说法,而采用消减型的三原色。)当这三种原色混合时可以产生其他颜色,例如黄色与青色混合可以产生绿色,黄色与品红色混合可以产生红色,品红色与青色混合可以产生蓝色。当这三种原色以等比例叠加在一起时,会变成灰色;若将此三原色的饱和度均调至最大并且等量混合时,理论上会呈现黑色,但实际上由于颜料的原因呈现的是浊褐色。</p><h4 id="HSI"><a href="#HSI" class="headerlink" title="HSI"></a>HSI</h4><p><img src="/images/Hsl-hsv_models.png" alt="HSL和HSV"><br>HSI色彩空间是从人的视觉系统出发,用色调(Hue)、色饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩。HSI色彩空间可以用一个圆锥空间模型来描述。用这种描述HSI色彩空间的圆锥模型相当复杂,但确能把色调、亮度和色饱和度的变化情形表现得很清楚。通常把色调和饱和度通称为色度,用来表示颜色的类别与深浅程度。由于人的视觉对亮度的敏感 程度远强于对颜色浓淡的敏感程度,为了便于色彩处理和识别,人的视觉系统经常采用HSI色彩空间,它比RGB色彩空间更符合人的视觉特性。在图像处理和计算机视觉中大量算法都可在HSI色彩空间中方便地使用,它们可以分开处理而且是相互独立的。因此,在HSI色彩空间可以大大简化图像分析和处理的工作量。HSI色彩空间和RGB色彩空间只是同一物理量的不同表示法,因而它们之间存在着转换关系。</p><h3 id="Contrast"><a href="#Contrast" class="headerlink" title="Contrast"></a>Contrast</h3><p><img src="/images/colourContrast1.png" alt=""></p><p><img src="/images/colourContrast2.png" alt=""></p><p>对比度的不同会对亮度的感受带来很大不同,因为人眼对色彩的突然的变化有很强的敏感度。白色背景下的圆形色块,更偏向棕色;黑色背景中偏向于橘色。</p><h3 id="视觉错觉"><a href="#视觉错觉" class="headerlink" title="视觉错觉"></a>视觉错觉</h3><p><img src="/images/colourIllusion.jpg" alt="A和B的颜色相同"><br>由于照明通常不均匀,人眼会抑制亮度的逐渐变化带来的影响。如果你用手遮挡住A和B周围的色块,就会看到它们的颜色相同。</p><h3 id="色盲眼中的世界"><a href="#色盲眼中的世界" class="headerlink" title="色盲眼中的世界"></a>色盲眼中的世界</h3><hr><p>(先写到这里吧,好饿。19:22, Jan 24th, 2017)</p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://www.itp.uni-hannover.de/~zawischa/ITP/introcol.html" target="_blank" rel="noopener">Introduction to colour science</a><br>[2] <a href="http://www.had2know.com/technology/hsi-rgb-color-converter-equations.html" target="_blank" rel="noopener">RGB to HSI, HSI to RGB Conversion Calculator</a><br>[3] <a href="https://zh.wikipedia.org/wiki/%E5%8E%9F%E8%89%B2" target="_blank" rel="noopener">原色</a><br>[4] <a href="https://en.wikipedia.org/wiki/HSL_and_HSV" target="_blank" rel="noopener">HSL和HSV色彩空间</a></p><hr><p>如果我还有什么不切实际的梦想,就是有朝一日,去读一个艺术史的学位。</p>]]></content>
<categories>
<category> Theory </category>
</categories>
</entry>
<entry>
<title>Hexo3.0以上版本git配置错误处理Mac</title>
<link href="/posts/32762/"/>
<content type="html"><![CDATA[<h3 id="工作环境"><a href="#工作环境" class="headerlink" title="工作环境"></a>工作环境</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">XXXXX-MacBook-Pro:hexo chenyu$ git --version</span><br><span class="line">git version 2.10.1 (Apple Git-78)</span><br><span class="line"></span><br><span class="line">XXXXX-MacBook-Pro:hexo chenyu$ hexo -v</span><br><span class="line">hexo: 3.2.2</span><br><span class="line">hexo-cli: 1.0.2</span><br><span class="line">os: Darwin 16.1.0 darwin x64</span><br><span class="line">http_parser: 2.7.0</span><br><span class="line">node: 7.4.0</span><br><span class="line">v8: 5.4.500.45</span><br><span class="line">uv: 1.10.1</span><br><span class="line">zlib: 1.2.8</span><br><span class="line">ares: 1.10.1-DEV</span><br><span class="line">modules: 51</span><br><span class="line">openssl: 1.0.2j</span><br><span class="line">icu: 58.2</span><br><span class="line">unicode: 9.0</span><br><span class="line">cldr: 30.0.3</span><br><span class="line">tz: 2016j</span><br></pre></td></tr></table></figure><hr><h3 id="Error"><a href="#Error" class="headerlink" title="Error"></a>Error</h3><p>使用hexo 3.0以上的版本配置网页到GitHub中时会报错: </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ERROR Deployer not found: git</span><br></pre></td></tr></table></figure><hr><h3 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h3><p>使用terminal安装hexo的包</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-deployer-git --save</span><br></pre></td></tr></table></figure><p>然后重新<code>deploy</code>即可</p><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://www.v2ex.com/t/175940" target="_blank" rel="noopener">搭建 hexo,在执行 hexo deploy 后,出现 error deployer not found:github 的错误</a></p>]]></content>
<categories>
<category> Hexo </category>
</categories>
<tags>
<tag> error shooting </tag>
</tags>
</entry>
<entry>
<title>Andriod Bottom Navigator (安卓底部导航栏)</title>
<link href="/posts/31550/"/>
<content type="html"><![CDATA[<h3 id="Material-design"><a href="#Material-design" class="headerlink" title="Material design"></a>Material design</h3><p>闲扯几句,这几年流行个扁平化风格,不管是ppt设计还是前端,大家都在玩这个,做UI当然也要凑个热闹,但是为什么要追求这个风潮还是要考究的。Google还提出了一个<a href="https://material.io/guidelines/#" target="_blank" rel="noopener">质感设计</a>的概念,没事er时候看两眼。anyway,简单优雅的UI提高的不止是视线所能及的好看,更多的是交互的便利性,按键的有效性,架构的优雅程序。<a id="more"></a><br>如果切换简单的情况下(3-5个),从<code>navigation bar</code>的角度来说,底端停驻的<code>navigation bar</code>,远比侧面划出的<code>navigation bar</code>更高效。</p><p><img src="/images/navigationbar.jpg" alt="navigation bar"></p><p>在安卓开发里面,想要实现底部的navigation bar这一功能,需要借助<code>fragment</code>来实现。</p><h3 id="Fragment"><a href="#Fragment" class="headerlink" title="Fragment"></a><code>Fragment</code></h3><p><code>Fragment</code>有点类似于小型的<code>activity</code>,但是<code>Fragment</code>只能存在于<code>activity</code>内部,受<code>activity</code>生命周期的影响,但它也有自己的生命周期。Google引入<code>Fragment</code>主要是为了适应更灵活的UI设计,主要服务于平板电脑此类大尺寸的显示设备。 </p><p><img src="/images/fragment_lifecycle.png" alt="Fragment lifecircle"></p><hr><h3 id="实例演示"><a href="#实例演示" class="headerlink" title="实例演示"></a>实例演示</h3><p><code>bottomNavigationBar</code>+<code>Fragment</code>对页面控制,只要通过5个步骤实现</p><ol><li><code>gradle</code>添加依赖</li><li>添加menu选项栏</li><li>在主要的layout XML文件中,为fragment在添加container</li><li>在main.java文件中添加控制fragment的listener</li><li>添加fragment本身java文件和XML布局文件 </li></ol><p>最后实现的布局如下: </p><p><img src="/images/navigationbar2.png" alt="navigation bar example"></p><h4 id="gradle添加依赖"><a href="#gradle添加依赖" class="headerlink" title="gradle添加依赖"></a><code>gradle</code>添加依赖</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">compile <span class="string">'com.android.support:recyclerview-v7:25.1.0'</span></span><br><span class="line"></span><br><span class="line">compile <span class="string">'com.android.support:support-v4:25.1.0'</span></span><br><span class="line"></span><br><span class="line">compile <span class="string">'com.android.support:design:25.1.0'</span></span><br></pre></td></tr></table></figure><h4 id="添加menu"><a href="#添加menu" class="headerlink" title="添加menu"></a>添加<code>menu</code></h4><p>先右键app添加menu资源文件 </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><?xml version="1.0" encoding="utf-8"?></span><br><span class="line"></span><br><span class="line"><menu xmlns:android="http://schemas.android.com/apk/res/android"></span><br><span class="line"> <item</span><br><span class="line"> android:id="@+id/action_gallery"</span><br><span class="line"> android:enabled="true"</span><br><span class="line"> android:icon="@drawable/ic_gallery_white_24dp"</span><br><span class="line"> android:title="@string/text_gallery" /></span><br><span class="line"> <item</span><br><span class="line"> android:id="@+id/action_map"</span><br><span class="line"> android:enabled="true"</span><br><span class="line"> android:icon="@drawable/ic_map_on_white_24dp"</span><br><span class="line"> android:title="@string/text_map"/></span><br><span class="line"> <item</span><br><span class="line"> android:id="@+id/action_about"</span><br><span class="line"> android:enabled="true"</span><br><span class="line"> android:icon="@drawable/ic_about_white_24dp"</span><br><span class="line"> android:title="@string/text_about"/></span><br><span class="line"></menu></span><br></pre></td></tr></table></figure><h4 id="main-XML文件"><a href="#main-XML文件" class="headerlink" title="main.XML文件"></a>main.XML文件</h4><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><?xml version=<span class="string">"1.0"</span> encoding=<span class="string">"utf-8"</span>?></span><br><span class="line"><LinearLayout</span><br><span class="line"> xmlns:android=<span class="string">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line"> xmlns:tools=<span class="string">"http://schemas.android.com/tools"</span></span><br><span class="line"> xmlns:app=<span class="string">"http://schemas.android.com/apk/res-auto"</span></span><br><span class="line"> android:layout_width=<span class="string">"match_parent"</span></span><br><span class="line"> android:layout_height=<span class="string">"match_parent"</span></span><br><span class="line"> android:orientation=<span class="string">"vertical"</span></span><br><span class="line"> tools:context=<span class="string">"com.example.myapplication.MainActivity"</span>></span><br><span class="line"> <!-- This is container --></span><br><span class="line"> <FrameLayout</span><br><span class="line"> android:layout_width=<span class="string">"match_parent"</span></span><br><span class="line"> android:id=<span class="string">"@+id/frameLayout"</span></span><br><span class="line"> android:layout_height=<span class="string">"0dp"</span></span><br><span class="line"> android:layout_weight=<span class="string">"1"</span>/></span><br><span class="line"> <!-- This is the Bottom Bavigation Bar --></span><br><span class="line"> <android.support.design.widget.BottomNavigationView</span><br><span class="line"> android:id=<span class="string">"@+id/navigation"</span></span><br><span class="line"> android:layout_width=<span class="string">"match_parent"</span></span><br><span class="line"> android:layout_height=<span class="string">"wrap_content"</span></span><br><span class="line"> android:layout_gravity=<span class="string">"start"</span></span><br><span class="line"> app:menu=<span class="string">"@menu/menu"</span></span><br><span class="line"> app:itemBackground=<span class="string">"@color/colorPrimaryLight"</span></span><br><span class="line"> app:itemIconTint=<span class="string">"@color/colorIcon"</span></span><br><span class="line"> app:itemTextColor=<span class="string">"@color/colorText"</span>/></span><br><span class="line"></LinearLayout></span><br></pre></td></tr></table></figure><h4 id="mainjava文件"><a href="#mainjava文件" class="headerlink" title="mainjava文件"></a>mainjava文件</h4><p>在包名(第一行)下添加如下代码,需要按照提示添加库 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"></span><br><span class="line"> FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();</span><br><span class="line"></span><br><span class="line"> fragmentTransaction.replace(R.id.frameLayout,MapFragment.newInstance());</span><br><span class="line"></span><br><span class="line"> fragmentTransaction.commit();</span><br><span class="line"></span><br><span class="line"> BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);</span><br><span class="line"> bottomNavigationView.setOnNavigationItemSelectedListener(<span class="keyword">new</span> BottomNavigationView.OnNavigationItemSelectedListener() {</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onNavigationItemSelected</span><span class="params">(@NonNull MenuItem item)</span> </span>{</span><br><span class="line"> Fragment fragment = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">switch</span> (item.getItemId()) {</span><br><span class="line"> <span class="keyword">case</span> R.id.action_map:</span><br><span class="line"> fragment = MapFragment.newInstance();</span><br><span class="line"> System.out.println(<span class="string">"here is main activity, map item selected"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> R.id.action_gallery:</span><br><span class="line"> fragment = GalleryFragment.newInstance();</span><br><span class="line"> System.out.println(<span class="string">"here is main activity, gallery item selected"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> R.id.action_about:</span><br><span class="line"> fragment = AboutFragment.newInstance();</span><br><span class="line"> System.out.println(<span class="string">"here is main activity, about item selected"</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (fragment != <span class="keyword">null</span>) {</span><br><span class="line"> FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();</span><br><span class="line"> fragmentTransaction.replace(R.id.frameLayout, fragment);</span><br><span class="line"> fragmentTransaction.commit();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>FragmentTransaction</code>是一个抽象类,提供了一些方法去控制<code>fragment</code>的变化。默认进入的是<code>mainXML</code>文件,这里用到<code>replace</code>方法把默认的布局改为启动MapFragment,后面也是同样的方法修改containner中的布局。switch语句监听用户点击<code>menu</code>的变化,当用户点击对应的menu选项,切换到对应的fragment当中。</p><h4 id="fragment-java文件"><a href="#fragment-java文件" class="headerlink" title="fragment java文件"></a>fragment java文件</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MapFragment</span> <span class="keyword">extends</span> <span class="title">Fragment</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> OnFragmentInteractionListener listener;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> MapFragment <span class="title">newInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> MapFragment();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> View <span class="title">onCreateView</span><span class="params">(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="comment">//System.out.println("here is map fragment OnCreate() method");</span></span><br><span class="line"> <span class="comment">//return inflater.inflate(R.layout.test, container, false);</span></span><br><span class="line"> <span class="comment">//using webtext in fragment</span></span><br><span class="line"></span><br><span class="line"> View v=inflater.inflate(R.layout.fragment_map, container, <span class="keyword">false</span>);</span><br><span class="line"> WebView mWebView = (WebView) v.findViewById(R.id.webview);</span><br><span class="line"> mWebView.loadUrl(<span class="string">"file:///android_asset/map.html"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Enable Javascript</span></span><br><span class="line"> WebSettings webSettings = mWebView.getSettings();</span><br><span class="line"> webSettings.setJavaScriptEnabled(<span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Force links and redirects to open in the WebView instead of in a browser</span></span><br><span class="line"> mWebView.setWebViewClient(<span class="keyword">new</span> WebViewClient());</span><br><span class="line"> <span class="keyword">return</span> v;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">// @Override</span></span><br><span class="line"><span class="comment">// public void onAttach(Context context) {</span></span><br><span class="line"><span class="comment">// super.onAttach(context);</span></span><br><span class="line"><span class="comment">// if (context instanceof OnFragmentInteractionListener) {</span></span><br><span class="line"><span class="comment">// listener = (OnFragmentInteractionListener) context;</span></span><br><span class="line"><span class="comment">// } else {</span></span><br><span class="line"><span class="comment">// throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener");</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// nothing needed to be done with onAttach method right now</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onAttach</span><span class="params">(Context context)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onAttach(context);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onDetach</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onDetach();</span><br><span class="line"> listener = <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">OnFragmentInteractionListener</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onMapFragmentInteraction</span><span class="params">(String string)</span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>代码中注释掉的是android studio中自动生成的<code>onAttach</code>方法,这里需要自己手动定义listener,否则会抛出错误如下: </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">MainActivity@<span class="number">2298f</span>3ca must implement OnFragmentInteractionListener</span><br><span class="line"> at com.peterchappy.lab5.ContentFragmet.onAttach(ContentFragmet.java:<span class="number">83</span>)</span><br></pre></td></tr></table></figure><p>这个listener设置主要是留作fragment之间的通信,本例中fragment没有通信的需要,不需要给<code>onAttach</code>方法设置listener。在stackoverflow中给出的方法是直接用另一段代码替换掉原来的<code>onAttach</code>方法。<br>还有一个要提的点,是在<code>fragment</code>中使用<code>WebView</code>。代码在OnCreate方法里实现,注释的比较清楚了。</p><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://medium.com/@hitherejoe/exploring-the-android-design-support-library-bottom-navigation-drawer-548de699e8e0#.o4mwvk73q" target="_blank" rel="noopener">Exploring the Android Design Support Library: Bottom Navigation View</a><br>[2] <a href="http://stackoverflow.com/questions/28822229/error-must-implement-onfragmentinteractionlistener" target="_blank" rel="noopener">ERROR: must implement OnFragmentInteractionListener</a><br>[3] <a href="http://copyandpaste.website/bottom-bar-navigation-android/" target="_blank" rel="noopener">Bottom bar navigation with 3 fragments</a><br>[4] <a href="http://stackoverflow.com/questions/29292942/how-do-i-implement-onfragmentinteractionlistener" target="_blank" rel="noopener">How do I implement OnFragmentInteractionListener?</a><br>[5] <a href="http://stackoverflow.com/questions/31159149/using-webview-in-fragment" target="_blank" rel="noopener">Using WebView in Fragment [duplicate]</a></p>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> design </tag>
</tags>
</entry>
<entry>
<title>实例讲解在安卓app中加入可交互地图</title>
<link href="/posts/36995/"/>
<content type="html"><![CDATA[<p>想要做一款基于位置的安卓应用,可交互的地图是重要的一部分。<a href="https://developers.google.com/android/reference/com/google/android/gms/maps/package-summary" target="_blank" rel="noopener"><code>Google</code></a>和<a href="http://leafletjs.com/index.html" target="_blank" rel="noopener"><code>Leaflet</code></a>都提供接口给开发者,<code>Leaflet</code>是一个开源的Javascript库,用于gis相关的应用,比google具有更高的定制性,本例就是基于<code>Leaflet</code>讲解安卓应用开发的地图方面的基本配置。<br><img src="/images/leafletdemo.png" alt="Leaflet 地图示例"><br>地图底图用<code>Mapbox</code>提供的数据来显示,其中包含大量数据,来源于OpenStreetMap,NASA等等。在<a href="https://www.mapbox.com/mapbox-studio/" target="_blank" rel="noopener"><code>Mapbox Studio</code></a>中可以定制自己的底图。<br><code>Leaflet</code>需要用到<code>JavaScript</code>,可以先跑通js再放进java代码中编译,推荐一个轻量级的在线editor <a href="https://plnkr.co/edit/" target="_blank" rel="noopener">Plunker</a></p><hr><p>由于<code>Mapbox Studio</code>提供的是在线的地图,所以在这里需要在Layout中创建一个Webview来显示地图。 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><?xml version=<span class="string">"1.0"</span> encoding=<span class="string">"utf-8"</span>?></span><br><span class="line"><WebView</span><br><span class="line">xmlns:android=<span class="string">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">android:id=<span class="string">"@+id/webview"</span></span><br><span class="line">android:layout_width=<span class="string">"match_parent"</span></span><br><span class="line">android:layout_height=<span class="string">"match_parent"</span> /></span><br></pre></td></tr></table></figure><p>然后配置<code>manifest</code>文件,以获取网络请求许可。在<code><manifest></code>标签内添加如下元素: </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><uses-permission android:name=<span class="string">"android.permission.INTERNET"</span> /></span><br></pre></td></tr></table></figure><p>在<code>java</code>文件中,<code>OnCreate()</code>方法中添加加载地图的参数 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">WebView webView = (WebView) findViewById(R.id.webview);</span><br><span class="line">webView.getSettings().setJavaScriptEnabled(<span class="keyword">true</span>);</span><br><span class="line">webView.loadUrl(<span class="string">"file:///android_asset/map.html"</span>);</span><br></pre></td></tr></table></figure><hr><p>到此地图的地基已经搭建完成,接下来就要写<code>html</code>和<code>js</code>代码完成地图的定制化显示。在app这个文件夹内新建文件夹<code>assets</code>,再在其中新建文件并命名为<code>map.html</code>,把自定义的图标<code>star.png</code>复制在<code>assets</code>文件夹目录下。 </p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">title</span>></span>Custom Map<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span></span></span><br><span class="line"><span class="tag"><span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0, user-scalable=no"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span></span></span><br><span class="line"><span class="tag"><span class="attr">href</span>=<span class="string">"https://unpkg.com/[email protected]/dist/leaflet.css"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/[email protected]/dist/leaflet.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined">html, body {</span></span><br><span class="line"><span class="undefined">padding: 0;</span></span><br><span class="line"><span class="undefined">margin: 0;</span></span><br><span class="line"><span class="undefined">height: 100%;</span></span><br><span class="line"><span class="undefined">width: 100%;</span></span><br><span class="line"><span class="undefined">}</span></span><br><span class="line"><span class="css"><span class="selector-id">#map</span> {</span></span><br><span class="line"><span class="undefined">width: 100%;</span></span><br><span class="line"><span class="undefined">height: 100%;</span></span><br><span class="line"><span class="undefined">}</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">'map'</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">var</span> map = L.map(<span class="string">'map'</span>, {</span></span><br><span class="line"><span class="undefined"> center: [48.12855, 13.123903],</span></span><br><span class="line"><span class="undefined"> zoom: 15</span></span><br><span class="line"><span class="undefined"> });</span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> myIcon = L.icon({</span></span><br><span class="line"><span class="javascript"> iconUrl:<span class="string">'star.png'</span>,</span></span><br><span class="line"><span class="undefined"> iconAnchor: [12, 12],</span></span><br><span class="line"><span class="undefined"> popupAnchor: [0, -12]</span></span><br><span class="line"><span class="undefined"> });</span></span><br><span class="line"><span class="undefined"> L.marker([48.12855, 13.123903], {</span></span><br><span class="line"><span class="undefined"> icon: myIcon</span></span><br><span class="line"><span class="undefined"> })</span></span><br><span class="line"><span class="undefined"> .addTo(map)</span></span><br><span class="line"><span class="xml"> .bindPopup("<span class="tag"><<span class="name">b</span>></span>This is<span class="tag"></<span class="name">b</span>></span><span class="tag"><<span class="name">br</span>></span>a demo")</span></span><br><span class="line"><span class="javascript"> .on(<span class="string">'click'</span>, clickCenter);</span></span><br><span class="line"><span class="javascript"> <span class="function"><span class="keyword">function</span> <span class="title">clickCenter</span>(<span class="params">e</span>) </span>{</span></span><br><span class="line"><span class="undefined"> map.setView(e.target.getLatLng(),map.getZoom());</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> circleOptions = {</span></span><br><span class="line"><span class="javascript">color: <span class="string">'#f07910'</span>,</span></span><br><span class="line"><span class="javascript">fillcolor: <span class="string">'#ff00dc'</span>,</span></span><br><span class="line"><span class="undefined">weight: 3,</span></span><br><span class="line"><span class="undefined">opacity: 1</span></span><br><span class="line"><span class="undefined"> };</span></span><br><span class="line"><span class="undefined"> L.circle([48.12855, 13.123903], 50, circleOptions).addTo(map);</span></span><br><span class="line"><span class="undefined">L.tileLayer(</span></span><br><span class="line"><span class="javascript"><span class="string">'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpandmbXliNDBjZWd2M2x6bDk3c2ZtOTkifQ._QA7i5Mpkd_m30IGElHziw'</span>,</span></span><br><span class="line"><span class="undefined">{</span></span><br><span class="line"><span class="javascript">id: <span class="string">'mapbox.streets'</span></span></span><br><span class="line"><span class="undefined">}).addTo(map);</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><p>解释一下上面这段代码,首先在html文件<code>head</code>之中要包含leaflet的css和js文件。在<code>body</code>部分我们添加了一个<code>div</code>定义了将要显示的地图为<code>map</code>。为了使地图全屏显示,在head部分用css代码控制元素的宽和高为100%。<br>在<code>script</code>标签内,第一个变量<code>map</code>指定了显示的中心和缩放等级。<code>myIcon</code>指定自定义的图标,<code>iconAnchor</code>指定图标显示的地理位置,默认的热点是左上角。本例中图标是24*24,所以需要向右向下各移动12个像素,这样图标才能被放置在指定位置的中间。<code>popupAnchor</code>指定popups的位置,在本例中[0,-12]<br>表示的是图标上边缘的中点。接下来marker把图标和popup一起添加给地图。<code>clickCenter</code>函数的功能是,当用户点击marker,就移动地图的显示范围,使其位于屏幕中心。然后指定一个圆圈绘制的属性,最后在地图上显示一个圆圈,并使用<code>circleOptions</code>指定的属性。<br>最后<code>tileLayer</code>提供地图底图,当然可以自己在Mapbox Studio中定制。<br>最后附上编译后的app示例:<br><img src="/images/leafletdemo2.png" alt="Leaflet 地图app示例"></p>]]></content>
<categories>
<category> Android </category>
</categories>
</entry>
<entry>
<title>Google Play 服务已停止运行解决方案</title>
<link href="/posts/30333/"/>
<content type="html"><![CDATA[<h3 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h3><p>调用Google Map的API,做一个安卓的map应用。在android 4.2上顺利运行,升级android 4.3版本出现错误,程序闪退。<br>原因是googleandroid 4.3 有bug</p><blockquote><p>Sorry, thats a bug! It’s just spurious logging though: Google Play services does some checking to see whether you are a Google app or a regular third party one.</p></blockquote><blockquote><p>As part of that, it calls the signature verifier and the logging ended up more verbose than intended - it will be fixed in a future version.This shouldn’t affect the behavior of your app at all.</p></blockquote><blockquote><p>This logcat warning is caused by a bug introduced in Google Play Services 9.x. It can be safely ignored, I don’t believe it causes a crash, so your crash may be caused by a different issue. The message should go away with a future update to play services.</p></blockquote><p>(Update)更新了版本到android 4.4,还是出现闪退,需要下载对应版本的<code>Google Play Service</code><br>(Update)下载了对应版本的<code>Google Play Service</code>,app还是闪退,原因是9X版本的<code>Google Play Service</code>有问题,我换了10X的还有问题,<a href="http://stackoverflow.com/questions/36208647/android-app-is-crashing-due-to-v-googlesignatureverifier-signature-not-valid?answertab=active#tab-top" target="_blank" rel="noopener">stackoverflow</a>上有人说退回到8X版本的<code>Google Play Service</code>,但是问题依旧存在。</p><hr><h3 id="Google-play-Service-版本"><a href="#Google-play-Service-版本" class="headerlink" title="Google play Service 版本"></a>Google play Service 版本</h3><p><code>Google Play 服务已停止运行</code>,出现这一错误更新<code>Google Play Service</code>可以解决,但是<code>Google Play Service</code>一定要找到对应的版本。版本号可以在[应用]当中查询,最后三位[XYZ]比较重要: </p><p><u>X 取决于 Google Play服务所运行的 Android 版本</u></p><ul><li>0 版本号低于 5.0</li><li>2 版本号5.0或者5.1,且Play Service是v8及以后</li><li>2 版本号5.0或者5.1,且Play Service是v8以前,或者版本号6.0及以上</li><li>5 Android Wear</li><li>7 Android 5.0</li><li>8 Android TV</li></ul><p><u>Y 取决于 所运行设备的 CPU 架构方式</u></p><ul><li>1 对应armeabi</li><li>3 对应armeabi-v7a</li><li>4 对应arm64-v8a</li><li>5 对应mips</li><li>7 对应x86</li><li>8 对应x86_64</li></ul><p><u>Z 取决于所运行设备的 dpi</u></p><ul><li>160 dpi 该位置数字为 2</li><li>240 dpi 该位置数字为 4</li><li>320 dpi 该位置数字为 6</li><li>480 dpi 该位置数字为 8</li><li>该位置数字为 0 一般指各 dpi 通用的 Google Play 服务</li></ul><hr><h3 id="机器信息查询"><a href="#机器信息查询" class="headerlink" title="机器信息查询"></a>机器信息查询</h3><ul><li><p>Android版本查询<br>Android版本可以在[设置] -> [本机信息] 当中查看</p></li><li><p>CPU构架查询<br>很多种方式可以查询CPU架构</p></li></ul><h4 id="软件查询"><a href="#软件查询" class="headerlink" title="软件查询"></a>软件查询</h4><p><code>Droid Hardware Info</code>是个很handy的小工具,<a href="http://www.apkmirror.com/apk/inkwired/droid-hardware-info/droid-hardware-info-1-0-3-release/droid-hardware-info-1-0-3-android-apk-download/" target="_blank" rel="noopener">下载链接</a></p><h4 id="命令行查询"><a href="#命令行查询" class="headerlink" title="命令行查询"></a>命令行查询</h4><p>打开<code>终端模拟器</code>,输入如下命令</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">u0_a50<span class="meta">@m</span>0:/ $ adb shell</span><br><span class="line"></span><br><span class="line">* daemon not running. starting it now on port <span class="number">5038</span> *</span><br><span class="line">* daemon started successfully *</span><br><span class="line">error: device not found</span><br><span class="line"></span><br><span class="line"><span class="number">1</span>|u0_a50<span class="meta">@m</span>0:/ $ cat /proc/cpuinfo</span><br><span class="line">Processor : ARMv7 Processor rev <span class="number">0</span> (v7l)</span><br><span class="line">processor : <span class="number">0</span></span><br><span class="line">BogoMIPS : <span class="number">1592.52</span></span><br><span class="line">processor : <span class="number">1</span></span><br><span class="line">BogoMIPS : <span class="number">2786.91</span></span><br><span class="line">processor : <span class="number">2</span></span><br><span class="line">BogoMIPS : <span class="number">2786.91</span></span><br><span class="line">processor : <span class="number">3</span></span><br><span class="line">BogoMIPS : <span class="number">2786.91</span></span><br><span class="line">Features : swp half thumb fastmult vfp edsp neon vfpv3 tls</span><br><span class="line">CPU implementer : <span class="number">0x41</span></span><br><span class="line">CPU architecture: <span class="number">7</span></span><br><span class="line">CPU variant : <span class="number">0x3</span></span><br><span class="line">CPU part : <span class="number">0xc09</span></span><br><span class="line">CPU revision : <span class="number">0</span></span><br><span class="line">Chip revision : <span class="number">0011</span></span><br><span class="line">Hardware : SMDK4x12</span><br><span class="line">Revision : <span class="number">000</span>c</span><br><span class="line">Serial : <span class="number">5</span>cc1303b4df75c1d</span><br></pre></td></tr></table></figure><p>所以测试机CPU构架为<code>armeabi-v7a</code></p><h4 id="代码查询"><a href="#代码查询" class="headerlink" title="代码查询"></a>代码查询</h4><p>写一个小demo就适合查询更多的信息(号码,内存,CPU,分辨率,MAC,IP,SD卡,IMEI,经纬度,信号强度等等),Google有提供很多接口,具体参见<a href="http://2402766.blog.51cto.com/2392766/1080837" target="_blank" rel="noopener">【小功能2】android获取手机信息</a></p><ul><li>设备dpi查询<br>手机分辨率为:720 * 1280<br>主屏尺寸为: 4.8</li></ul><p>Diagonal pixel = \sqrt{width{^2^} + {height}{^2^}} = 1468.6<br>dpi = 1468.6 / 4.8 = 305</p><p>所以测试机使用的<code>Google Play Service</code>版本是<code>036</code></p><hr><h3 id="下载并安装对应的apk"><a href="#下载并安装对应的apk" class="headerlink" title="下载并安装对应的apk"></a>下载并安装对应的apk</h3><p><a href="http://www.apkmirror.com/" target="_blank" rel="noopener">APKMirror</a>很方便下载安装包,比Google play更新速度快。</p><hr><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p>[1] <a href="http://izaka.tw/android-processor-architecture-determine/" target="_blank" rel="noopener">http://izaka.tw/android-processor-architecture-determine/</a> 如何查詢安卓手機平板所使用的處理器架構<br>[2] <a href="http://blog.csdn.net/watermusicyes/article/details/45059309" target="_blank" rel="noopener">http://blog.csdn.net/watermusicyes/article/details/45059309</a> 如何查看Android设备的CPU架构信息<br>[3] <a href="http://2402766.blog.51cto.com/2392766/1080837" target="_blank" rel="noopener">http://2402766.blog.51cto.com/2392766/1080837</a> 【小功能2】android获取手机信息<br>[4] <a href="http://blog.csdn.net/moruite/article/details/6028547" target="_blank" rel="noopener">http://blog.csdn.net/moruite/article/details/6028547</a> Android手机分辨率基础知识(DPI,DIP计算)<br>[5] <a href="http://sspai.com/30526" target="_blank" rel="noopener">http://sspai.com/30526</a> Google Play 服务已停止运行?这是解决方案</p>]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> error shooting </tag>
</tags>
</entry>
<entry>
<title>深入理解Android Activity生命周期</title>
<link href="/posts/858/"/>
<content type="html"><![CDATA[<p><code>activity</code>是一个提供用户交互的窗口,<code>activity</code>之内可以包含多个<code>view</code>去实现具体的显示和交互。<code>activity</code>一般是以全屏的形式出现,也有特殊情况比如内嵌在另一个<code>activity</code>中。<br>Google给出了<code>activity</code>的生命周期流程图如下<br><img src="/images/activity_lifecycle.png" alt="Activity生命周期"></p><hr><h3 id="生命周期函数"><a href="#生命周期函数" class="headerlink" title="生命周期函数"></a>生命周期函数</h3><p><code>activity</code>生命周期函数是由<code>android</code>操作系统调用,我们如上可以复写某个(或多个)函数,实现更多的功能。比如管理音乐软件的后台播放功能。</p><table><thead><tr><th>函数</th><th>调用时机</th></tr></thead><tbody><tr><td>OnCreate</td><td>在activity对象被第一次创建时候调用</td></tr><tr><td>OnStart</td><td>在activity变得可见时调用</td></tr><tr><td>OnResume</td><td>在activity开始准备与用户交互时调用(不释放内存)</td></tr><tr><td>OnPause</td><td>在系统即将启动另外一个activity之前调用(不释放内存)</td></tr><tr><td>OnStop</td><td>当前activity变得不可见时调用</td></tr><tr><td>OnRestart</td><td>当一个activity再次被启动之前调用</td></tr><tr><td>OnDestroy</td><td>当前activity被销毁之前调用</td></tr></tbody></table><hr><h3 id="多个activity的实现方法"><a href="#多个activity的实现方法" class="headerlink" title="多个activity的实现方法"></a>多个<code>activity</code>的实现方法</h3><h4 id="定义多个activity"><a href="#定义多个activity" class="headerlink" title="定义多个activity"></a>定义多个<code>activity</code></h4><ul><li>首先定义一个类,继承<code>activity</code></li><li>在该类当中,复写<code>activity</code>当中的<code>OnCreate</code>方法</li><li>在<code>AndroidManifest.xml</code>文件中注册该<code>activity</code></li></ul><h4 id="启动一个activity的方法"><a href="#启动一个activity的方法" class="headerlink" title="启动一个activity的方法"></a>启动一个<code>activity</code>的方法</h4><ul><li>生成一个意图对象<code>Intent</code></li><li>调用<code>setClass</code>方法设置所要启动的<code>activity</code>,其中第一个参数是<code>packageContext</code>,就是当前类中应用的包名;第二个参数是意图要设置的类的名称。</li><li>调用<code>startActivity</code>方法启动<code>activity</code></li></ul><p>在这里复写了<code>MainActivity</code>中的七种方法,为了更清晰的了解<code>activity</code>的生命周期,这里还创建第二个<code>activity</code>,以便观察不同时期<code>activity</code>的状态。本例中调用<code>SystemOut</code>输出<code>activity</code>的状态。设置监听器<code>ButtonListener</code>,在点击按钮的时候启动第二个<code>activity</code>。 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Button button;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"> button = (Button) findViewById(R.id.button);</span><br><span class="line"> ButtonListener listener = <span class="keyword">new</span> ButtonListener();</span><br><span class="line"> button.setOnClickListener(listener);</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnCreate"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">ButtonListener</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>{</span><br><span class="line"> Intent intent = <span class="keyword">new</span> Intent();</span><br><span class="line"> intent.setClass(MainActivity.<span class="keyword">this</span>, SecondActivity.class);</span><br><span class="line"> startActivity(intent);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onStart();</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnStart"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onStop();</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnStop"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onDestroy();</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnDestroy"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onResume();</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnResume"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onPause</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onResume();</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnPause"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onRestart</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onResume();</span><br><span class="line"> System.out.println(<span class="string">"MainActivity OnRestart"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>第二个<code>activity</code>,命名为<code>SecondActivity</code>,同样复写其中的七个生命周期函数 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.cheryl.multiactivity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.support.v7.app.AppCompatActivity;</span><br><span class="line"><span class="keyword">import</span> android.os.Bundle;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecondActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_second);</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnCreate"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onStart();</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnStart"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onStop();</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnStop"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onDestroy();</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnDestroy"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onResume();</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnResume"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onPause</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onResume();</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnPause"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onRestart</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onResume();</span><br><span class="line"> System.out.println(<span class="string">"SecondActivity OnRestart"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><code>AndroidManifest.xml</code>文件中注册第二个<code>activity</code>,在<code><application></code>标签结束之前添加如下代码: </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><activity android:name=<span class="string">".SecondActivity"</span> android:label=<span class="string">"SecondActivity"</span>></span><br></pre></td></tr></table></figure><hr><h3 id="Back-Stack"><a href="#Back-Stack" class="headerlink" title="Back Stack"></a>Back Stack</h3><p>安卓应用中通常包含多个<code>activity</code>,每个<code>activity</code>都是围绕不同的内容设计,而且可以打开别的<code>activity</code>,甚至是其他app中的<code>activity</code>,比如分享或者在浏览器中打开等等功能。在一个特定的功能当中,一个任务(task)就等于是多个<code>activity</code>的集合。</p><p>一般情况下,安卓系统中会同时运行多个apps,系统就需要同时管理多个apps,且每个任务中有很多任务。当用户启动一个应用程序的时候,当前app就会在前台显示。另一个app被开启的时候,新的app就会在旧app的顶端显示,同时获得焦点。旧的app被压入back stack栈中。当用户点击返回按钮,位于栈顶的<code>activity</code>被弹出,底部的<code>activity</code>会在前台显示并获得焦点。back stack栈中<code>activity</code>的顺序不能被改变,只能压入栈push,或者弹出栈pop。如果用户持续点击返回,栈内的<code>activity</code>会依次弹出,前台显示之前的<code>activity</code>,直到显示主页,back stack栈为空。</p><p>当用户开启新的任务,或者回到主页,一个任务在后台的状态下仍会保持以一个整体的形式存放。当任务被存放在后台,所有的<code>activity</code>都是stopped状态,但仍会保持完整性,只是暂时失去焦点,焦点被另一个<code>activity</code>所取代。举例用户在使用app A,且app A包括三个<code>activity</code>,在当前<code>activity</code>之下还有两个存放在栈中。然后用户点击home按钮返回主页,然后开启一个新的app B,这时app A进入后台。系统会给app B开启新的任务和back stack,用户在完成app B中的工作后,按home键返回主页,再次进入app A,这时app A中保存的所有<code>activity</code>会在暂停的位置获得焦点继续运行。如果用户返回app B,也会继续运行之前app B中的<code>activity</code>。<br><img src="/images/diagram_multitasking.png" alt="多任务状态"><br>因为<code>activity</code>在back stack栈中的位置不能被改变,可能会导致某个<code>activity</code>反复进出back stack栈(比如home <code>activity</code>)。如果要改变这种行为,需要深入了解<a href="https://developer.android.com/design/patterns/navigation.html" target="_blank" rel="noopener">Navigation Design</a>。</p><hr><h3 id="实例说明"><a href="#实例说明" class="headerlink" title="实例说明"></a>实例说明</h3><p>在第一个<code>activity</code>布局中设置一个按钮,让用户通过点击按钮进入第二个<code>activity</code>。<code>logcat</code>查看函数运行情况。 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><Button</span><br><span class="line">android:id=<span class="string">"@+id/button"</span></span><br><span class="line">android:layout_width=<span class="string">"wrap_content"</span></span><br><span class="line">android:layout_height=<span class="string">"wrap_content"</span></span><br><span class="line">android:text=<span class="string">"Call SecondActivity"</span>/></span><br></pre></td></tr></table></figure><p>第二个<code>activity</code>只显示文字 </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><TextView</span><br><span class="line">android:id=<span class="string">"@+id/secondTextView"</span></span><br><span class="line">android:layout_width=<span class="string">"wrap_content"</span></span><br><span class="line">android:layout_height=<span class="string">"wrap_content"</span></span><br><span class="line">android:text=<span class="string">"SecondActivity"</span>/></span><br></pre></td></tr></table></figure><ul><li>运行App<br><img src="/images/runapp.jpg" alt="运行界面"><br>输出如下,系统相继调用了<code>OnCreate</code>,<code>OnStart</code>和<code>OnResume</code>方法。</li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:39:15.775 I/System.out: MainActivity OnCreate</span><br><span class="line">01-07 12:39:15.775 I/System.out: MainActivity OnStart</span><br><span class="line">01-07 12:39:15.775 I/System.out: MainActivity OnResume</span><br></pre></td></tr></table></figure></code></pre><ul><li>屏幕变暗休眠<br>系统调用<code>OnPause</code>和<code>OnStop</code>方法</li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:39:45.840 I/System.out: MainActivity OnPause</span><br><span class="line">01-07 12:39:45.860 I/System.out: MainActivity OnStop</span><br></pre></td></tr></table></figure></code></pre><ul><li>再次点亮屏幕</li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:44:55.085 I/System.out: MainActivity OnRestart</span><br><span class="line">01-07 12:44:55.085 I/System.out: MainActivity OnStart</span><br><span class="line">01-07 12:44:55.095 I/System.out: MainActivity OnResume</span><br></pre></td></tr></table></figure></code></pre><ul><li>点击按钮进入第二个<code>activity</code>,可以看到系统是先暂停第一个<code>activity</code>,创建和开始第二个<code>activity</code>,第二个<code>activity</code>准备与用户交互,最后再停掉第一个<code>activity</code>。</li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:47:10.355 I/System.out: MainActivity OnPause</span><br><span class="line">01-07 12:47:10.410 I/System.out: SecondActivity OnCreate</span><br><span class="line">01-07 12:47:10.410 I/System.out: SecondActivity OnStart</span><br><span class="line">01-07 12:47:10.410 I/System.out: SecondActivity OnResume</span><br><span class="line">01-07 12:47:10.575 I/System.out: MainActivity OnStop</span><br></pre></td></tr></table></figure></code></pre><ul><li>Home键</li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:49:08.245 I/System.out: SecondActivity OnPause</span><br><span class="line">01-07 12:49:08.560 I/System.out: SecondActivity OnStop</span><br></pre></td></tr></table></figure></code></pre><ul><li>再次进入app</li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:49:35.690 I/System.out: SecondActivity OnRestart</span><br><span class="line">01-07 12:49:35.690 I/System.out: SecondActivity OnStart</span><br><span class="line">01-07 12:49:35.690 I/System.out: SecondActivity OnResume</span><br></pre></td></tr></table></figure></code></pre><ul><li>Back键,app返回到第一个<code>activity</code>的页面。系统是先暂停第二个<code>activity</code>,重新返回第一个<code>activity</code>,然后销毁第二个<code>activity</code></li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:50:36.185 I/System.out: SecondActivity OnPause</span><br><span class="line">01-07 12:50:36.200 I/System.out: MainActivity OnRestart</span><br><span class="line">01-07 12:50:36.200 I/System.out: MainActivity OnStart</span><br><span class="line">01-07 12:50:36.200 I/System.out: MainActivity OnResume</span><br><span class="line">01-07 12:50:36.370 I/System.out: SecondActivity OnStop</span><br><span class="line">01-07 12:50:36.370 I/System.out: SecondActivity OnDestroy</span><br></pre></td></tr></table></figure></code></pre><ul><li>再次Back,回到系统主页,销毁第一个<code>activity</code></li></ul><pre><code><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">01-07 12:53:19.980 I/System.out: MainActivity OnPause</span><br><span class="line">01-07 12:53:20.180 I/System.out: MainActivity OnStop</span><br><span class="line">01-07 12:53:20.180 I/System.out: MainActivity OnDestroy</span><br></pre></td></tr></table></figure></code></pre><hr><h3 id="Intent对象基础"><a href="#Intent对象基础" class="headerlink" title="Intent对象基础"></a>Intent对象基础</h3><p>在第一段代码的Lisener函数里我们看到了<code>intent</code>的使用,intent是即将要进行操作的一个抽象描述,可以用于启动另一个<code>activity</code>,广播一个特定的组件信息,或者和后台服务通信。可以通俗的理解<code>intent</code>,就是<code>action</code>和<code>data</code>的集合体。</p><blockquote><p>An Intent is an object that provides runtime binding between separate components (such as two activities). The Intent represents an app’s “intent to do something.” You can use intents for a wide variety of tasks, but most often they’re used to start another activity.</p></blockquote><p>简单理解就是,想要应用中做事件X,就把这个<code>动作</code>和<code>数据</code>写进<code>intent</code>,在合适的时机使用或接收。主要有三个场景下比较常用:</p><ul><li>在<code>activity</code>之间通过<code>intent</code>对象传递数据</li><li>使用<code>putExtra()</code>系列方法向<code>intent</code>对象中存储数据</li><li>使用<code>getXXXExtra()</code>系列方法从<code>intent</code>对象中取出数据<br>通过以上方法,就可以实现不同<code>activity</code>之间的通信</li></ul><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="https://developer.android.com/guide/components/activities/tasks-and-back-stack.html" target="_blank" rel="noopener">https://developer.android.com/guide/components/activities/tasks-and-back-stack.html</a> Google guide: Tasks and Back Stack<br>[2] <a href="http://blog.csdn.net/android_tutor/article/details/5772285" target="_blank" rel="noopener">http://blog.csdn.net/android_tutor/article/details/5772285</a> 两分钟彻底让你明白Android Activity生命周期(图文)<br>[3] <a href="http://stackoverflow.com/questions/6578051/what-is-an-intent-in-android" target="_blank" rel="noopener">http://stackoverflow.com/questions/6578051/what-is-an-intent-in-android</a> What is an Intent in Android?<br>[4] <a href="https://developer.android.com/reference/android/content/Intent.html" target="_blank" rel="noopener">https://developer.android.com/reference/android/content/Intent.html</a> Intent|Android Developers</p>]]></content>
<categories>
<category> Android </category>
</categories>
</entry>
<entry>
<title>安卓线程初步(一)</title>
<link href="/posts/45498/"/>
<content type="html"><![CDATA[<p>重要的话写在前面,关于线程知识的掌握,一定要看源码!一定要看源码!一定要看源码!一定要看源码!一定要看源码!<br>主要有三个<code>java</code>类之间的关系一定要理解清楚:<code>Looper</code>,<code>Handler</code>和<code>MessagesQueue</code>,这三个类之间一一对应,看了源码才知道Google设计的精妙之处,不然写代码只知其然不知其所以然。本文先讲讲’其然’,’所以然’之后细说。</p><hr><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><p><code>进程(Process)</code>是一块包含了某些资源的内存区域。<br>进程中所包含的一个或多个执行单元为<code>线程(Thread)</code>。<br>标准的解释如上所属,但是概念很难被理解。通俗地说,进程和线程最大的区别在于,进程是一块独立的内存空间,而线程运行在公共的内存空间中。<br>具体来说,每个应用都至少会开辟自己的一个进程,一个进程内可以包含多个线程。重要的是,线程可以做进程做的任何任务,所以线程可以当作“轻量级”的进程。一般来说线程处理一些小任务,“重量级”的任务会交给进程。<br>而且,进程之间是独立的,一个进程内的多个线程是共享内存的。所以线程间就可以共同处理一块数据,线程间的通讯比进程间的通讯容易很多。<br>打个比方,进程就好比一棵大树,线程就是这颗树上的树枝,所有树枝共享根部提供的养分(内存)。进程是个大工厂,线程是工厂内具体进行操作的工人。</p><p>在安卓应用程序中,主线程用于接收用户的输入,以及反馈结果。因为一旦主线程阻塞,程序就会暂停运行。所以一些会产生阻塞的操作,比如从网络上下载数据,就会放在worker thread中进行。主线程之外(worker thread)不允许修改UI属性,但是processing bar除外。</p><hr><h3 id="从Worker-Thread到Main-Thread传送数据"><a href="#从Worker-Thread到Main-Thread传送数据" class="headerlink" title="从Worker Thread到Main Thread传送数据"></a>从Worker Thread到Main Thread传送数据</h3><p>从<code>Worker Thread</code>到<code>Main Thread</code>传送数据一般用于从网络中获取数据,然后显示在界面反馈给用户。主要有三个操作步骤:</p><ul><li>继承<code>Thread</code>类,使用<code>worker thread</code>获取网络中的数据,发送<code>message</code></li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">2</span> * <span class="number">1000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//实用s模拟网络中获取的数据</span></span><br><span class="line"> System.out.println(<span class="string">"MyThreadMessage------>"</span> + Thread.currentThread().getName());</span><br><span class="line"> String s = <span class="string">"Data from internet!"</span>; </span><br><span class="line"></span><br><span class="line"> Message msg = handler.obtainMessage();</span><br><span class="line"> msg.obj = s;</span><br><span class="line"> handler.sendMessage(msg);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><p>在<code>workthread</code>实现过程中,先休眠两秒,模拟网络中获取数据的时间开销。然后创建<code>msg</code>对象,把<code>handler</code>和<code>msg</code>对象相关联,<code>s</code>的值赋给<code>msg</code>,最后用<code>handler</code>发送消息。</p><ul><li>实现监听窗口,调用<code>worker thread</code></li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OnButtonClick</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>{</span><br><span class="line"> <span class="comment">//当用户点击按钮时,穿件一个消息对象,并实用Handler发送该对象</span></span><br><span class="line"> System.out.println(<span class="string">"OnClickListener"</span>);</span><br><span class="line"><span class="comment">// Message msg = handler.obtainMessage();</span></span><br><span class="line"><span class="comment">// msg.what = 2;</span></span><br><span class="line"><span class="comment">// handler.sendMessage(msg);</span></span><br><span class="line"> Thread t = <span class="keyword">new</span> MyThread();</span><br><span class="line"> t.start();</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><p>当用户点击按钮时,监听器监听到这一行为,开启一个<code>worker thread</code></p><ul><li>继承<code>Handler</code>类,实现<code>handlemassges</code>方法获取<code>msg</code></li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">MyHandler</span> <span class="keyword">extends</span> <span class="title">Handler</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleMessage</span><span class="params">(Message msg)</span> </span>{</span><br><span class="line"><span class="comment">// int what = msg.what;</span></span><br><span class="line"><span class="comment">// System.out.println("What: " + what);</span></span><br><span class="line"> System.out.println(<span class="string">"handleMessageThread------>"</span> + Thread.currentThread().getName());</span><br><span class="line"> String s = (String)msg.obj;</span><br><span class="line"> textView.setText(s);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><p><code>handler</code>位于<code>main thread</code>中,故此可以修改UI为<code>msg</code>传过来的消息</p><ul><li>顺便附上<code>OnCerate()</code>方法</li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"> button = (Button) findViewById(R.id.buttonId);</span><br><span class="line"> button.setOnClickListener(<span class="keyword">new</span> OnButtonClick());</span><br><span class="line"> textView = (TextView) findViewById(R.id.textViewId);</span><br><span class="line"> handler = <span class="keyword">new</span> MyHandler();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><ul><li><p>logcat中的输出<br>在手机上运行程序,并点击按钮。界面中的<code>Hello world!</code>在两秒之后,变成<code>Data from internet!</code>。<br>logcat中输出如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">19112</span>-<span class="number">19112</span>/com.cheryl.handler01 I/System.out: OnClickListener</span><br><span class="line"><span class="number">19112</span>-<span class="number">21361</span>/com.cheryl.handler01 I/System.out: MyThreadMessage------>Thread-<span class="number">642</span></span><br><span class="line"><span class="number">19112</span>-<span class="number">19112</span>/com.cheryl.handler01 I/System.out: handleMessage------>main</span><br></pre></td></tr></table></figure></li></ul><p>可见系统先是在监听器中监听到按钮被点击的行为,然后启动worker thread,最后回到main thread中修改界面。</p><hr><h3 id="从Main-Thread到Worker-Thread传送数据"><a href="#从Main-Thread到Worker-Thread传送数据" class="headerlink" title="从Main Thread到Worker Thread传送数据"></a>从Main Thread到Worker Thread传送数据</h3><ul><li>继承<code>Thread</code>类,准备<code>Looper</code>对象</li><li>在<code>Worker Thread</code>中生成<code>handler</code>对象,重写<code>handleMessage()</code>方法</li><li>调用<code>Looper.loop()</code>方法</li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WorkerThread</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> Looper.prepare();</span><br><span class="line"> System.out.println(<span class="string">"Worker Thread"</span>);</span><br><span class="line"> handler = <span class="keyword">new</span> Handler(){</span><br><span class="line"><span class="comment">// @Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleMessage</span><span class="params">(Message msg)</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"Worker thread Message received"</span>);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> Looper.loop();</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><p>以上几步的使用方法在这里单独拿出来,看起来会有点别扭,但正是Google设计的巧妙之处,一个<code>Looper</code>对应一个<code>handler</code>一个<code>msg</code>对象。</p><ul><li>在<code>ButtonLisener</code>中用<code>handler</code>生成<code>msg</code>对象</li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">OnButtonClick</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span></span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>{</span><br><span class="line"><span class="comment">// MyThread t = new MyThread();</span></span><br><span class="line"><span class="comment">// t.start();</span></span><br><span class="line"> System.out.println(<span class="string">"OnClickListener1"</span>);</span><br><span class="line"> Message msg = handler.obtainMessage();</span><br><span class="line"> handler.sendMessage(msg);</span><br><span class="line"> System.out.println(<span class="string">"OnClickListener2"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><ul><li>在<code>OnCreate</code>方法中启动<code>WorkerThread</code></li></ul><pre><code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> setContentView(R.layout.activity_main);</span><br><span class="line"> button = (Button) findViewById(R.id.buttonId);</span><br><span class="line"> textView = (TextView) findViewById(R.id.textViewId);</span><br><span class="line"> WorkerThread wt = <span class="keyword">new</span> WorkerThread();</span><br><span class="line"> wt.start();</span><br><span class="line"> button.setOnClickListener(<span class="keyword">new</span> OnButtonClick());</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></code></pre><hr><h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><p>[1] <a href="http://stackoverflow.com/a/200473/7396256" target="_blank" rel="noopener">What is the difference between a process and a thread?</a><br>[2] <a href="http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html" target="_blank" rel="noopener">进程与线程的一个简单解释</a><br>[3] <a href="http://www.programmerinterview.com/index.php/operating-systems/thread-vs-process/" target="_blank" rel="noopener">What is the difference between a thread and a process?</a></p>]]></content>
<categories>