From 5b534c6de81149d52ea244d42ffd6aa376da17be Mon Sep 17 00:00:00 2001 From: collnell Date: Fri, 1 Oct 2021 16:56:20 -0500 Subject: [PATCH 01/26] make gcolor scale global --- public/quant_peaks.csv | 14 +++++++------- src/components/GWL.vue | 29 +++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/public/quant_peaks.csv b/public/quant_peaks.csv index 186cfd7..4f4de7b 100644 --- a/public/quant_peaks.csv +++ b/public/quant_peaks.csv @@ -1,7 +1,7 @@ -color,peak_mid,quant,path_quant -#7E1900,5,Verylow,M-10 0 C -10 0 0 45 10 0 Z -#C1A53A,17.5,Low,M-10 0 C -10 0 0 32 10 0 Z -#8fce83,50,Normal,M-10 0 C -10 0 0 15 10 0 Z -#8fce83,50,Normal,M-10 0 C -10 0 0 -15 10 0 Z -#479BC5,82.5,High,M-10 0 C -10 0 0 -32 10 0 Z -#1A3399,95,Veryhigh,M-10 0 C -10 0 0 -45 10 0 Z +peak_mid,quant,path_quant +5,Verylow,M-10 0 C -10 0 0 45 10 0 Z +17.5,Low,M-10 0 C -10 0 0 32 10 0 Z +50,Normal,M-10 0 C -10 0 0 15 10 0 Z +50,Normal,M-10 0 C -10 0 0 -15 10 0 Z +82.5,High,M-10 0 C -10 0 0 -32 10 0 Z +95,Veryhigh,M-10 0 C -10 0 0 -45 10 0 Z diff --git a/src/components/GWL.vue b/src/components/GWL.vue index c05d4c3..bf5816c 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -73,7 +73,16 @@ export default { // style for timeline button_color: "grey", button_hilite: "black", - green: "rgb(143, 206, 131)", + + // 5 color scale of peaks + verylow: "#7E1900", + low: "#C1A53A", + normal: "#8fce83", + high: "#479BC5", + veryhigh: "#1A3399", + pal_roma: null, + pal_roma_rev: null, + // TODO: derive from pipeline. inputs are months, day sequence nested w/ key @@ -103,6 +112,9 @@ export default { this.width = window.innerWidth - this.margin.left - this.margin.right; this.height = window.innerHeight*.5 - this.margin.top - this.margin.bottom; + this.pal_roma = [this.verylow, this.low, this.normal, this.high, this.veryhigh]; + this.pal_roma_rev = [this.veryhigh, this.high, this.normal, this.low, this.verylow]; + // read in data this.loadData(); @@ -131,7 +143,7 @@ export default { // assign data this.quant_peaks = data[0]; // peak shapes for legend this.date_peaks = data[1]; // gwl timeseries data - this.site_coords = data[2]; // site positioning on svg + this.site_coords = data[2]; // site positioning on svg - not needed with svg fix? this.site_count = data[3]; // number of sites x quant_category x wyday // water days @@ -161,7 +173,7 @@ export default { // set color scale for path fill this.quant_color = this.d3.scaleThreshold() .domain([-40, -25, 25, 40]) - .range(["#1A3399","#479BC5",this.green,"#C1A53A","#7E1900"]) // using a slightly darker green + .range(this.pal_roma_rev) //same for bar chart data var quant_cat = [...new Set(this.quant_peaks.map(function(d) { return d.quant}))]; @@ -310,12 +322,12 @@ export default { .attr("transform", "translate(0," + 20 + ")") var y = this.d3.scaleLinear() - .domain([0, 0.5]) + .domain([0, 0.6]) .range([100, 0]) var bar_color = this.d3.scaleOrdinal() .domain(["Veryhigh", "High", "Normal", "Low","Verylow"]) - .range(["#1A3399","#479BC5",this.green,"#C1A53A","#7E1900"]) + .range(this.pal_roma_rev) var line = this.d3.line() .defined(d => !isNaN(d)) @@ -460,8 +472,9 @@ export default { .attr("transform", "translate(90, 0)") var legend_keys = ["Very low", "Low", "Normal", "High","Very high"]; // labels + var legend_color = [this.verylow, this.low, this.normal,this.normal, this.high, this.veryhigh]; var shape_dist = [5,25,42,42,60,83,103]; // y positioning (normal has 2 shapes butted together) - var perc_label = ["0 - 0.1", "0.1 - 0.25" ,"0.25 - 0.75", "0.75 - 0.9", "0.9+"] + var perc_label = ["0 - 0.1", "0.1 - 0.25" ,"0.25 - 0.75", "0.75 - 0.9", "0.9 +"] // draw path shapes and labels legend_peak @@ -486,7 +499,7 @@ export default { .data(this.quant_peaks) .enter() .append("path") - .attr("fill", function(d){return d["color"]}) + .attr("fill", function(d, i){return legend_color[i]}) .attr("d", function(d){return d["path_quant"]}) .attr("transform", function(d, i){return "translate(0, " + (140-shape_dist[i]) + ") scale(.8)"}) .attr("id", function(d){return d["quant"]}) @@ -543,7 +556,7 @@ export default { this.peak_grp .transition() .duration(this.day_length) // duration of each day - .attr("d", function(d) { return "M-7 0 C -7 0 0 " + d.gwl[start]*1.5 + " 7 0 Z" }) + .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" }) .attr("fill", function(d) { return self.quant_color(d.gwl[start]) }) .end() .then(() => this.animateGWL(start+1)) // loop animation increasing by 1 wyday From 7a870eb649d2b769d1cb67a44186e56cc5cb1d72 Mon Sep 17 00:00:00 2001 From: collnell Date: Fri, 1 Oct 2021 17:10:28 -0500 Subject: [PATCH 02/26] add color scale options --- src/components/GWL.vue | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/components/GWL.vue b/src/components/GWL.vue index bf5816c..42014f5 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -74,15 +74,30 @@ export default { button_color: "grey", button_hilite: "black", - // 5 color scale of peaks - verylow: "#7E1900", + // roma color scale + /* verylow: "#7E1900", low: "#C1A53A", normal: "#8fce83", high: "#479BC5", - veryhigh: "#1A3399", + veryhigh: "#1A3399", */ pal_roma: null, pal_roma_rev: null, + // color scale alternatives +/* // Green-Brown + verylow: "#a6611a", + low: "#dfc27d", + normal: "#f5f5f5", + high: "#80cdc1", + veryhigh: "#018571", */ + + // Blue-Brown + verylow: "#BF6200", + low: "#FEB100", + normal: "#B3B3B3", + high: "#2E9EC6", + veryhigh: "#28648A", + // TODO: derive from pipeline. inputs are months, day sequence nested w/ key @@ -114,6 +129,7 @@ export default { this.pal_roma = [this.verylow, this.low, this.normal, this.high, this.veryhigh]; this.pal_roma_rev = [this.veryhigh, this.high, this.normal, this.low, this.verylow]; + // read in data this.loadData(); From fbfd6e07e49bb94659bc7bd9fdab9cccfb258139 Mon Sep 17 00:00:00 2001 From: collnell Date: Fri, 1 Oct 2021 19:05:39 -0500 Subject: [PATCH 03/26] define first and last frames --- src/components/GWL.vue | 25 ++++++++++++++++--------- src/components/PreFooterCodeLinks.vue | 4 ++-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 42014f5..e7e3a30 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -62,10 +62,10 @@ export default { days: null, peak_grp: null, - day_length: 50, // frame duration in milliseconds + day_length: 1, // frame duration in milliseconds current_time: 0, start: 0, - n_days: 367, + n_days: 365, //x: 0, sites_list: null, //t2: null, @@ -549,25 +549,25 @@ export default { // select existing paths using class var start = this.start; - this.peak_grp = this.svg.selectAll("path.peak") + this.peak_grp = this.svg.selectAll("path.gwl_glyph") .data(data, function(d) { return d ? d.key : this.class; }) // binds data based on class/key .join("path") // match with selection .attr("transform", d => `translate(` + d.site_x + ' ' + d.site_y + `) scale(0.35 0.35)`) - // draws a oath for each site, using the first date + // draws a path for each site, using the first date this.peak_grp .attr("class", function(d) { return d.key }) - .attr("fill", function(d) { return self.quant_color(d.gwl[0]) }) // this is not exactly right - .attr("stroke-width", "1px") + .attr("fill", function(d) { return self.quant_color(d.gwl[0]) }) .attr("opacity", ".5") - .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start]*1 + " 10 0 Z" } ) // d.gwl.# corresponds to day of wy, starting with 0 + .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" } ) // d.gwl.# corresponds to day of wy, starting with 0 this.animateGWL(start); // once sites are drawn, trigger animation }, animateGWL(start){ const self = this; // animate path d and fill by wy day - if (start < this.n_days ){ + console.log(start) + if (start < 365 ){ // transition through days in sequence this.peak_grp .transition() @@ -582,7 +582,8 @@ export default { this.peak_grp .transition() .duration(this.day_length) // duration of each day - .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[this.n_days] + " 10 0 Z" }) + .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[365] + " 10 0 Z" }) + .attr("fill", function(d) { return self.quant_color(d.gwl[365]) }) } } } @@ -679,5 +680,11 @@ export default { margin-left: 10px; } } +// glyph paths +.gwl_glyph { + stroke: none; + fill-opacity: 50%; + //transform: scale(0.35, 0.35); +} \ No newline at end of file diff --git a/src/components/PreFooterCodeLinks.vue b/src/components/PreFooterCodeLinks.vue index 409b4a9..abe276c 100644 --- a/src/components/PreFooterCodeLinks.vue +++ b/src/components/PreFooterCodeLinks.vue @@ -29,12 +29,12 @@ display: flex; justify-content: right; width: 100%; - background-color: #c2c4c5; + background-color:#323333;; margin: 0 auto; padding: 0.4rem; border-bottom: 2px solid black; a { - color: #090211; + color: white; margin-left: 10px; font-family: 'Source Sans Pro',sans-serif; text-decoration: none From 7a0daa5cc9b1923d93856cced7028f2d833ba26a Mon Sep 17 00:00:00 2001 From: collnell Date: Fri, 1 Oct 2021 19:09:58 -0500 Subject: [PATCH 04/26] build peaks with d3 --- 3_visualize.yml | 23 +- 3_visualize/src/build_peaks_svg.R | 28 - 3_visualize/src/svg_utils_general.R | 1 + src/assets/anomaly_peaks.svg | 6671 +-------------------------- 4 files changed, 10 insertions(+), 6713 deletions(-) diff --git a/3_visualize.yml b/3_visualize.yml index c718a2d..3ea5cfc 100644 --- a/3_visualize.yml +++ b/3_visualize.yml @@ -19,25 +19,18 @@ targets: 3_visualize: depends: - - 3_visualize/out/anomaly_peaks.svg - - src/assets/anomaly_peaks.svg - - public/gw_sites.csv - - public/date_peaks.csv + - src/assets/anomaly_peaks.svg + - public/gw_sites.csv ## this is in aws as gw-conditions-sites.csv + - public/date_peaks.csv ## in aws as gw-conditions-wy20.csv + - public/gw-conditions-daily-count.csv ## in aws as gw-conditions-daily-count.csv - 3_visualize/out/anomaly_peaks.svg: + # exports that are leveraged by vue + src/assets/anomaly_peaks.svg: command: build_peaks_svg( target_name, - data_in = gw_anomaly_data_w_colors, - sites_sf = gw_sites_sf, svg_width = svg_width, svg_height = svg_height) - src/assets/anomaly_peaks.svg: - command: file.copy( - to = target_name, - from = '3_visualize/out/anomaly_peaks.svg', - overwrite = TRUE) - public/date_peaks.csv: command: gwl_to_peak( target_name, @@ -47,8 +40,8 @@ targets: command: get_site_coords( target_name, sites_sf = gw_sites_sf) - - public/gwl_daily_count.csv: + + public/gw-conditions-daily-count.csv: command: site_prop_timeseries(target_name, gw_anomaly_data_w_colors) diff --git a/3_visualize/src/build_peaks_svg.R b/3_visualize/src/build_peaks_svg.R index e20e455..3edb836 100644 --- a/3_visualize/src/build_peaks_svg.R +++ b/3_visualize/src/build_peaks_svg.R @@ -5,33 +5,5 @@ build_peaks_svg <- function(out_file, data_in, sites_sf, svg_width, svg_height) add_background_map(svg_root, svg_width = svg_width, outline_states = FALSE) - # Add spark line within group per site - - # TODO: THIS ONLY WORKS FOR A SINGLE DAY RIGHT NOW. I CHOSE OCT 31, 2019 - # TODO: Blanket removing any path with an NA in it. There is a smarter way - # to do this but will come back to that. - data_in <- data_in %>% - filter(Date == as.Date("2019-10-31")) %>% - filter(!grepl("NA", path)) - - sites <- sites_sf %>% pull(site_no) %>% unique - for(s in sites) { - site_coords_svg <- sites_sf %>% - filter(site_no == s) %>% - convert_coords_to_svg(svg_width = svg_width, view_bbox = st_bbox(generate_usa_map_data())) - - gw_data_s <- data_in %>% filter(site_no == s) - - # Spark lines centered at GW location - svg_root %>% - add_grp(grp_nm = s, trans_x = site_coords_svg$x, - trans_y = site_coords_svg$y) %>% - xml_add_child("path", - class = sprintf('gwl_%s', s), - style = sprintf("stroke: none; fill: %s; fill-opacity: 50%%", gw_data_s$color), - d = gw_data_s$path) - - } - xml2::write_xml(svg_root, file = out_file) } diff --git a/3_visualize/src/svg_utils_general.R b/3_visualize/src/svg_utils_general.R index 0ec1fb6..0456b2e 100644 --- a/3_visualize/src/svg_utils_general.R +++ b/3_visualize/src/svg_utils_general.R @@ -13,3 +13,4 @@ add_grp <- function(svg_root, grp_nm, trans_x, trans_y) { xml_add_child(svg_root, 'g', id = grp_nm, transform = sprintf("translate(%s %s) scale(0.35, 0.35)", trans_x, trans_y)) } + diff --git a/src/assets/anomaly_peaks.svg b/src/assets/anomaly_peaks.svg index ff7595e..b5fb566 100644 --- a/src/assets/anomaly_peaks.svg +++ b/src/assets/anomaly_peaks.svg @@ -1,5 +1,5 @@ - + @@ -12,6673 +12,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9e8919eb3b8367277a8bec3ff7b8e24016aa0d03 Mon Sep 17 00:00:00 2001 From: collnell Date: Fri, 1 Oct 2021 19:34:27 -0500 Subject: [PATCH 05/26] set axis scales globally --- src/components/FooterUSGS.vue | 12 ++--- src/components/GWL.vue | 64 +++++++++++++-------------- src/components/PreFooterCodeLinks.vue | 4 +- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/components/FooterUSGS.vue b/src/components/FooterUSGS.vue index e9e356a..0430703 100644 --- a/src/components/FooterUSGS.vue +++ b/src/components/FooterUSGS.vue @@ -178,7 +178,7 @@ footer.footer .footer-doi ul.menu li a { padding: 5px 0; - color: black; + color: #323333; float: left; font-size: 12px; } @@ -208,12 +208,12 @@ footer.footer .footer-wrap .menu.nav a { padding: 4px 0; - color: black; + color: #323333; font-size: 12px; } footer.footer .footer-social-links { - color: black; + color: #323333; font-size: 12px; padding-right: 0; } @@ -247,14 +247,14 @@ font-family: 'Source Sans Pro',sans-serif; font-size: 14px; line-height: 1.42857; - color: black; - background-color: black; + color: #323333; + background-color: #323333; padding-left: 15px; padding-right: 15px; } .svg-inline--fa { - color: black; + color: #323333; text-decoration: none; height: 24px; width: 21px; diff --git a/src/components/GWL.vue b/src/components/GWL.vue index e7e3a30..f8eacc6 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -50,6 +50,7 @@ export default { width: null, height: null, margin: { top: 50, right: 0, bottom: 50, left: 0 }, + mar: 20, // data mgmt quant_peaks: null, @@ -66,7 +67,6 @@ export default { current_time: 0, start: 0, n_days: 365, - //x: 0, sites_list: null, //t2: null, @@ -74,6 +74,10 @@ export default { button_color: "grey", button_hilite: "black", + // sclaes + xScale: null, + yScale: null, + // roma color scale /* verylow: "#7E1900", low: "#C1A53A", @@ -130,9 +134,9 @@ export default { this.pal_roma = [this.verylow, this.low, this.normal, this.high, this.veryhigh]; this.pal_roma_rev = [this.veryhigh, this.high, this.normal, this.low, this.verylow]; - // read in data this.loadData(); + this.setScales(); // define style before page fully loads this.svg = this.d3.select("svg.map") @@ -221,26 +225,19 @@ export default { drawLine(date_range, prop_data) { const self = this; - var line_width = this.width; var line_height = 250; - var mar = 20; // set up svg for timeline var svg = this.d3.select("#line-container") .append("svg") .attr("width", "100%") .attr("preserveAspectRatio", "xMinYMin meet") - .attr("viewBox", "0 0 " + line_width + " " + line_height) + .attr("viewBox", "0 0 " + this.width + " " + line_height) .attr("id", "x-line") - // scale space - var xScale = this.d3.scaleLinear() - .domain([0, this.n_days]) - .range([mar, line_width-2*mar]) - // define axes var xLine = this.d3.axisBottom() - .scale(xScale) + .scale(this.xScale) .ticks(0).tickSize(0); // draw axes @@ -268,7 +265,7 @@ export default { .append("circle") .attr("class", function(d,i) { return "button_inner inner_" + d.name + " " + d.name } ) .attr("r", 3) - .attr("cx", function(d) { return xScale(d.day) }) + .attr("cx", function(d) { return self.xScale(d.day) }) .attr("cy", 0) .attr("stroke", this.button_color) .attr("stroke-width", "2px") @@ -289,7 +286,7 @@ export default { .enter() .append("text") .attr("class", function(d,i) { return "button_name name_" + d.name + " " + d.name } ) - .attr("x", function(d) { return xScale(d.day)-12 }) // centering on pt + .attr("x", function(d) { return self.xScale(d.day)-12 }) // centering on pt .attr("y", 25) .attr("stroke", this.button_color) .text(function(d, i) { return d.name }) @@ -309,7 +306,7 @@ export default { button_month .append("text") .attr("class", function(d,i) { return "button_year" } ) - .attr("x", function(d) { return xScale(1)-10 }) // centering on pt + .attr("x", function(d) { return self.xScale(1)-10 }) // centering on pt .attr("y", 45) .attr("stroke", this.button_color) .text(function(d, i) { return 2021 }) @@ -317,7 +314,7 @@ export default { button_month .append("text") .attr("class", function(d,i) { return "button_year" } ) - .attr("x", function(d) { return xScale(367)-20 }) // centering on pt + .attr("x", function(d) { return self.xScale(367)-20 }) // centering on pt .attr("y", 45) .attr("stroke", this.button_color) .text(function(d, i) { return 2022 }) @@ -325,7 +322,7 @@ export default { button_month .append("text") .attr("class", function(d,i) { return "axis_label" } ) - .attr("x", function(d) { return xScale(1)-10 }) // centering on pt + .attr("x", function(d) { return self.xScale(1)-10 }) // centering on pt .attr("y", -110) .attr("stroke", this.button_color) .text(function(d, i) { return "Proportion of wells" }) @@ -337,21 +334,17 @@ export default { .attr("id", "time-legend") .attr("transform", "translate(0," + 20 + ")") - var y = this.d3.scaleLinear() - .domain([0, 0.6]) - .range([100, 0]) - var bar_color = this.d3.scaleOrdinal() .domain(["Veryhigh", "High", "Normal", "Low","Verylow"]) .range(this.pal_roma_rev) var line = this.d3.line() .defined(d => !isNaN(d)) - .x((d, i) => xScale(this.days[i])) - .y(d => y(d)) + .x((d, i) => self.xScale(this.days[i])) + .y(d => self.yScale(d)) // add line chart - const path = line_chart.append("g") + line_chart.append("g") .attr("fill", "none") .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") @@ -369,31 +362,36 @@ export default { line_chart.append("rect") .data(this.days) .classed("hilite", true) - //.attr("transform", "translate(1, 0)") .attr("width", "5") .attr("height", "100") .attr("opacity", 0.5) .attr("fill", "grey") - .attr("x", xScale(this.days[start])) + .attr("x", self.xScale(this.days[start])) this.animateLine(start); + }, + setScales(){ + + this.xScale = this.d3.scaleLinear() + .domain([0, this.n_days]) + .range([this.mar, this.width-2*this.mar]) + + this.yScale = this.d3.scaleLinear() + .domain([0, 0.6]) + .range([100, 0]) + }, animateLine(start){ // animates grey line on timeseries chart to represent current timepoint - var line_width = this.width; + const self = this; var line_height = 250; - var mar = 20; - - var x = this.d3.scaleLinear() - .domain([1, this.n_days]) - .range([mar, line_width-mar]) if (start < this.n_days){ this.d3.selectAll(".hilite") .transition() .duration(this.day_length) - .attr("x", x(this.days[start])) + .attr("x", self.xScale(this.days[start])) .end() .then(() => this.animateLine(start+1)) } else { @@ -566,7 +564,7 @@ export default { animateGWL(start){ const self = this; // animate path d and fill by wy day - console.log(start) + if (start < 365 ){ // transition through days in sequence this.peak_grp diff --git a/src/components/PreFooterCodeLinks.vue b/src/components/PreFooterCodeLinks.vue index abe276c..dc3eec9 100644 --- a/src/components/PreFooterCodeLinks.vue +++ b/src/components/PreFooterCodeLinks.vue @@ -29,10 +29,10 @@ display: flex; justify-content: right; width: 100%; - background-color:#323333;; + background-color:#323333; margin: 0 auto; padding: 0.4rem; - border-bottom: 2px solid black; + border-bottom: 2px solid #323333; a { color: white; margin-left: 10px; From 56f26e4a51374acbaec2da93800fe60310acd8af Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 12:54:50 -0500 Subject: [PATCH 06/26] add play button --- src/App.vue | 9 ++- src/assets/anomaly_peaks.svg | 2 +- src/components/GWL.vue | 116 ++++++++++++++++++++++++++--------- 3 files changed, 92 insertions(+), 35 deletions(-) diff --git a/src/App.vue b/src/App.vue index 87a4478..59981e7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -63,11 +63,9 @@ // Fonts @import url('https://fonts.googleapis.com/css2?family=Cairo:wght@200;300;400;600;700;900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Assistant:wght@200;300;400;500;600;700;800&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Abel&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap'); @import url("https://use.typekit.net/yww2frw.css"); -$Abel: 'Abel', sans-serif; $Cairo: 'Cairo', sans-serif; $Assistant: 'Assistant', sans-serif; $Noto: 'Noto Serif', serif; @@ -91,7 +89,7 @@ body { } h1{ font-size: 3.5em; - font-weight: 300; + font-weight: 600; font-family: $Assistant; line-height: 1; text-align: left; @@ -101,7 +99,7 @@ h1{ } } h2{ - font-weight: 400; + font-weight: 600; text-align: left; font-family:$Assistant; font-size: 3em; @@ -124,7 +122,8 @@ h3{ } p, text { padding: 1em 0 0 0; - font-family: $Assistant; + font-family: $acu_bold; + line-height: 1.5; } diff --git a/src/assets/anomaly_peaks.svg b/src/assets/anomaly_peaks.svg index b5fb566..036a317 100644 --- a/src/assets/anomaly_peaks.svg +++ b/src/assets/anomaly_peaks.svg @@ -1,5 +1,5 @@ - + diff --git a/src/components/GWL.vue b/src/components/GWL.vue index f8eacc6..7a7879e 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -50,7 +50,7 @@ export default { width: null, height: null, margin: { top: 50, right: 0, bottom: 50, left: 0 }, - mar: 20, + mar: 50, // data mgmt quant_peaks: null, @@ -69,6 +69,7 @@ export default { n_days: 365, sites_list: null, //t2: null, + isPlaying: null, // style for timeline button_color: "grey", @@ -212,6 +213,8 @@ export default { this.makeLegend(); this.drawFrame1(this.peaky); + this.playButton(this.svg, this.width*(2.5/7) , 300); + // animated time chart this.drawLine(this.days, this.percData) @@ -288,7 +291,6 @@ export default { .attr("class", function(d,i) { return "button_name name_" + d.name + " " + d.name } ) .attr("x", function(d) { return self.xScale(d.day)-12 }) // centering on pt .attr("y", 25) - .attr("stroke", this.button_color) .text(function(d, i) { return d.name }) .attr("text-align", "middle") .on('click', function(d, i) { @@ -308,7 +310,6 @@ export default { .attr("class", function(d,i) { return "button_year" } ) .attr("x", function(d) { return self.xScale(1)-10 }) // centering on pt .attr("y", 45) - .attr("stroke", this.button_color) .text(function(d, i) { return 2021 }) button_month @@ -316,15 +317,13 @@ export default { .attr("class", function(d,i) { return "button_year" } ) .attr("x", function(d) { return self.xScale(367)-20 }) // centering on pt .attr("y", 45) - .attr("stroke", this.button_color) .text(function(d, i) { return 2022 }) button_month .append("text") .attr("class", function(d,i) { return "axis_label" } ) .attr("x", function(d) { return self.xScale(1)-10 }) // centering on pt - .attr("y", -110) - .attr("stroke", this.button_color) + .attr("y", -100) .text(function(d, i) { return "Proportion of wells" }) // add line chart @@ -375,17 +374,69 @@ export default { this.xScale = this.d3.scaleLinear() .domain([0, this.n_days]) - .range([this.mar, this.width-2*this.mar]) + .range([this.mar/2, this.width-2*this.mar]) this.yScale = this.d3.scaleLinear() .domain([0, 0.6]) .range([100, 0]) }, + playButton(svg, x, y) { + const self = this; + + var button = svg.append("g") + .attr("transform", "translate("+ x +","+ y +")") + .attr("class", "play_button"); + + button + .append("rect") + .attr("width", 50) + .attr("height", 50) + .attr("rx", 4) + .style("fill", "steelblue"); + + // append hover title + button + .append("title") + .text("replay animation") + + button + .append("path") + .attr("d", "M15 10 L15 40 L35 25 Z") + .style("fill", "white"); + + button + .on("mousedown", function() { + self.animateLine(0); + self.animateGWL(0); + }); + }, + pressButton(playing) { + const self = this; + + // trigger animation if animation is not already playing + if (playing == false) { + self.animateChart_Map() + } + }, + resetPlayButton() { + const self = this; + + // reset global playing variable to false now that animation is complete + self.isPlaying = false; + + // undim button + let button_rect = this.d3.selectAll(".play_button").selectAll("rect") + .style("fill", 'rgb(250,109,49)') + + }, animateLine(start){ // animates grey line on timeseries chart to represent current timepoint const self = this; var line_height = 250; + + // set indicator for play button + self.isPlaying = true if (start < this.n_days){ this.d3.selectAll(".hilite") @@ -398,7 +449,7 @@ export default { this.d3.selectAll(".hilite") .transition() .duration(this.day_length) - .attr("x", x(this.days[this.n_days])) + .attr("x", self.xScale(this.days[this.n_days])) } }, buttonSelect(d){ @@ -413,7 +464,6 @@ export default { .duration(100) .attr("r", 6) .attr("fill", this.button_hilite) - .attr("stroke", this.button_hilite) }, buttonDeSelect(d){ // unhighlight on mouseout @@ -434,7 +484,6 @@ export default { .duration(100) .attr("r", 3) .attr("fill", this.button_color) - .attr("stroke", this.button_color) }, initTime(){ // TO DO: init nested timelines for playback control @@ -525,7 +574,7 @@ export default { .enter() .append("text") .attr("x", -20) - .attr("y", function(d,i){ return 140 - (i*22)}) // 100 is where the first dot appears. 25 is the distance between dots + .attr("y", function(d,i){ return 140 - (i*22)}) .text(function(d){ return d}) .attr("text-anchor", "end") .style("alignment-baseline", "middle") @@ -535,7 +584,7 @@ export default { .enter() .append("text") .attr("x", 20) - .attr("y", function(d,i){ return 140 - (i*22)}) // 100 is where the first dot appears. 25 is the distance between dots + .attr("y", function(d,i){ return 145 - (i*23)}) .text(function(d){ return d}) .attr("text-anchor", "start") .style("alignment-baseline", "middle") @@ -566,7 +615,6 @@ export default { // animate path d and fill by wy day if (start < 365 ){ - // transition through days in sequence this.peak_grp .transition() .duration(this.day_length) // duration of each day @@ -588,13 +636,15 @@ export default { } \ No newline at end of file From f658ad5913eecb3283979c8a003d3484e41ba463 Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 15:01:14 -0500 Subject: [PATCH 07/26] generate month labels in pipeline --- 2_process.yml | 6 +++- 2_process/src/prep_data_for_visualizing.R | 39 +++++++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/2_process.yml b/2_process.yml index 35186b5..d6d5c75 100644 --- a/2_process.yml +++ b/2_process.yml @@ -49,7 +49,11 @@ targets: # Prepare data for peaks SVG gw_anomaly_data: command: read_csv("2_process/out/gw_data_anomalies.csv") + gw_time: + command: generate_time(gw_anomaly_data) + public/gw-conditions-time-labels.csv: + command: generate_months(target_name, gw_time) gw_anomaly_data_w_paths: command: add_paths_to_data(gw_anomaly_data) gw_anomaly_data_w_colors: - command: add_colors_to_data(gw_anomaly_data_w_paths, scico_palette) + command: add_colors_to_data(gw_anomaly_data_w_paths, scico_palette, gw_time) diff --git a/2_process/src/prep_data_for_visualizing.R b/2_process/src/prep_data_for_visualizing.R index c12ee14..5b8d9c8 100644 --- a/2_process/src/prep_data_for_visualizing.R +++ b/2_process/src/prep_data_for_visualizing.R @@ -3,16 +3,19 @@ add_paths_to_data <- function(data_in) { data_in %>% mutate(path = build_path_peak(daily_quant)) } -add_colors_to_data <- function(data_in, scico_palette_nm = "roma") { +add_colors_to_data <- function(data_in, scico_palette_nm = "roma", gw_time) { # Create 5 color palette col_palette <- rev(scico::scico(5, palette = scico_palette_nm)) - data_in %>% - # Add number 1:365 for day of water year for each site - group_by(site_no) %>% - arrange(Date) %>% - mutate(wyday = row_number()) %>% - ungroup() %>% + date_full <- data_in %>% + # create a row for every date x site + mutate(site_no = as.character(site_no)) %>% + expand(Date, site_no) %>% + distinct() + + gw_time %>% + left_join(date_full) %>% + left_join(data_in %>% mutate(site_no = as.character(site_no))) %>% # Add color based on quantile category mutate(color = ifelse( quant_category == "Very high", @@ -26,3 +29,25 @@ add_colors_to_data <- function(data_in, scico_palette_nm = "roma") { quant_category == "Very low", yes = col_palette[5], no = "black")))))) } +generate_time <- function(data_in) { + date_start <- min(gw_anomaly_data$Date) + date_end <- max(gw_anomaly_data$Date) + + time_df <- tibble(Date = seq.Date(from = date_start, + to = date_end, + by = "1 day")) %>% + mutate(day_seq = as.numeric(rownames(.))) %>% + arrange(day_seq) + + return(time_df) + +} +generate_months <- function(file_out, data_in){ + data_in %>% + mutate(month = lubridate::month(Date), + month_label = lubridate::month(Date, label = TRUE), + year = lubridate::year(Date)) %>% + group_by(month, month_label, year) %>% + filter(day_seq == min(day_seq)) %>% ## find the first day of each month to draw labels + write_csv(file_out) +} \ No newline at end of file From 07333f544274960e106a5966b679d2383c485be5 Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 15:14:02 -0500 Subject: [PATCH 08/26] align time sequence when dates are missing --- 2_process.yml | 1 + 3_visualize.yml | 5 ++-- 3_visualize/src/svg_utils_vue.R | 33 ++++++++++++------------- src/components/GWL.vue | 43 ++++++++++++++++++++++----------- 4 files changed, 49 insertions(+), 33 deletions(-) diff --git a/2_process.yml b/2_process.yml index d6d5c75..afa47bb 100644 --- a/2_process.yml +++ b/2_process.yml @@ -20,6 +20,7 @@ targets: - 2_process/out/gw_daily_quantiles.csv - 2_process/out/gw_data_anomalies.csv - gw_sites_sf + - public/gw-conditions-time-labels.csv # Sites that use "depth below" as their gw level need to be inversed. In the # current implementation, this means any site that used pcode == '72019' diff --git a/3_visualize.yml b/3_visualize.yml index 3ea5cfc..ca10a72 100644 --- a/3_visualize.yml +++ b/3_visualize.yml @@ -21,7 +21,7 @@ targets: depends: - src/assets/anomaly_peaks.svg - public/gw_sites.csv ## this is in aws as gw-conditions-sites.csv - - public/date_peaks.csv ## in aws as gw-conditions-wy20.csv + - public/gw-conditions-wy20.csv ## in aws as gw-conditions-wy20.csv - public/gw-conditions-daily-count.csv ## in aws as gw-conditions-daily-count.csv # exports that are leveraged by vue @@ -31,7 +31,7 @@ targets: svg_width = svg_width, svg_height = svg_height) - public/date_peaks.csv: + public/gw-conditions-wy20.csv: command: gwl_to_peak( target_name, gw_anomaly_data_w_colors) @@ -45,4 +45,5 @@ targets: command: site_prop_timeseries(target_name, gw_anomaly_data_w_colors) + diff --git a/3_visualize/src/svg_utils_vue.R b/3_visualize/src/svg_utils_vue.R index a4389b7..f158bce 100644 --- a/3_visualize/src/svg_utils_vue.R +++ b/3_visualize/src/svg_utils_vue.R @@ -1,13 +1,13 @@ gwl_to_peak <- function(file_out, gw_anomaly_data_w_colors){ # Create timeseries data to draw peak animation with D3 - gw_anomaly_data_w_colors %>% + gw_anomaly_data_w_colors %>% mutate(quant = str_replace(quant_category, " ", ""), path_y = round(50-daily_quant, digits = 0)) %>% - filter(!is.na(quant)) %>% + #filter(!is.na(quant)) %>% mutate(site_no = paste0('gwl_', site_no)) %>% - select(site_no, wyday, daily_quant, path_y) %>% - dcast(wyday~site_no, value.var = 'path_y') %>% - arrange(wyday) %>% + select(site_no, day_seq, daily_quant, path_y) %>% + dcast(day_seq~site_no, value.var = 'path_y') %>% + arrange(day_seq) %>% write_csv(file_out) } @@ -20,25 +20,24 @@ get_site_coords <- function(file_out, sites_sf){ } site_prop_timeseries <- function(file_out, gw_anomaly_data_w_colors){ - gw <- gw_anomaly_data_w_colors %>% - filter(!is.na(quant_category)) %>% - group_by(Date) %>% - filter(wyday == max(wyday)) - - ## write json with timeseries of sites in each category - gw %>% - group_by(Date, wyday, quant_category) %>% + + ## write timeseries % of sites in each category + gw_anomaly_data_w_colors %>% + filter(!is.na(quant_category)) #%>% # filtering out dates with no category + group_by(Date, day_seq, quant_category) %>% summarize(n_sites = length(unique(site_no))) %>% left_join(gw %>% - group_by(Date, wyday) %>% + group_by(Date, day_seq) %>% summarize(n_sites_total = length(unique(site_no)))) %>% mutate(perc = n_sites/n_sites_total) %>% ungroup() %>% mutate(cat = gsub(" ", "", quant_category), perc = round(perc, 3)) %>% select(-quant_category) %>% - reshape2::dcast(Date+wyday+n_sites_total~cat, value.var = "perc") %>% - arrange(wyday) %>% + reshape2::dcast(Date+day_seq+n_sites_total~cat, value.var = "perc") %>% + arrange(day_seq) %>% write_csv(file_out) -} \ No newline at end of file +} + + diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 7a7879e..dd6a6ac 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -75,9 +75,12 @@ export default { button_color: "grey", button_hilite: "black", - // sclaes + // scales + dates: null, xScale: null, yScale: null, + pal_roma: null, + pal_roma_rev: null, // roma color scale /* verylow: "#7E1900", @@ -85,8 +88,6 @@ export default { normal: "#8fce83", high: "#479BC5", veryhigh: "#1A3399", */ - pal_roma: null, - pal_roma_rev: null, // color scale alternatives /* // Green-Brown @@ -137,7 +138,6 @@ export default { // read in data this.loadData(); - this.setScales(); // define style before page fully loads this.svg = this.d3.select("svg.map") @@ -163,7 +163,7 @@ export default { callback(data) { // assign data this.quant_peaks = data[0]; // peak shapes for legend - this.date_peaks = data[1]; // gwl timeseries data + this.date_peaks = data[1]; // gwl site level timeseries data this.site_coords = data[2]; // site positioning on svg - not needed with svg fix? this.site_count = data[3]; // number of sites x quant_category x wyday @@ -196,27 +196,36 @@ export default { .domain([-40, -25, 25, 40]) .range(this.pal_roma_rev) - //same for bar chart data + //same for timeseries data var quant_cat = [...new Set(this.quant_peaks.map(function(d) { return d.quant}))]; var n_quant = quant_cat.length this.percData = []; for (i = 0; i < n_quant; i++) { var key_quant = quant_cat[i]; - var wyday = this.site_count.map(function(d){ return d['wyday']}); + var wyday = this.site_count.map(function(d){ return d['Date']}); + //var date = this.site_count.map(function(d) { return d['Date']}); var perc = this.site_count.map(function(d){ return d[key_quant]}); this.percData.push({key_quant: key_quant, wyday: wyday, perc: perc}) }; this.days = this.site_count.map(function(d) { return d['wyday']}) + this.date = this.site_count.map(function(d) { return d['Date']}) + this.n_days = this.date.length + + //console.log(this.date) + + var date_par = Date.parse(this.date) + console.log(date_par) // draw the chart + this.setScales(); this.makeLegend(); this.drawFrame1(this.peaky); this.playButton(this.svg, this.width*(2.5/7) , 300); // animated time chart - this.drawLine(this.days, this.percData) + this.drawLine(this.percData) }, createPanel(month) { @@ -225,7 +234,7 @@ export default { // add rest of this return tl; }, - drawLine(date_range, prop_data) { + drawLine(prop_data) { const self = this; var line_height = 250; @@ -367,11 +376,13 @@ export default { .attr("fill", "grey") .attr("x", self.xScale(this.days[start])) - this.animateLine(start); + //this.animateLine(start); }, setScales(){ + console.log(this.date.range) + this.xScale = this.d3.scaleLinear() .domain([0, this.n_days]) .range([this.mar/2, this.width-2*this.mar]) @@ -407,8 +418,8 @@ export default { button .on("mousedown", function() { - self.animateLine(0); - self.animateGWL(0); + //self.animateLine(0); + //self.animateGWL(0); }); }, pressButton(playing) { @@ -486,7 +497,7 @@ export default { .attr("fill", this.button_color) }, initTime(){ - // TO DO: init nested timelines for playback control + // nested timelines for playback control // broken up by month and tagged for user control var tl_jan = new TimelineMax(); // TimelineMax permits repeating animation var tl_feb = new TimelineMax(); @@ -517,6 +528,10 @@ export default { .add(tl_nov) .add(tl_dec) + }, + animateCharts(){ + // link animation functions to same day + }, makeLegend(){ @@ -608,7 +623,7 @@ export default { .attr("opacity", ".5") .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" } ) // d.gwl.# corresponds to day of wy, starting with 0 - this.animateGWL(start); // once sites are drawn, trigger animation + //this.animateGWL(start); // once sites are drawn, trigger animation }, animateGWL(start){ const self = this; From 9914c0634b4e63e1add56453ce633f0062bd195b Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 16:11:42 -0500 Subject: [PATCH 09/26] refine timeline sequencing --- 3_visualize/src/svg_utils_vue.R | 4 +-- src/components/GWL.vue | 56 ++++++++++++++++----------------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/3_visualize/src/svg_utils_vue.R b/3_visualize/src/svg_utils_vue.R index f158bce..04f5a05 100644 --- a/3_visualize/src/svg_utils_vue.R +++ b/3_visualize/src/svg_utils_vue.R @@ -23,10 +23,10 @@ site_prop_timeseries <- function(file_out, gw_anomaly_data_w_colors){ ## write timeseries % of sites in each category gw_anomaly_data_w_colors %>% - filter(!is.na(quant_category)) #%>% # filtering out dates with no category + filter(!is.na(quant_category)) %>% # filtering out dates with no category group_by(Date, day_seq, quant_category) %>% summarize(n_sites = length(unique(site_no))) %>% - left_join(gw %>% + left_join(gw_anomaly_data_w_colors %>% group_by(Date, day_seq) %>% summarize(n_sites_total = length(unique(site_no)))) %>% mutate(perc = n_sites/n_sites_total) %>% diff --git a/src/components/GWL.vue b/src/components/GWL.vue index dd6a6ac..453b645 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -79,6 +79,7 @@ export default { dates: null, xScale: null, yScale: null, + line: null, pal_roma: null, pal_roma_rev: null, @@ -154,9 +155,11 @@ export default { // read in data let promises = [ self.d3.csv(self.publicPath + "quant_peaks.csv", this.d3.autotype), // used to draw legend shapes - color palette needs to be pulled out - self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-wy20.csv", this.d3.autotype), + //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-wy20.csv", this.d3.autotype), + self.d3.csv(self.publicPath + "gw-conditions-wy20.csv", this.d3.autotype), // needs to go to aws self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-sites.csv", this.d3.autotype), - self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-count.csv", this.d3.autotype) + //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-count.csv", this.d3.autotype) + self.d3.csv(self.publicPath + "gw-conditions-daily-count.csv", this.d3.autotype) // needs to go to aws ]; Promise.all(promises).then(self.callback); // once it's loaded }, @@ -165,11 +168,11 @@ export default { this.quant_peaks = data[0]; // peak shapes for legend this.date_peaks = data[1]; // gwl site level timeseries data this.site_coords = data[2]; // site positioning on svg - not needed with svg fix? - this.site_count = data[3]; // number of sites x quant_category x wyday + this.site_count = data[3]; // number of sites x quant_category x day_seq // water days - var wyday = this.date_peaks.columns - wyday.shift(); + var day_seq = this.date_peaks.columns + day_seq.shift(); // sites this.sites_list = this.site_coords.map(function(d) { return d.site_no }) @@ -184,11 +187,11 @@ export default { this.peaky = []; for (i = 1; i < n; i++) { var key = this.sites_list[i]; - var wyday = this.date_peaks.map(function(d){ return d['wyday']; }); + var day_seq = this.date_peaks.map(function(d){ return d['day_seq']; }); var gwl = this.date_peaks.map(function(d){ return d[key]; }); var site_x = this.sites_x[i]; var site_y = this.sites_y[i]; - this.peaky.push({key: key, wyday: wyday, gwl: gwl, site_x: site_x, site_y: site_y}) + this.peaky.push({key: key, day_seq: day_seq, gwl: gwl, site_x: site_x, site_y: site_y}) }; // set color scale for path fill @@ -202,20 +205,16 @@ export default { this.percData = []; for (i = 0; i < n_quant; i++) { var key_quant = quant_cat[i]; - var wyday = this.site_count.map(function(d){ return d['Date']}); + var day_seq = this.site_count.map(function(d){ return d['day_seq']}); //var date = this.site_count.map(function(d) { return d['Date']}); var perc = this.site_count.map(function(d){ return d[key_quant]}); - this.percData.push({key_quant: key_quant, wyday: wyday, perc: perc}) + this.percData.push({key_quant: key_quant, day_seq: day_seq, perc: perc}) }; - this.days = this.site_count.map(function(d) { return d['wyday']}) - this.date = this.site_count.map(function(d) { return d['Date']}) - this.n_days = this.date.length + this.days = this.site_count.map(function(d) { return d['day_seq']}) + //this.date = this.site_count.map(function(d) { return d['Date']}) + this.n_days = this.days.length - //console.log(this.date) - - var date_par = Date.parse(this.date) - console.log(date_par) // draw the chart this.setScales(); @@ -346,11 +345,6 @@ export default { .domain(["Veryhigh", "High", "Normal", "Low","Verylow"]) .range(this.pal_roma_rev) - var line = this.d3.line() - .defined(d => !isNaN(d)) - .x((d, i) => self.xScale(this.days[i])) - .y(d => self.yScale(d)) - // add line chart line_chart.append("g") .attr("fill", "none") @@ -359,7 +353,7 @@ export default { .selectAll("path") .data(prop_data) .join("path") - .attr("d", d => line(d.perc)) + .attr("d", d => self.line(d.perc)) .attr("stroke", function(d) { return bar_color(d.key_quant) }) .attr("stroke-width", "3px") .attr("opacity", 0.7); @@ -376,13 +370,11 @@ export default { .attr("fill", "grey") .attr("x", self.xScale(this.days[start])) - //this.animateLine(start); + this.animateLine(start); }, setScales(){ - console.log(this.date.range) - this.xScale = this.d3.scaleLinear() .domain([0, this.n_days]) .range([this.mar/2, this.width-2*this.mar]) @@ -391,6 +383,12 @@ export default { .domain([0, 0.6]) .range([100, 0]) + + this.line = this.d3.line() + .defined(d => !isNaN(d)) + .x((d, i) => this.xScale(this.days[i])) + .y(d => this.yScale(d)) + }, playButton(svg, x, y) { const self = this; @@ -418,8 +416,8 @@ export default { button .on("mousedown", function() { - //self.animateLine(0); - //self.animateGWL(0); + self.animateLine(0); + self.animateGWL(0); }); }, pressButton(playing) { @@ -623,7 +621,7 @@ export default { .attr("opacity", ".5") .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" } ) // d.gwl.# corresponds to day of wy, starting with 0 - //this.animateGWL(start); // once sites are drawn, trigger animation + this.animateGWL(start); // once sites are drawn, trigger animation }, animateGWL(start){ const self = this; @@ -636,7 +634,7 @@ export default { .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" }) .attr("fill", function(d) { return self.quant_color(d.gwl[start]) }) .end() - .then(() => this.animateGWL(start+1)) // loop animation increasing by 1 wyday + .then(() => this.animateGWL(start+1)) // loop animation increasing by 1 day_seq } else { // if it's the last day of the water year, stop animation From c9dca03a8f54a77c8ab4102354faba0b403dff52 Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 16:48:45 -0500 Subject: [PATCH 10/26] dynamically add month and year labels --- src/components/GWL.vue | 123 +++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 453b645..6a55133 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -59,6 +59,7 @@ export default { peaky: null, site_coords: null, site_count: null, + time_labels: null, percData: null, days: null, @@ -158,8 +159,9 @@ export default { //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-wy20.csv", this.d3.autotype), self.d3.csv(self.publicPath + "gw-conditions-wy20.csv", this.d3.autotype), // needs to go to aws self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-sites.csv", this.d3.autotype), - //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-count.csv", this.d3.autotype) - self.d3.csv(self.publicPath + "gw-conditions-daily-count.csv", this.d3.autotype) // needs to go to aws + //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-count.csv", this.d3.autotype), + self.d3.csv(self.publicPath + "gw-conditions-daily-count.csv", this.d3.autotype), // needs to go to aws + self.d3.csv(self.publicPath + "gw-conditions-time-labels.csv", this.d3.autotype) ]; Promise.all(promises).then(self.callback); // once it's loaded }, @@ -169,6 +171,7 @@ export default { this.date_peaks = data[1]; // gwl site level timeseries data this.site_coords = data[2]; // site positioning on svg - not needed with svg fix? this.site_count = data[3]; // number of sites x quant_category x day_seq + this.time_labels = data[4]; // timeline annotations - including months // water days var day_seq = this.date_peaks.columns @@ -206,16 +209,13 @@ export default { for (i = 0; i < n_quant; i++) { var key_quant = quant_cat[i]; var day_seq = this.site_count.map(function(d){ return d['day_seq']}); - //var date = this.site_count.map(function(d) { return d['Date']}); var perc = this.site_count.map(function(d){ return d[key_quant]}); this.percData.push({key_quant: key_quant, day_seq: day_seq, perc: perc}) }; this.days = this.site_count.map(function(d) { return d['day_seq']}) - //this.date = this.site_count.map(function(d) { return d['Date']}) - this.n_days = this.days.length + this.n_days = this.days.length-1 - // draw the chart this.setScales(); this.makeLegend(); @@ -233,57 +233,32 @@ export default { // add rest of this return tl; }, - drawLine(prop_data) { + addButtons(svg){ const self = this; + // timeline events/"buttons" + // want these to be buttons that rewind the animation to the date + // and also drive annotations to events + console.log(this.time_labels) - var line_height = 250; - - // set up svg for timeline - var svg = this.d3.select("#line-container") - .append("svg") - .attr("width", "100%") - .attr("preserveAspectRatio", "xMinYMin meet") - .attr("viewBox", "0 0 " + this.width + " " + line_height) - .attr("id", "x-line") - - // define axes - var xLine = this.d3.axisBottom() - .scale(this.xScale) - .ticks(0).tickSize(0); - - // draw axes - var liney = svg.append("g") - .call(xLine) - .attr("transform", "translate(0," + 120 + ")") - .classed("liney", true) - - // style axes - liney.select("path.domain") - .attr("id", "timeline-x") - .attr("color", "lightgrey") - .attr("stroke-width", "3px") - - // timeline events/"buttons" var button_month = svg.append("g") .classed("#btn-month", true) .attr("transform", "translate(0," + 120 + ")") .attr("z-index", 100) // month points on timeline - // TODO: make functions that accept any date and label for annotations button_month.selectAll(".button_inner") - .data(this.months).enter() + .data(this.time_labels).enter() .append("circle") - .attr("class", function(d,i) { return "button_inner inner_" + d.name + " " + d.name } ) + .attr("class", function(d,i) { return "button_inner inner_" + d.month_label + "_" + d.year } ) .attr("r", 3) - .attr("cx", function(d) { return self.xScale(d.day) }) + .attr("cx", function(d) { return self.xScale(d.day_seq) }) .attr("cy", 0) .attr("stroke", this.button_color) .attr("stroke-width", "2px") .attr("fill", this.button_color) - .on('click', function(d, i) { - //self.moveTimeline(d); // requires gsap for playback control or some way to cancel playback loop partway - }) + //.on('click', function(d, i) { + //self.moveTimeline(d); + // }) .on('mouseover', function(d, i) { self.buttonSelect(d); }) @@ -293,17 +268,17 @@ export default { // month labels button_month.selectAll(".button_name") - .data(this.months) + .data(this.time_labels) .enter() .append("text") - .attr("class", function(d,i) { return "button_name name_" + d.name + " " + d.name } ) - .attr("x", function(d) { return self.xScale(d.day)-12 }) // centering on pt + .attr("class", function(d,i) { return "button_name name_" + d.month_label + "_" + d.year } ) + .attr("x", function(d) { return self.xScale(d.day_seq)-12 }) // centering on pt .attr("y", 25) - .text(function(d, i) { return d.name }) + .text(function(d, i) { return d.month_label }) .attr("text-align", "middle") - .on('click', function(d, i) { + //.on('click', function(d, i) { //self.moveTimeline(d); - }) + //}) .on('mouseover', function(d, i) { self.buttonSelect(d); }) @@ -312,20 +287,14 @@ export default { }) // year annotations - // TODO: derive from data input via pipeline - button_month - .append("text") - .attr("class", function(d,i) { return "button_year" } ) - .attr("x", function(d) { return self.xScale(1)-10 }) // centering on pt - .attr("y", 45) - .text(function(d, i) { return 2021 }) - - button_month + button_month.selectAll(".button_year") + .data(this.time_labels) + .enter() .append("text") - .attr("class", function(d,i) { return "button_year" } ) - .attr("x", function(d) { return self.xScale(367)-20 }) // centering on pt + .attr("class", function(d,i) { return "button_year button_" + d.year } ) + .attr("x", function(d) { return self.xScale(d.day_seq)-10 }) // centering on pt .attr("y", 45) - .text(function(d, i) { return 2022 }) + .text(function(d, i) { return d.year }) button_month .append("text") @@ -334,6 +303,40 @@ export default { .attr("y", -100) .text(function(d, i) { return "Proportion of wells" }) + + }, + drawLine(prop_data) { + const self = this; + + var line_height = 250; + + // set up svg for timeline + var svg = this.d3.select("#line-container") + .append("svg") + .attr("width", "100%") + .attr("preserveAspectRatio", "xMinYMin meet") + .attr("viewBox", "0 0 " + this.width + " " + line_height) + .attr("id", "x-line") + + // define axes + var xLine = this.d3.axisBottom() + .scale(this.xScale) + .ticks(0).tickSize(0); + + // draw axes + var liney = svg.append("g") + .call(xLine) + .attr("transform", "translate(0," + 120 + ")") + .classed("liney", true) + + // style axes + liney.select("path.domain") + .attr("id", "timeline-x") + .attr("color", "lightgrey") + .attr("stroke-width", "3px") + + self.addButtons(svg) + // add line chart // line chart showing proportion of gages in each category var line_chart = svg.append("g") From d166d0d2301900f78734f14e1d43ab036f771b53 Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 17:55:52 -0500 Subject: [PATCH 11/26] drop unnecessary global variables --- 2_process/src/prep_data_for_visualizing.R | 3 + 3_visualize/src/svg_utils_mapping.R | 11 +- src/assets/anomaly_peaks.svg | 24 ++--- src/components/GWL.vue | 126 ++++++++++------------ 4 files changed, 79 insertions(+), 85 deletions(-) diff --git a/2_process/src/prep_data_for_visualizing.R b/2_process/src/prep_data_for_visualizing.R index 5b8d9c8..1a0b9ed 100644 --- a/2_process/src/prep_data_for_visualizing.R +++ b/2_process/src/prep_data_for_visualizing.R @@ -49,5 +49,8 @@ generate_months <- function(file_out, data_in){ year = lubridate::year(Date)) %>% group_by(month, month_label, year) %>% filter(day_seq == min(day_seq)) %>% ## find the first day of each month to draw labels + ungroup() %>% + group_by(year) %>% + mutate(year_label = ifelse(day_seq == min(day_seq), year, NA)) %>% write_csv(file_out) } \ No newline at end of file diff --git a/3_visualize/src/svg_utils_mapping.R b/3_visualize/src/svg_utils_mapping.R index 156e342..4544d30 100644 --- a/3_visualize/src/svg_utils_mapping.R +++ b/3_visualize/src/svg_utils_mapping.R @@ -5,14 +5,19 @@ add_background_map <- function(svg, svg_width, outline_states) { map_data <- generate_usa_map_data(outline_states = outline_states) - bkgrd_grp <- xml_add_child(svg, 'g', id = "bkgrd-map-grp") + bkgrd_grp <- xml_add_child(svg, 'g', + id = "bkgrd-map-grp", + class='map-bkgrd', + style="stroke:white;stroke-width:0.2;fill:white") purrr::map(map_data$ID, function(polygon_id, map_data, svg_width) { d <- map_data %>% filter(ID == polygon_id) %>% convert_coords_to_svg(view_bbox = st_bbox(map_data), svg_width) %>% build_path(connect = TRUE) - # "#e8d9c5" tan (what about slate grey #9fabb7) - xml_add_child(bkgrd_grp, 'path', d = d, class='map-bkgrd', style="stroke:#9fabb7;stroke-width:0.5;fill:none") + xml_add_child(bkgrd_grp, 'path', + d = d, + class='map-bkgrd', + style="stroke:white;stroke-width:0.2;fill:white") }, map_data, svg_width) } diff --git a/src/assets/anomaly_peaks.svg b/src/assets/anomaly_peaks.svg index 036a317..410100e 100644 --- a/src/assets/anomaly_peaks.svg +++ b/src/assets/anomaly_peaks.svg @@ -1,15 +1,15 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 6a55133..6121da2 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -56,7 +56,6 @@ export default { quant_peaks: null, date_peaks: null, svg: null, - peaky: null, site_coords: null, site_count: null, time_labels: null, @@ -106,26 +105,6 @@ export default { high: "#2E9EC6", veryhigh: "#28648A", - - - // TODO: derive from pipeline. inputs are months, day sequence nested w/ key - // timeline data - months: [ - { 'name': 'Jan', 'day': '1' }, - { 'name': 'Feb', 'day': '31' }, - { 'name': 'Mar', 'day': '60' }, - { 'name': 'Apr', 'day': '90' }, - { 'name': 'May', 'day': '120' }, - { 'name': 'Jun', 'day': '150' }, - { 'name': 'Jul', 'day': '181' }, - { 'name': 'Aug', 'day': '210' }, - { 'name': 'Sept', 'day': '240' }, - { 'name': 'Oct', 'day': '270' }, - { 'name': 'Nov', 'day': '300' }, - { 'name': 'Dec', 'day': '331' }, - { 'name': 'Jan', 'day': '367' } - ], - } }, mounted(){ @@ -141,14 +120,6 @@ export default { // read in data this.loadData(); - // define style before page fully loads - this.svg = this.d3.select("svg.map") - - this.svg.selectAll(".map-bkgrd") - .style("stroke", "white") - .style("stroke-width", "0.1px") - .style("fill", "white") - }, methods:{ loadData() { @@ -173,58 +144,64 @@ export default { this.site_count = data[3]; // number of sites x quant_category x day_seq this.time_labels = data[4]; // timeline annotations - including months - // water days + // days in sequence var day_seq = this.date_peaks.columns - day_seq.shift(); + day_seq.shift(); // drop first col with site_no - // sites + // sites this.sites_list = this.site_coords.map(function(d) { return d.site_no }) var n = this.sites_list.length // to create nested array for indexing in animation // site placement on map - this.sites_x = this.site_coords.map(function(d) { return d.x }) - this.sites_y = this.site_coords.map(function(d) { return d.y }) + var sites_x = this.site_coords.map(function(d) { return d.x }) + var sites_y = this.site_coords.map(function(d) { return d.y }) // reorganize - site is the key with gwl for each day of the wy // can be indexed using site key (gwl_#) - and used to bind data to DOM elements - this.peaky = []; + var peaky = []; for (i = 1; i < n; i++) { var key = this.sites_list[i]; var day_seq = this.date_peaks.map(function(d){ return d['day_seq']; }); var gwl = this.date_peaks.map(function(d){ return d[key]; }); - var site_x = this.sites_x[i]; - var site_y = this.sites_y[i]; - this.peaky.push({key: key, day_seq: day_seq, gwl: gwl, site_x: site_x, site_y: site_y}) + var site_x = sites_x[i]; + var site_y = sites_y[i]; + peaky.push({key: key, day_seq: day_seq, gwl: gwl, site_x: site_x, site_y: site_y}) }; - // set color scale for path fill - this.quant_color = this.d3.scaleThreshold() - .domain([-40, -25, 25, 40]) - .range(this.pal_roma_rev) - - //same for timeseries data + // same for timeseries data but indexed by percentile category var quant_cat = [...new Set(this.quant_peaks.map(function(d) { return d.quant}))]; var n_quant = quant_cat.length - this.percData = []; + var percData = []; for (i = 0; i < n_quant; i++) { var key_quant = quant_cat[i]; var day_seq = this.site_count.map(function(d){ return d['day_seq']}); var perc = this.site_count.map(function(d){ return d[key_quant]}); - this.percData.push({key_quant: key_quant, day_seq: day_seq, perc: perc}) + percData.push({key_quant: key_quant, day_seq: day_seq, perc: perc}) }; this.days = this.site_count.map(function(d) { return d['day_seq']}) this.n_days = this.days.length-1 - // draw the chart - this.setScales(); - this.makeLegend(); - this.drawFrame1(this.peaky); + // set up scales + this.setScales(); // axes, color, and line drawing fnu + this.makeLegend(); - this.playButton(this.svg, this.width*(2.5/7) , 300); + // draw the map + var map_svg = this.d3.select("svg.map") + /* map_svg.selectAll(".map-bkgrd") + .style("stroke", "white") + .style("stroke-width", "0.1px") + .style("fill", "white") */ + this.drawFrame1(map_svg, peaky); // animated time chart - this.drawLine(this.percData) + var time_container = this.d3.select("#line-container"); + this.drawLine(time_container, percData); + this.addButtons(time_container); + + // control animation + this.playButton(map_svg, this.width*(2.5/7) , 300); + }, createPanel(month) { @@ -233,14 +210,14 @@ export default { // add rest of this return tl; }, - addButtons(svg){ + addButtons(time_container){ const self = this; // timeline events/"buttons" // want these to be buttons that rewind the animation to the date // and also drive annotations to events - console.log(this.time_labels) - var button_month = svg.append("g") + var button_month = time_container.select('svg') + .append("g") .classed("#btn-month", true) .attr("transform", "translate(0," + 120 + ")") .attr("z-index", 100) @@ -259,12 +236,12 @@ export default { //.on('click', function(d, i) { //self.moveTimeline(d); // }) - .on('mouseover', function(d, i) { + /* .on('mouseover', function(d, i) { self.buttonSelect(d); }) .on('mouseout', function(d, i) { self.buttonDeSelect(d); - }) + }) */ // month labels button_month.selectAll(".button_name") @@ -275,20 +252,25 @@ export default { .attr("x", function(d) { return self.xScale(d.day_seq)-12 }) // centering on pt .attr("y", 25) .text(function(d, i) { return d.month_label }) - .attr("text-align", "middle") + .attr("text-align", "start") //.on('click', function(d, i) { //self.moveTimeline(d); //}) - .on('mouseover', function(d, i) { + /* .on('mouseover', function(d, i) { self.buttonSelect(d); }) .on('mouseout', function(d, i) { self.buttonDeSelect(d); - }) + }) */ + + // filter to just year annotations + var year_labels = this.time_labels.filter(function(el) { + return el.year_label >= 2000; + }); - // year annotations + // add year labels to timeline button_month.selectAll(".button_year") - .data(this.time_labels) + .data(year_labels) .enter() .append("text") .attr("class", function(d,i) { return "button_year button_" + d.year } ) @@ -305,13 +287,13 @@ export default { }, - drawLine(prop_data) { + drawLine(time_container, prop_data) { const self = this; var line_height = 250; // set up svg for timeline - var svg = this.d3.select("#line-container") + var svg = time_container .append("svg") .attr("width", "100%") .attr("preserveAspectRatio", "xMinYMin meet") @@ -335,8 +317,6 @@ export default { .attr("color", "lightgrey") .attr("stroke-width", "3px") - self.addButtons(svg) - // add line chart // line chart showing proportion of gages in each category var line_chart = svg.append("g") @@ -378,6 +358,11 @@ export default { }, setScales(){ + // set color scale for path fill + this.quant_color = this.d3.scaleThreshold() + .domain([-40, -25, 25, 40]) + .range(this.pal_roma_rev) + this.xScale = this.d3.scaleLinear() .domain([0, this.n_days]) .range([this.mar/2, this.width-2*this.mar]) @@ -606,13 +591,13 @@ export default { .style("alignment-baseline", "middle") }, - drawFrame1(data){ + drawFrame1(map_svg, data){ // draw the first frame of the animation const self = this; // select existing paths using class var start = this.start; - this.peak_grp = this.svg.selectAll("path.gwl_glyph") + this.peak_grp = map_svg.selectAll("path.gwl_glyph") .data(data, function(d) { return d ? d.key : this.class; }) // binds data based on class/key .join("path") // match with selection .attr("transform", d => `translate(` + d.site_x + ' ' + d.site_y + `) scale(0.35 0.35)`) @@ -676,7 +661,7 @@ $dark: #323333; display: flex; justify-content: center; align-items: center; - .map { + svg.map { max-height: 650px; } } @@ -716,7 +701,8 @@ $dark: #323333; #bkgrd-map-grp { filter: drop-shadow(0.2rem 0.2rem 0.5rem rgba(38, 49, 43, 0.15)); stroke-width: 0.2; - color: "white" + color: white; + fill: white; } // annotated timeline .liney { From 79cecf123ba6f77982b7e56c4e4b08b22e477332 Mon Sep 17 00:00:00 2001 From: collnell Date: Sat, 2 Oct 2021 18:52:43 -0500 Subject: [PATCH 12/26] add y axis to time chart --- src/App.vue | 4 +++ src/components/GWL.vue | 60 +++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/App.vue b/src/App.vue index 59981e7..80dad1c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -86,6 +86,10 @@ body { @media screen and (max-width: 600px) { font-size: 16px; } + .axis_label { + font-size: 20px; + font-weight: 600; + } } h1{ font-size: 3.5em; diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 6121da2..17b5835 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -63,7 +63,7 @@ export default { days: null, peak_grp: null, - day_length: 1, // frame duration in milliseconds + day_length: 10, // frame duration in milliseconds current_time: 0, start: 0, n_days: 365, @@ -188,10 +188,6 @@ export default { // draw the map var map_svg = this.d3.select("svg.map") - /* map_svg.selectAll(".map-bkgrd") - .style("stroke", "white") - .style("stroke-width", "0.1px") - .style("fill", "white") */ this.drawFrame1(map_svg, peaky); // animated time chart @@ -218,8 +214,7 @@ export default { var button_month = time_container.select('svg') .append("g") - .classed("#btn-month", true) - .attr("transform", "translate(0," + 120 + ")") + .attr("transform", "translate(20," + 120 + ")") .attr("z-index", 100) // month points on timeline @@ -227,10 +222,10 @@ export default { .data(this.time_labels).enter() .append("circle") .attr("class", function(d,i) { return "button_inner inner_" + d.month_label + "_" + d.year } ) - .attr("r", 3) + .attr("r", 5) .attr("cx", function(d) { return self.xScale(d.day_seq) }) .attr("cy", 0) - .attr("stroke", this.button_color) + .attr("stroke", "white") .attr("stroke-width", "2px") .attr("fill", this.button_color) //.on('click', function(d, i) { @@ -249,7 +244,7 @@ export default { .enter() .append("text") .attr("class", function(d,i) { return "button_name name_" + d.month_label + "_" + d.year } ) - .attr("x", function(d) { return self.xScale(d.day_seq)-12 }) // centering on pt + .attr("x", function(d) { return self.xScale(d.day_seq)-10 }) // centering on pt .attr("y", 25) .text(function(d, i) { return d.month_label }) .attr("text-align", "start") @@ -263,7 +258,7 @@ export default { self.buttonDeSelect(d); }) */ - // filter to just year annotations + // filter to just year annotations for first month they appear var year_labels = this.time_labels.filter(function(el) { return el.year_label >= 2000; }); @@ -278,12 +273,13 @@ export default { .attr("y", 45) .text(function(d, i) { return d.year }) + // chart title button_month .append("text") .attr("class", function(d,i) { return "axis_label" } ) - .attr("x", function(d) { return self.xScale(1)-10 }) // centering on pt - .attr("y", -100) - .text(function(d, i) { return "Proportion of wells" }) + .attr("x", function(d) { return self.xScale(1)-40 }) // centering on pt + .attr("y", -120) + .text(function(d, i) { return "Wells by groundwater level" }) }, @@ -291,13 +287,14 @@ export default { const self = this; var line_height = 250; + var y_nudge = 20; // set up svg for timeline var svg = time_container .append("svg") .attr("width", "100%") .attr("preserveAspectRatio", "xMinYMin meet") - .attr("viewBox", "0 0 " + this.width + " " + line_height) + .attr("viewBox", "0 -20 " + this.width + " " + line_height) .attr("id", "x-line") // define axes @@ -305,24 +302,39 @@ export default { .scale(this.xScale) .ticks(0).tickSize(0); + var yLine = this.d3.axisLeft().tickFormat(this.d3.format('~%')) + .scale(this.yScale) + .ticks(2).tickSize(6); + // draw axes - var liney = svg.append("g") + var xliney = svg.append("g") .call(xLine) - .attr("transform", "translate(0," + 120 + ")") + .attr("transform", "translate(20," + 120 + ")") + .classed("liney", true) + + var yliney = svg.append("g") + .call(yLine) + .attr("transform", "translate(47," + y_nudge + ")") .classed("liney", true) // style axes - liney.select("path.domain") + xliney.select("path.domain") .attr("id", "timeline-x") - .attr("color", "lightgrey") - .attr("stroke-width", "3px") + .attr("color", "white") + .attr("stroke-width", "4px") + + yliney.select("path.domain") + .attr("id", "timeline-y") + .attr("color", "white") + .attr("stroke-width", "4px") + .attr('font-size', '5rem') // add line chart // line chart showing proportion of gages in each category var line_chart = svg.append("g") .classed("time-chart", true) .attr("id", "time-legend") - .attr("transform", "translate(0," + 20 + ")") + .attr("transform", "translate(20," + y_nudge + ")") var bar_color = this.d3.scaleOrdinal() .domain(["Veryhigh", "High", "Normal", "Low","Verylow"]) @@ -363,15 +375,16 @@ export default { .domain([-40, -25, 25, 40]) .range(this.pal_roma_rev) + // x axis of line chart this.xScale = this.d3.scaleLinear() .domain([0, this.n_days]) .range([this.mar/2, this.width-2*this.mar]) + // y axis of line chart this.yScale = this.d3.scaleLinear() - .domain([0, 0.6]) + .domain([0, 0.6]) // this should come from the data - round up from highest proportion value .range([100, 0]) - this.line = this.d3.line() .defined(d => !isNaN(d)) .x((d, i) => this.xScale(this.days[i])) @@ -744,5 +757,4 @@ text-container { stroke: none; fill-opacity: 50%; } - \ No newline at end of file From bf4bb658552c5cf749484283512f1d0b43974bc2 Mon Sep 17 00:00:00 2001 From: collnell Date: Sun, 3 Oct 2021 10:24:44 -0500 Subject: [PATCH 13/26] read data from aws --- src/components/GWL.vue | 50 +++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 17b5835..e46b57a 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -125,14 +125,18 @@ export default { loadData() { const self = this; // read in data + // providing multiple file paths for the data because need to be updated in AWS to reflect latest changes in pipeline + // can run from public folder if building targets locally + let promises = [ self.d3.csv(self.publicPath + "quant_peaks.csv", this.d3.autotype), // used to draw legend shapes - color palette needs to be pulled out - //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-wy20.csv", this.d3.autotype), - self.d3.csv(self.publicPath + "gw-conditions-wy20.csv", this.d3.autotype), // needs to go to aws + self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-wy20.csv", this.d3.autotype), + //self.d3.csv(self.publicPath + "gw-conditions-wy20.csv", this.d3.autotype), // needs to go to aws self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-sites.csv", this.d3.autotype), - //self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-count.csv", this.d3.autotype), - self.d3.csv(self.publicPath + "gw-conditions-daily-count.csv", this.d3.autotype), // needs to go to aws - self.d3.csv(self.publicPath + "gw-conditions-time-labels.csv", this.d3.autotype) + self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-count.csv", this.d3.autotype), + //self.d3.csv(self.publicPath + "gw-conditions-daily-count.csv", this.d3.autotype), // needs to go to aws + self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-time-labels.csv", this.d3.autotype), + //self.d3.csv(self.publicPath + "gw-conditions-time-labels.csv", this.d3.autotype) // needs to go to aws ]; Promise.all(promises).then(self.callback); // once it's loaded }, @@ -180,7 +184,8 @@ export default { }; this.days = this.site_count.map(function(d) { return d['day_seq']}) - this.n_days = this.days.length-1 + this.dates = this.site_count.map(function(d) { return d['Date']}) + this.n_days = this.days.length // set up scales this.setScales(); // axes, color, and line drawing fnu @@ -196,7 +201,9 @@ export default { this.addButtons(time_container); // control animation - this.playButton(map_svg, this.width*(2.5/7) , 300); + this.animateLine(this.start); + this.animateGWL(this.start); + this.playButton(map_svg, this.width*(2.5/7) , 300); }, @@ -354,8 +361,6 @@ export default { .attr("opacity", 0.7); // animate line to time - var start = this.start; - line_chart.append("rect") .data(this.days) .classed("hilite", true) @@ -363,9 +368,16 @@ export default { .attr("height", "100") .attr("opacity", 0.5) .attr("fill", "grey") - .attr("x", self.xScale(this.days[start])) - - this.animateLine(start); + .attr("x", self.xScale(this.days[this.start])) + + // add date ticker +/* line_chart + .append("text") + .attr("class", "ticker-date") + .attr("x", self.xScale(365)) // centering on pt + .attr("y", -10) + .text( this.dates[this.start]) + .attr("text-anchor", "end") */ }, setScales(){ @@ -377,7 +389,7 @@ export default { // x axis of line chart this.xScale = this.d3.scaleLinear() - .domain([0, this.n_days]) + .domain([0, this.n_days-1]) .range([this.mar/2, this.width-2*this.mar]) // y axis of line chart @@ -455,11 +467,19 @@ export default { .attr("x", self.xScale(this.days[start])) .end() .then(() => this.animateLine(start+1)) + + /* this.d3.selectAll(".ticker-date") + .transition() + .duration(this.day_length) + .text(this.dates[start]) + .end() + .then(() => this.animateLine(start+1)) */ + } else { this.d3.selectAll(".hilite") .transition() .duration(this.day_length) - .attr("x", self.xScale(this.days[this.n_days])) + .attr("x", self.xScale(this.days[this.n_days-1])) } }, buttonSelect(d){ @@ -622,7 +642,7 @@ export default { .attr("opacity", ".5") .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" } ) // d.gwl.# corresponds to day of wy, starting with 0 - this.animateGWL(start); // once sites are drawn, trigger animation + // this.animateGWL(this.start); // once sites are drawn, trigger animation }, animateGWL(start){ const self = this; From d9548982b0d46bfa4aaed048a8b0046441a910dd Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 4 Oct 2021 14:18:18 -0500 Subject: [PATCH 14/26] address LP comments --- 2_process.yml | 2 +- 2_process/src/prep_data_for_visualizing.R | 20 ++++++++++++-------- 3_visualize/src/build_peaks_svg.R | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/2_process.yml b/2_process.yml index afa47bb..f8ddbf1 100644 --- a/2_process.yml +++ b/2_process.yml @@ -49,7 +49,7 @@ targets: # Prepare data for peaks SVG gw_anomaly_data: - command: read_csv("2_process/out/gw_data_anomalies.csv") + command: read_csv("2_process/out/gw_data_anomalies.csv", col_types = I('cDnnc')) gw_time: command: generate_time(gw_anomaly_data) public/gw-conditions-time-labels.csv: diff --git a/2_process/src/prep_data_for_visualizing.R b/2_process/src/prep_data_for_visualizing.R index 1a0b9ed..9775726 100644 --- a/2_process/src/prep_data_for_visualizing.R +++ b/2_process/src/prep_data_for_visualizing.R @@ -9,13 +9,14 @@ add_colors_to_data <- function(data_in, scico_palette_nm = "roma", gw_time) { date_full <- data_in %>% # create a row for every date x site - mutate(site_no = as.character(site_no)) %>% expand(Date, site_no) %>% distinct() + # bind data to full date sequence so data are complete for each site even with missing data + # this prevents misalignment of dates and animation sequence in later steps gw_time %>% left_join(date_full) %>% - left_join(data_in %>% mutate(site_no = as.character(site_no))) %>% + left_join(data_in) %>% # Add color based on quantile category mutate(color = ifelse( quant_category == "Very high", @@ -30,27 +31,30 @@ add_colors_to_data <- function(data_in, scico_palette_nm = "roma", gw_time) { yes = col_palette[5], no = "black")))))) } generate_time <- function(data_in) { - date_start <- min(gw_anomaly_data$Date) - date_end <- max(gw_anomaly_data$Date) + date_start <- min(data_in$Date) + date_end <- max(data_in$Date) time_df <- tibble(Date = seq.Date(from = date_start, to = date_end, by = "1 day")) %>% - mutate(day_seq = as.numeric(rownames(.))) %>% - arrange(day_seq) + mutate(day_seq = dplyr::row_number(.)) return(time_df) } generate_months <- function(file_out, data_in){ + # create data to drive annotations on the timeline + # this includes month and year labels data_in %>% mutate(month = lubridate::month(Date), month_label = lubridate::month(Date, label = TRUE), year = lubridate::year(Date)) %>% group_by(month, month_label, year) %>% - filter(day_seq == min(day_seq)) %>% ## find the first day of each month to draw labels + # draw month labels to the first day of the month + filter(day_seq == min(day_seq)) %>% ungroup() %>% group_by(year) %>% - mutate(year_label = ifelse(day_seq == min(day_seq), year, NA)) %>% + # label years on first month they appear + mutate(year_label = ifelse(day_seq == min(day_seq), year, NA)) %>% write_csv(file_out) } \ No newline at end of file diff --git a/3_visualize/src/build_peaks_svg.R b/3_visualize/src/build_peaks_svg.R index 3edb836..8d6004e 100644 --- a/3_visualize/src/build_peaks_svg.R +++ b/3_visualize/src/build_peaks_svg.R @@ -1,5 +1,5 @@ -build_peaks_svg <- function(out_file, data_in, sites_sf, svg_width, svg_height) { +build_peaks_svg <- function(out_file, svg_width, svg_height) { svg_root <- init_svg(viewbox_dims = c(0, 0, svg_width=svg_width, svg_height=svg_height)) From cbc0815d08d1978326f91225614182489e529122 Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 25 Oct 2021 20:31:46 -0500 Subject: [PATCH 15/26] add GA tag --- public/index.html | 9 +++++++++ src/assets/usgsHeaderAndFooter/images/usgsLogo.svg | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/public/index.html b/public/index.html index 66f7994..c988414 100644 --- a/public/index.html +++ b/public/index.html @@ -1,6 +1,15 @@ + + + diff --git a/src/assets/usgsHeaderAndFooter/images/usgsLogo.svg b/src/assets/usgsHeaderAndFooter/images/usgsLogo.svg index 965b9a8..206e27c 100644 --- a/src/assets/usgsHeaderAndFooter/images/usgsLogo.svg +++ b/src/assets/usgsHeaderAndFooter/images/usgsLogo.svg @@ -1,3 +1,6 @@ - From a6de9c819db38f8958fd758068bfea05726bc32b Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 25 Oct 2021 20:36:49 -0500 Subject: [PATCH 17/26] add description --- public/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/index.html b/public/index.html index 287725f..a3d7feb 100644 --- a/public/index.html +++ b/public/index.html @@ -20,18 +20,18 @@ <%= VUE_APP_TITLE %> - + - + - + - - \ No newline at end of file From e379f32ba0d6efb2357a43142ef5624f8a3ecbf0 Mon Sep 17 00:00:00 2001 From: collnell Date: Sun, 31 Oct 2021 11:27:31 -0500 Subject: [PATCH 20/26] rename data --- 3_visualize.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/3_visualize.yml b/3_visualize.yml index ca10a72..276d560 100644 --- a/3_visualize.yml +++ b/3_visualize.yml @@ -20,11 +20,12 @@ targets: 3_visualize: depends: - src/assets/anomaly_peaks.svg - - public/gw_sites.csv ## this is in aws as gw-conditions-sites.csv + - public/gw-conditions-site-coords.csv ## this is in aws as gw-conditions-sites.csv - public/gw-conditions-wy20.csv ## in aws as gw-conditions-wy20.csv - - public/gw-conditions-daily-count.csv ## in aws as gw-conditions-daily-count.csv + - public/gw-conditions-daily-proportion.csv ## in aws as gw-conditions-daily-count.csv # exports that are leveraged by vue + # TODO: send to s3 src/assets/anomaly_peaks.svg: command: build_peaks_svg( target_name, @@ -36,12 +37,12 @@ targets: target_name, gw_anomaly_data_w_colors) - public/gw_sites.csv: + public/gw-conditions-site-coords.csv: command: get_site_coords( target_name, sites_sf = gw_sites_sf) - public/gw-conditions-daily-count.csv: + public/gw-conditions-daily-proportion.csv: command: site_prop_timeseries(target_name, gw_anomaly_data_w_colors) From ef861e89c629b18418f5e78882f878b982d8f239 Mon Sep 17 00:00:00 2001 From: collnell Date: Sun, 31 Oct 2021 19:51:34 -0500 Subject: [PATCH 21/26] refine legend positioning --- public/quant_peaks.csv | 3 +- src/components/GWL.vue | 111 ++++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/public/quant_peaks.csv b/public/quant_peaks.csv index 4f4de7b..135dfc3 100644 --- a/public/quant_peaks.csv +++ b/public/quant_peaks.csv @@ -1,7 +1,6 @@ peak_mid,quant,path_quant 5,Verylow,M-10 0 C -10 0 0 45 10 0 Z 17.5,Low,M-10 0 C -10 0 0 32 10 0 Z -50,Normal,M-10 0 C -10 0 0 15 10 0 Z -50,Normal,M-10 0 C -10 0 0 -15 10 0 Z +50,Normal,M-10 0 C -10 0 0 15 10 0 C 10 0 0 -15 -10 0 Z 82.5,High,M-10 0 C -10 0 0 -32 10 0 Z 95,Veryhigh,M-10 0 C -10 0 0 -45 10 0 Z diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 354baa3..a093730 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -80,23 +80,7 @@ export default { xScale: null, yScale: null, line: null, - pal_roma: null, - pal_roma_rev: null, - - // roma color scale - /* verylow: "#7E1900", - low: "#C1A53A", - normal: "#8fce83", - high: "#479BC5", - veryhigh: "#1A3399", */ - - // color scale alternatives -/* // Green-Brown - verylow: "#a6611a", - low: "#dfc27d", - normal: "#f5f5f5", - high: "#80cdc1", - veryhigh: "#018571", */ + //gwl_color: null, // Blue-Brown verylow: "#BF6200", @@ -104,6 +88,7 @@ export default { normal: "#B3B3B3", high: "#2E9EC6", veryhigh: "#28648A", + pal_BuBr: null, } }, @@ -113,9 +98,7 @@ export default { // resize this.width = window.innerWidth - this.margin.left - this.margin.right; this.height = window.innerHeight*.5 - this.margin.top - this.margin.bottom; - - this.pal_roma = [this.verylow, this.low, this.normal, this.high, this.veryhigh]; - this.pal_roma_rev = [this.veryhigh, this.high, this.normal, this.low, this.verylow]; + this.pal_BuBr = [this.veryhigh, this.high, this.normal, this.low, this.verylow]; // read in data this.loadData(); @@ -356,10 +339,6 @@ export default { .attr("id", "time-legend") .attr("transform", "translate(20," + y_nudge + ")") - var bar_color = this.d3.scaleOrdinal() - .domain(["Veryhigh", "High", "Normal", "Low","Verylow"]) - .range(this.pal_roma_rev) - // add line chart line_chart.append("g") .attr("fill", "none") @@ -369,7 +348,7 @@ export default { .data(prop_data) .join("path") .attr("d", d => self.line(d.perc)) - .attr("stroke", function(d) { return bar_color(d.key_quant) }) + .attr("stroke", function(d) { return self.gwl_color(d.key_quant) }) .attr("stroke-width", "3px") .attr("opacity", 0.7); @@ -398,7 +377,7 @@ export default { // set color scale for path fill this.quant_color = this.d3.scaleThreshold() .domain([-40, -25, 25, 40]) - .range(this.pal_roma_rev) + .range(this.pal_BuBr) // x axis of line chart this.xScale = this.d3.scaleLinear() @@ -410,11 +389,17 @@ export default { .domain([0, 0.6]) // this should come from the data - round up from highest proportion value .range([100, 0]) + // line drawing this.line = this.d3.line() .defined(d => !isNaN(d)) .x((d, i) => this.xScale(this.days[i])) .y(d => this.yScale(d)) + // categorical color scale + this.gwl_color = this.d3.scaleOrdinal() + .domain(["Veryhigh", "High", "Normal", "Low","Verylow"]) + .range(this.pal_BuBr) + }, playButton(svg, x, y) { const self = this; @@ -567,8 +552,9 @@ export default { }, makeLegend(){ + const self = this; - var legend_height = 160; + var legend_height = 200; var legend_width = 240; // make a legend @@ -580,62 +566,82 @@ export default { .attr("preserveAspectRatio", "xMinYMin meet") .attr("viewbox", "0 0 " + legend_width + " " + legend_height) .append("g").classed("legend", true) - .attr("transform", "translate(90, 0)") - + .attr("transform", "translate(0, 0)") + + // legend elements var legend_keys = ["Very low", "Low", "Normal", "High","Very high"]; // labels - var legend_color = [this.verylow, this.low, this.normal,this.normal, this.high, this.veryhigh]; - var shape_dist = [5,25,42,42,60,83,103]; // y positioning (normal has 2 shapes butted together) - var perc_label = ["0 - 0.1", "0.1 - 0.25" ,"0.25 - 0.75", "0.75 - 0.9", "0.9 +"] + var perc_label = ["0.00 - 0.10", "0.10 - 0.25" ,"0.25 - 0.75", "0.75 - 0.90", "0.90 - 1.00"] // percentile ranges + // draw path shapes and labels + var legend_title_x = 0; + var legend_label_x = 56; legend_peak .append("text") - .text("GWL") - .attr("x", -20) - .attr("y", "30") + .text("Groundwater levels") + .attr("x", legend_title_x) + .attr("y", "20") .style("font-size", "20") - .style("font-weight", 700) - .attr("text-anchor", "end") + .style("font-weight", 600) // matching css of .axis_labels + .attr("text-anchor", "start") legend_peak .append("text") - .text("Percentile") - .attr("x", 105) - .attr("y", "30") - .style("font-size", "20") - .style("font-weight", 700) - .attr("text-anchor", "end") + .text("Percentile based on historic") + .attr("x", legend_title_x) + .attr("y", "40") + .style("font-size", "16px") + .style("font-weight", 400) + .attr("text-anchor", "start") + + legend_peak + .append("text") + .text("daily record at each site") + .attr("x", legend_title_x) + .attr("y", "60") + .style("font-size", "16px") + .style("font-weight", 400) + .attr("text-anchor", "start") + + + var label_end = 180; // moves legend keys and labels up and down + var label_space = 23; // spacing between legend elements + // add glyphs legend_peak.selectAll("peak_symbol") .data(this.quant_peaks) .enter() .append("path") - .attr("fill", function(d, i){return legend_color[i]}) + .attr("fill", function(d){return self.gwl_color(d.quant)}) .attr("d", function(d){return d["path_quant"]}) - .attr("transform", function(d, i){return "translate(0, " + (140-shape_dist[i]) + ") scale(.8)"}) + .attr("transform", function(d, i){return "translate(" + 95 + ", " + ((label_end-8)-20*i) + ") scale(.85)"}) .attr("id", function(d){return d["quant"]}) .attr("class", "peak_symbol") - // add categorical labels very low - very high + // add categorical labels ranked from very low to very high legend_peak.selectAll("mylabels") .data(legend_keys) .enter() .append("text") - .attr("x", -20) - .attr("y", function(d,i){ return 140 - (i*22)}) + .attr("x", legend_label_x+20) + .attr("y", function(d,i){ return label_end - (i*label_space)}) .text(function(d){ return d}) .attr("text-anchor", "end") .style("alignment-baseline", "middle") + .style("font-weight", "600") + .attr("font-size", "16px") + // label percentile ranges in each category legend_peak.selectAll("percLabels") .data(perc_label) .enter() .append("text") - .attr("x", 20) - .attr("y", function(d,i){ return 145 - (i*23)}) + .attr("x", legend_label_x+60) + .attr("y", function(d,i){ return label_end - (i*label_space)}) .text(function(d){ return d}) .attr("text-anchor", "start") .style("alignment-baseline", "middle") + .attr("font-size", "16px") }, drawFrame1(map_svg, data){ @@ -692,7 +698,7 @@ $dark: #323333; padding-right: 2rem; margin: 1rem; width: 100%; - height: 98vh; + height: auto; vertical-align: middle; overflow: hidden; grid-template-areas: @@ -741,6 +747,7 @@ $dark: #323333; color:$dark; height: auto; padding: 4px; + padding-bottom: 0; } } @@ -773,7 +780,7 @@ $dark: #323333; #legend-container { display: flex; justify-content: flex-start; - padding-left: 50px; + padding-left: 20px; align-items: center; } #line-container { From d2056b89bfe7b30153ee5da014fa8ca58dc0be4c Mon Sep 17 00:00:00 2001 From: collnell Date: Sun, 31 Oct 2021 20:52:20 -0500 Subject: [PATCH 22/26] map scaling --- src/components/GWL.vue | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/GWL.vue b/src/components/GWL.vue index a093730..054c7c5 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -25,7 +25,7 @@

