Korea Ocean Water Quality Information¶

from https://www.nifs.go.kr (National Institute of Fisheries Science)¶

api service https://www.nifs.go.kr/OpenAPI_json¶

In [40]:
%use kandy
%use dataframe
%use lets-plot
In [2]:
var df_stat_raw = DataFrame.readJson("http://192.168.35.107:7788/nifs/stat")
df_stat_raw.describe()
Out[2]:

DataFrame: rowsCount = 7, columnsCount = 10

nametypecountuniquenullstopfreqminmedianmax
gru_namString93630남해528남해남해서해
sta_cdeString936390fgg4c24bgj8aftdk5wn087
sta_nam_korString936390거제 가배24강릉영덕해남 임하
obs_datetimeString93624026-06-07 133926-06-07 1326-06-08 0026-06-08 12
tmp_minString93689018.9490.218.922.9
tmp_maxString93688019.1510.219.023.0
tmp_avgString936150018.60350.2018.9522.95
In [3]:
var df_stat = df_stat_raw.convert { tmp_min and  tmp_max and  tmp_avg }.with { it.toFloat() }
df_stat.describe()
Out[3]:

DataFrame: rowsCount = 7, columnsCount = 12

nametypecountuniquenullstopfreqmeanstdminmedianmax
gru_namString93630남해528nullnull남해남해서해
sta_cdeString936390fgg4c24nullnullbgj8aftdk5wn087
sta_nam_korString936390거제 가배24nullnull강릉영덕해남 임하
obs_datetimeString93624026-06-07 1339nullnull26-06-07 1326-06-08 0026-06-08 12
tmp_minFloat93689018.9000004918.3630343.3660310.20000018.90000022.900000
tmp_maxFloat93688019.1000005118.4694443.3754580.20000019.00000023.000000
tmp_avgFloat936150018.6000003518.4162393.3699880.20000018.95000122.950001
In [30]:
df_stat.filter { gru_nam == "서해" }.plot{

    layout {
        title = "일별 해수 온도 변화"
        size = 1500 to 400
      
    }

    x("obs_datetime"){
        axis.name = "관측일시"
    }

    y {
        axis {
            limits = tmp_min.min().toInt().minus(1)..tmp_max.max().toInt().plus(1)
            name = "Temperature °C"
        }
    }

    line {
        y(tmp_avg)
        color("sta_nam_kor"){
            legend.name = "관측소명"
        }
        type = LineType.DOTTED
        width = 0.6
    }

    ribbon {
        yMin("tmp_min")
        yMax("tmp_max")
        fillColor("sta_nam_kor") {
            legend.name = "관측소명"
        }
        alpha = 0.6
        borderLine.width = 0.0
    }
} 
Out[30]:
26-06-07 13 26-06-07 14 26-06-07 15 26-06-07 16 26-06-07 17 26-06-07 18 26-06-07 19 26-06-07 20 26-06-07 21 26-06-07 22 26-06-07 23 26-06-08 00 26-06-08 01 26-06-08 02 26-06-08 03 26-06-08 04 26-06-08 05 26-06-08 06 26-06-08 07 26-06-08 08 26-06-08 09 26-06-08 10 26-06-08 11 26-06-08 12 12 14 16 18 20 22 일별 해수 온도 변화 Temperature °C 관측일시 관측소명 군산 신시도 목포 백령도 보령 소도 서산 지곡 서산 창리 태안 고남 태안 대야도 태안 파도리 해남 임하
In [75]:
val data_Ribbon = df_stat.filter { gru_nam == "서해" }.toMap()

letsPlot(data_Ribbon) +
    
        geomRibbon(alpha = 0.2){
            x="obs_datetime"
            ymin = "tmp_min"
            ymax = "tmp_max"
            fill = "sta_nam_kor"
        } +
        
        geomLine( ) {x="obs_datetime"; y="tmp_avg"; color="sta_nam_kor"} +
        scaleYContinuous(limits=Pair(10, 25) ) +
        labs(x="관측일시", y="Temperature °C") +
        theme(
            axisTextX= elementText( angle=45),
        ) +
        ggsize(1500, 400)
Out[75]:
In [97]:
val data_Ribbon = df_stat.filter { gru_nam == "동해" }.toMap()

letsPlot(data_Ribbon) +
    
        geomRibbon(alpha = 0.2){
            x="obs_datetime"
            ymin = "tmp_min"
            ymax = "tmp_max"
            fill = "sta_nam_kor"
        } +
        
        geomLine( ) {x="obs_datetime"; y="tmp_avg"; color="sta_nam_kor"} +
        scaleYContinuous(limits=Pair(10, 25) ) +
        labs(x="관측일시", y="Temperature °C") +
        theme(
            axisTextX= elementText( angle=45),
        ) +
        ggsize(1500, 400)