- Seitan 8-bit in, veniam pickled pitchfork hammock sustainable aliqua edison bulb. Four dollar toast man bun affogato crucifix locavore ut, labore quinoa gastropub qui reprehenderit adipisicing chicharrones asymmetrical. Live-edge squid banjo bespoke prism migas post-ironic tousled kitsch aute banh mi veniam ut kogi. Literally woke sriracha taxidermy freegan +1 voluptate church-key tempor cornhole humblebrag small batch fanny pack. + Four dollar toast man bun affogato crucifix locavore ut, labore quinoa gastropub qui reprehenderit adipisicing chicharrones asymmetrical. Live-edge squid banjo bespoke prism migas post-ironic tousled kitsch aute banh mi veniam ut kogi. Literally woke sriracha taxidermy freegan +1 voluptate church-key tempor cornhole humblebrag small batch fanny pack.

@@ -66,7 +66,7 @@ export default { day_length: 10, // frame duration in milliseconds current_time: 0, start: 0, - n_days: 365, + n_days: null, sites_list: null, //t2: null, isPlaying: null, @@ -572,7 +572,6 @@ export default { var legend_keys = ["Very low", "Low", "Normal", "High","Very high"]; // labels var perc_label = ["0.00 - 0.10", "0.10 - 0.25" ,"0.25 - 0.75", "0.75 - 0.90", "0.90 - 1.00"] // percentile ranges - // draw path shapes and labels var legend_title_x = 0; var legend_label_x = 56; @@ -648,7 +647,9 @@ export default { // draw the first frame of the animation const self = this; - // select existing paths using class + // select existing paths using class - currently all drawn with D3 + // to grab existing paths, needs to look exact same as first frame + // requries dealing with sites with no data on day 1 var start = this.start; this.peak_grp = map_svg.selectAll("path.gwl_glyph") .data(data, function(d) { return d ? d.key : this.class; }) // binds data based on class/key @@ -658,7 +659,7 @@ export default { // draws a path for each site, using the first date this.peak_grp .attr("class", function(d) { return d.key }) - .attr("fill", function(d) { return self.quant_color(d.gwl[0]) }) + .attr("fill", function(d) { return self.quant_color(d.gwl[start]) }) .attr("opacity", ".5") .attr("d", function(d) { return "M-10 0 C -10 0 0 " + d.gwl[start] + " 10 0 Z" } ) // d.gwl.# corresponds to day of wy, starting with 0 @@ -743,11 +744,11 @@ $dark: #323333; height: auto; grid-area: title; h1, h2, h3 { - // width: 95vw; color:$dark; height: auto; padding: 4px; padding-bottom: 0; + padding-left: 0; } } @@ -786,8 +787,12 @@ $dark: #323333; #line-container { grid-area: line; } -.map { +#map-container{ margin-top: 50px; + margin-right: 20px; + svg.map { + max-height: 1100px; + } } text-container { padding-left: 50px; From e2750ad8f28197cc3f0223ec672b2256b81e365f Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 1 Nov 2021 09:09:44 -0500 Subject: [PATCH 23/26] fix total calc --- 3_visualize/src/svg_utils_vue.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/3_visualize/src/svg_utils_vue.R b/3_visualize/src/svg_utils_vue.R index 04f5a05..09e112e 100644 --- a/3_visualize/src/svg_utils_vue.R +++ b/3_visualize/src/svg_utils_vue.R @@ -26,7 +26,9 @@ site_prop_timeseries <- function(file_out, gw_anomaly_data_w_colors){ filter(!is.na(quant_category)) %>% # filtering out dates with no category group_by(Date, day_seq, quant_category) %>% summarize(n_sites = length(unique(site_no))) %>% - left_join(gw_anomaly_data_w_colors %>% + # join with the total number of sites WITH DATA for each day + left_join(gw_anomaly_data_w_colors %>% + filter(!is.na(quant_category))%>% group_by(Date, day_seq) %>% summarize(n_sites_total = length(unique(site_no)))) %>% mutate(perc = n_sites/n_sites_total) %>% From a07ccd925b34bace20f3a8fe78aa0ada89d7f8b7 Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 1 Nov 2021 09:57:21 -0500 Subject: [PATCH 24/26] move and style play button --- src/components/GWL.vue | 113 +++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 054c7c5..5ec5d94 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -23,11 +23,12 @@
-
+ +
@@ -112,7 +113,7 @@ export default { self.d3.csv(self.publicPath + "quant_peaks.csv", this.d3.autotype), // used to draw legend shapes - color palette needs to be pulled out self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-wy2020.csv", this.d3.autotype), self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-site-coords.csv", this.d3.autotype), - self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-proportion.csv", this.d3.autotype), + self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-daily-proportions.csv", this.d3.autotype), self.d3.csv("https://labs.waterdata.usgs.gov/visualizations/data/gw-conditions-time-labels.csv", this.d3.autotype), ]; Promise.all(promises).then(self.callback); // once it's loaded @@ -143,7 +144,7 @@ export default { // annotations for the timeline // R pipeline pulls out each month and the year for time labels // TODO: incorporate additional event annotations - this.time_labels = data[4]; + var time_labels = data[4]; // days in sequence var day_seq = this.date_peaks.columns @@ -195,13 +196,15 @@ export default { // animated time chart var time_container = this.d3.select("#line-container"); this.drawLine(time_container, percData); - this.addButtons(time_container); + this.addButtons(time_container, time_labels); // control animation this.animateLine(this.start); this.animateGWL(this.start); - this.playButton(map_svg, this.width*(2.5/7) , 300); + var play_container = this.d3.select("#play-container"); + this.playButton(play_container, "200","50"); + }, createPanel(month) { var tl = new TimelineMax(); @@ -209,7 +212,7 @@ export default { // add rest of this return tl; }, - addButtons(time_container){ + addButtons(time_container, time_labels){ const self = this; // timeline events/"buttons" // want these to be buttons that rewind the animation to the date @@ -222,7 +225,7 @@ export default { // month points on timeline button_month.selectAll(".button_inner") - .data(this.time_labels).enter() + .data(time_labels).enter() .append("circle") .attr("class", function(d,i) { return "button_inner inner_" + d.month_label + "_" + d.year } ) .attr("r", 5) @@ -243,7 +246,7 @@ export default { // month labels button_month.selectAll(".button_name") - .data(this.time_labels) + .data(time_labels) .enter() .append("text") .attr("class", function(d,i) { return "button_name name_" + d.month_label + "_" + d.year } ) @@ -262,7 +265,7 @@ export default { }) */ // filter to just year annotations for first month they appear - var year_labels = this.time_labels.filter(function(el) { + var year_labels = time_labels.filter(function(el) { return el.year_label >= 2000; }); @@ -403,33 +406,49 @@ export default { }, playButton(svg, x, y) { const self = this; - - var button = svg.append("g") - button - .attr("transform", "translate("+ x +","+ y +")") + var svg_play = svg + .append("svg") + .attr("width", x) + .attr("height", y) + .attr("preserveAspectRatio", "xMinYMin meet") + .attr("viewbox", "0 0 " + x + " " + y) + + var button = svg_play.append("g") + .attr("transform", "translate("+ 0 +","+ 0 +")") .attr("class", "play_button"); button .append("rect") - .attr("width", 50) - .attr("height", 50) + .attr("width", 100) + .attr("height", 40) .attr("rx", 4) - .style("fill", "steelblue"); + .style("color", "black") + .style("fill","transparent") + .attr("stroke-width", "1px"); + + svg_play + .append("text") + .text("Play") + .attr("x", 42) + .attr("y", 30) + .attr("font-size", "1.5rem") + .attr("font-weight", "600") // append hover title button .append("title") - .text("replay animation") + .text("replay") button .append("path") - .attr("d", "M15 10 L15 40 L35 25 Z") - .style("fill", "white"); + .attr("d", "M7.5 7.5 L7.5 35 L32.5 20 Z") + .style("fill", "white") + .style("stroke", "black") + .attr("stroke-width", "2px"); button .on("mousedown", function() { - self.animateLine(0); - self.animateGWL(0); + self.pressButton(self.isPlaying) }); }, pressButton(playing) { @@ -437,7 +456,8 @@ export default { // trigger animation if animation is not already playing if (playing == false) { - self.animateChart_Map() + self.animateLine(0); + self.animateGWL(0); } }, resetPlayButton() { @@ -459,6 +479,12 @@ export default { // set indicator for play button self.isPlaying = true + // dim play button rectangle + let button_rect = this.d3.selectAll(".play_button").selectAll("rect") + button_rect + .style("fill", "#d6d6d6") + + if (start < this.n_days){ this.d3.selectAll(".hilite") .transition() @@ -732,6 +758,9 @@ $dark: #323333; grid-area: line; margin-bottom: 10px; } +#play-container { + grid-area: play; +} #legend-container { grid-area: legend; display: flex; @@ -765,6 +794,36 @@ $dark: #323333; } // desktop +@media (min-width:700px) { + #grid-container { + margin: 50px; + grid-template-columns: 2fr 5fr; + grid-template-areas: + "title map" + "legend map" + "play map" + "line line" + } + .title { + text-align: left; + } + #legend-container { + display: flex; + justify-content: flex-start; + padding-left: 20px; + align-items: center; + } + #line-container { + grid-area: line; +} +#map-container{ + margin-top: 50px; + margin-right: 20px; + svg.map { + max-height: 900px; + } +} +} @media (min-width:1024px) { #grid-container { margin: 50px; @@ -772,11 +831,13 @@ $dark: #323333; grid-template-areas: "title map" "legend map" - "text map" + "play map" "line line" } .title { text-align: left; + margin-bottom: 0; + padding-bottom: 0; } #legend-container { display: flex; @@ -794,8 +855,8 @@ $dark: #323333; max-height: 1100px; } } -text-container { - padding-left: 50px; +#play-container { + padding-left: 20px; } } // glyph paths From 4a529b5dbbca79625ddcb83cb1afe0282863ce93 Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 1 Nov 2021 18:14:13 -0500 Subject: [PATCH 25/26] consistent naming between r and s3 --- 3_visualize.yml | 4 ++-- src/App.vue | 15 ++++++++++----- src/components/GWL.vue | 25 ++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/3_visualize.yml b/3_visualize.yml index 276d560..8b2fda2 100644 --- a/3_visualize.yml +++ b/3_visualize.yml @@ -22,7 +22,7 @@ targets: - src/assets/anomaly_peaks.svg - public/gw-conditions-site-coords.csv ## this is in aws as gw-conditions-sites.csv - public/gw-conditions-wy20.csv ## in aws as gw-conditions-wy20.csv - - public/gw-conditions-daily-proportion.csv ## in aws as gw-conditions-daily-count.csv + - public/gw-conditions-daily-proportions.csv ## in aws as gw-conditions-daily-count.csv # exports that are leveraged by vue # TODO: send to s3 @@ -42,7 +42,7 @@ targets: target_name, sites_sf = gw_sites_sf) - public/gw-conditions-daily-proportion.csv: + public/gw-conditions-daily-proportions.csv: command: site_prop_timeseries(target_name, gw_anomaly_data_w_colors) diff --git a/src/App.vue b/src/App.vue index 80dad1c..01ba384 100644 --- a/src/App.vue +++ b/src/App.vue @@ -65,16 +65,22 @@ @import url('https://fonts.googleapis.com/css2?family=Assistant:wght@200;300;400;500;600;700;800&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap'); @import url("https://use.typekit.net/yww2frw.css"); +@import url('https://fonts.googleapis.com/css2?family=Copse&display=swap'); // sort of old timey +@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap'); $Cairo: 'Cairo', sans-serif; $Assistant: 'Assistant', sans-serif; $Noto: 'Noto Serif', serif; $acu_bold: 'acumin-pro', sans-serif; +$copse: 'Copse', serif; +$titillium: 'Titillium Wed', sans-serif; +$open_sans: 'Open Sans', sans-serif; html, body { height:100%; - background-color: rgb(237, 237, 237); + background-color: rgb(227, 227, 227); margin: 0; padding: 0; line-height: 1.2; @@ -97,7 +103,6 @@ h1{ font-family: $Assistant; line-height: 1; text-align: left; - text-shadow: 1px 1px 100px rgba(0,0,0,.8); @media screen and (max-width: 600px) { font-size: 2.5em; } @@ -109,7 +114,6 @@ h2{ font-size: 3em; margin-top: 5px; line-height: 1; - text-shadow: 10px 10px 100px rgba(20, 20, 20, 0.8); @media screen and (max-width: 600px) { font-size: 2em; } @@ -126,8 +130,9 @@ h3{ } p, text { padding: 1em 0 0 0; - font-family: $acu_bold; - line-height: 1.5; + font-family: $open_sans; + font-weight: 400; + line-height: 1.3; } diff --git a/src/components/GWL.vue b/src/components/GWL.vue index 5ec5d94..cf389aa 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -424,7 +424,8 @@ export default { .attr("rx", 4) .style("color", "black") .style("fill","transparent") - .attr("stroke-width", "1px"); + .attr("stroke-width", "1px") + .classed("pressMe", true); svg_play .append("text") @@ -446,7 +447,7 @@ export default { .style("stroke", "black") .attr("stroke-width", "2px"); - button + button.select("rect") .on("mousedown", function() { self.pressButton(self.isPlaying) }); @@ -468,7 +469,7 @@ export default { // undim button let button_rect = this.d3.selectAll(".play_button").selectAll("rect") - .style("fill", 'rgb(250,109,49)') + .style("fill", '#9b6adb8e') }, animateLine(start){ @@ -505,6 +506,13 @@ export default { .transition() .duration(this.day_length) .attr("x", self.xScale(this.days[this.n_days-1])) + + // once animation has completed, reset color of play button + // and set isPlaying to false + button_rect + .transition() + .delay(this.day_length*(this.n_days-1)) + .on("end", self.resetPlayButton); } }, buttonSelect(d){ @@ -847,6 +855,7 @@ $dark: #323333; } #line-container { grid-area: line; + padding-left: 20px; } #map-container{ margin-top: 50px; @@ -864,4 +873,14 @@ $dark: #323333; stroke: none; fill-opacity: 50%; } +.pressMe:active { + background-color: #9b6adb8e; + box-shadow: 0 5px #666; + transform: translateY(4px); +} +.pressMe:hover { + background-color: #b996e78e; + box-shadow: 0 1px #666; + transform: translateY(1px); +} \ No newline at end of file From b951de97b7555572b99c92b6b9d0f7ddec147cb3 Mon Sep 17 00:00:00 2001 From: collnell Date: Mon, 1 Nov 2021 18:29:49 -0500 Subject: [PATCH 26/26] fix laptop scaling --- src/assets/anomaly_peaks.svg | 2 +- src/components/GWL.vue | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/assets/anomaly_peaks.svg b/src/assets/anomaly_peaks.svg index 410100e..caec7d8 100644 --- a/src/assets/anomaly_peaks.svg +++ b/src/assets/anomaly_peaks.svg @@ -1,5 +1,5 @@ - + diff --git a/src/components/GWL.vue b/src/components/GWL.vue index cf389aa..873b402 100644 --- a/src/components/GWL.vue +++ b/src/components/GWL.vue @@ -614,7 +614,7 @@ export default { .text("Groundwater levels") .attr("x", legend_title_x) .attr("y", "20") - .style("font-size", "20") + .style("font-size", "1.5rem") .style("font-weight", 600) // matching css of .axis_labels .attr("text-anchor", "start") @@ -623,7 +623,7 @@ export default { .text("Percentile based on historic") .attr("x", legend_title_x) .attr("y", "40") - .style("font-size", "16px") + .style("font-size", "1rem") .style("font-weight", 400) .attr("text-anchor", "start") @@ -632,7 +632,7 @@ export default { .text("daily record at each site") .attr("x", legend_title_x) .attr("y", "60") - .style("font-size", "16px") + .style("font-size", "1rem") .style("font-weight", 400) .attr("text-anchor", "start") @@ -858,10 +858,11 @@ $dark: #323333; padding-left: 20px; } #map-container{ - margin-top: 50px; + margin-top: 0px; + margin-bottom: 0px; margin-right: 20px; svg.map { - max-height: 1100px; + max-height: 75vh; } } #play-container { @@ -883,4 +884,8 @@ $dark: #323333; box-shadow: 0 1px #666; transform: translateY(1px); } +text.tick { + font-size: 1rem; + +} \ No newline at end of file