Out[97]:
In [100]:
val data_Ribbon = df_stat.filter { gru_nam == "남해" }.toMap()

letsPlot(data_Ribbon) +
    
        geomRibbon(alpha = 0.2){
            x="obs_datetime"
            ymin = "tmp_min"
            ymax = "tmp_max"
            fill = "sta_nam_kor"
        } +
        
        geomLine( ) {x="obs_datetime"; y="tmp_avg"; color="sta_nam_kor"} +
        scaleYContinuous(limits=Pair(14, 25) ) +
        labs(x="관측일시", y="Temperature °C") +
        theme(
            axisTextX= elementText( angle=45),
        ) +
        ggsize(1500, 600)
Out[100]:
In [32]:
val df_day = df_day_raw.convert { wtr_tmp }.with { it.toFloat() }
df_day.describe()
Out[32]:

DataFrame: rowsCount = 8, columnsCount = 12

nametypecountuniquenullstopfreqmeanstdminmedianmax
sta_cdeString2970390fth59144nullnullbgj8afsch6wn087
sta_nam_korString2970390통영 학림144nullnull강릉여수 신월해남 임하
obs_datetimeString29704802026-06-07 13:30:0062nullnull2026-06-07 13:30:002026-06-08 01:30:002026-06-08 13:00:00
obs_layString29703011869nullnull113
wtr_tmpFloat2970183018.90000011617.2054884.1119740.20000018.60000023.000000
gru_namString297030남해1440nullnull남해동해서해
lonDouble2970390128.415100144127.7628421.178954124.729500128.148000129.549700
latDouble297039034.74980014435.7115311.39978133.31040034.83480038.368100
In [92]:
df_day.filter { gru_nam == "동해" }.plot {

    layout {
        size = 800 to 400
        x.axis.name = "Observatory"
        y.axis.name = "Temperature"
    }

    boxplot(sta_nam_kor, wtr_tmp) {
        boxes {
            fillColor(Stat.middle) {
                legend{
                    name = "Temperature "
                    breaks(format = "{d}°C")
                }
                scale = continuous(Color.BLUE..Color.RED)
            }
            // Border line color depends on `x` category
            borderLine.color(Stat.x)
            // `identity` position, i.e boxes are overlapping
        }

        outliers {
            // points context + StatBoxplotOutliers context
            // color depends on `x` category
            color(Stat.x){
                legend.name = "Observatory"
            }
        }
    }
}
Out[92]:
강릉 고성 가진 구룡포 하정 기장 삼척 양양 영덕 4 6 8 10 12 14 16 18 20 Temperature Observatory Temperature 12°C 14°C 16°C 18°C Observatory 강릉 고성 가진 구룡포 하정 기장 삼척 양양 영덕
In [91]:
val data_stat = df_day.filter { gru_nam == "동해" }.toMap()
val sta_nam_korByMiddle = asDiscrete("sta_nam_kor", orderBy = "..middle..", order = 1)

letsPlot( data_stat) { y = "wtr_tmp"} +
scaleColorViridis(option = "C", end = 0.8) +
scaleYContinuous(limits=Pair(0, 25) ) +
geomBoxplot(){ x=sta_nam_korByMiddle ; color = "..middle.."} +
labs(y="온도 °C", x="관측지점", color ="온도 °C") +
ggsize( width = 800, height = 400)
Out[91]:
In [93]:
val data_stat = df_day.filter { gru_nam == "서해" }.toMap()
val sta_nam_korByMiddle = asDiscrete("sta_nam_kor", orderBy = "..middle..", order = 1)

letsPlot( data_stat) { y = "wtr_tmp"} +
scaleColorViridis(option = "C", end = 0.8) +
scaleYContinuous(limits=Pair(0, 25) ) +
geomBoxplot(){ x=sta_nam_korByMiddle ; color = "..middle.."} +
labs(y="온도 °C", x="관측지점", color ="온도 °C") +
ggsize( width = 800, height = 400)
Out[93]:
In [96]:
val data_stat = df_day.filter { gru_nam == "남해" }.toMap()
val sta_nam_korByMiddle = asDiscrete("sta_nam_kor", orderBy = "..middle..", order = 1)

letsPlot( data_stat) { y = "wtr_tmp"} +
scaleColorViridis(option = "C", end = 0.8) +
scaleYContinuous(limits=Pair(0, 25) ) +
geomBoxplot(){ x=sta_nam_korByMiddle ; color = "..middle.."} +
labs(y="온도 °C", x="관측지점", color ="온도 °C") +
ggsize( width = 1500, height = 400)
Out[96]:
In [35]:
var df_current_raw = DataFrame.readJson("http://192.168.35.107:7788/nifs/seawaterinfo/current")
df_current_raw.describe()
Out[35]:

DataFrame: rowsCount = 8, columnsCount = 12

nametypecountuniquenullstopfreqmeanstdminmedianmax
sta_cdeString62390bgna33nullnullbgj8afnm5bwn087
sta_nam_korString62390강릉3nullnull강릉여수 신월해남 임하
obs_datetimeString62102026-06-08 13:00:0062nullnull2026-06-08 13:00:002026-06-08 13:00:002026-06-08 13:00:00
obs_layString6230139nullnull113
wtr_tmpString6243019.14nullnull0.218.89.7
gru_namString6230남해30nullnull남해동해서해
lonDouble62390128.9492003127.7626081.190227124.729500128.148000129.549700
latDouble6239037.799000335.7136691.41056633.31040034.85470038.368100
In [36]:
var df_current = df_current_raw.convert { wtr_tmp  }.with { it.toFloat() }
df_current.describe()
Out[36]:

DataFrame: rowsCount = 8, columnsCount = 12

nametypecountuniquenullstopfreqmeanstdminmedianmax
sta_cdeString62390bgna33nullnullbgj8afnm5bwn087
sta_nam_korString62390강릉3nullnull강릉여수 신월해남 임하
obs_datetimeString62102026-06-08 13:00:0062nullnull2026-06-08 13:00:002026-06-08 13:00:002026-06-08 13:00:00
obs_layString6230139nullnull113
wtr_tmpFloat6243019.100000417.4258063.9622370.20000018.60000022.700001
gru_namString6230남해30nullnull남해동해서해
lonDouble62390128.9492003127.7626081.190227124.729500128.148000129.549700
latDouble6239037.799000335.7136691.41056633.31040034.85470038.368100
In [37]:
df_current =  df_current.insert("관측층"){
    when(this.obs_lay){
        "1" -> "표층"
        "2" -> "중층"
        "3" -> "심층"
        else -> ""
    }
}.after("obs_lay")
df_current.describe()
Out[37]:

DataFrame: rowsCount = 9, columnsCount = 12

nametypecountuniquenullstopfreqmeanstdminmedianmax
sta_cdeString62390bgna33nullnullbgj8afnm5bwn087
sta_nam_korString62390강릉3nullnull강릉여수 신월해남 임하
obs_datetimeString62102026-06-08 13:00:0062nullnull2026-06-08 13:00:002026-06-08 13:00:002026-06-08 13:00:00
obs_layString6230139nullnull113
관측층String6230표층39nullnull심층표층표층
wtr_tmpFloat6243019.100000417.4258063.9622370.20000018.60000022.700001
gru_namString6230남해30nullnull남해동해서해
lonDouble62390128.9492003127.7626081.190227124.729500128.148000129.549700
latDouble6239037.799000335.7136691.41056633.31040034.85470038.368100
In [39]:
df_current
    .select{sta_nam_kor and wtr_tmp and "관측층"}
    .plot {
        layout {
            title = "관측 층별 해수 온도"
        size = 1500 to 400
            xAxisLabel = "Observatory"
            yAxisLabel = "Temperature( °C )"
        }

        bars {
            x(sta_nam_kor)

            y(wtr_tmp){
                scale = continuous(wtr_tmp.min().minus(1)..wtr_tmp.max().plus(1))
            }

            fillColor("관측층") {
                legend{
                    name = "Ocean Layer"
                }
                scale =  categoricalColorHue()
            }
        }
    }
Out[39]:
강릉 거제 가배 거제 일운 고성 가진 고흥 소록도 구룡포 하정 군산 신시도 기장 남해 강진 남해 미조 목포 백령도 보령 소도 삼척 서산 지곡 서산 창리 서제주 양양 여수 신월 영덕 완도 가교 완도 감목 완도 금일 완도 노화도 완도 동백 완도 망남 완도 백도 완도 일정 완도 청산 태안 고남 태안 대야도 태안 파도리 통영 비산도 통영 사량 통영 수월 통영 영운 통영 풍화 통영 학림 해남 임하 0 5 10 15 20 관측 층별 해수 온도 Temperature( °C ) Observatory Ocean Layer 표층 중층 심층
In [61]:
val data = df_current.select{sta_nam_kor and wtr_tmp and "관측층"}

letsPlot(data.toMap()) {  x = "sta_nam_kor" } +
    geomBar( position = positionDodge(), alpha = 0.5 )  {
        fill = "관측층"
        weight = "wtr_tmp" 
    } +
    labs( title="관측 층별 해수 온도", y="Temperature( °C )", x="Observatory", fill="Ocean Layer" ) +
    theme( axisTextX= elementText( angle=45)  ) +
    scaleYContinuous(limits=Pair(0, 25) ) +
    ggsize( width = 1500, height = 400)
Out[61]:
In [ ]: