### Download example count matrix from Zenodo Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Downloads the GEUVADIS_GBR20 gene counts matrix from Zenodo. This is a prerequisite for running qcnorm with the example data. ```bash wget https://zenodo.org/record/6631875/files/GEUVADIS_GBR20_gene_counts.tsv.gz ``` -------------------------------- ### WebGL cone rendering setup (JavaScript) Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/Young_2019_QC_report.html Initializes WebGL buffers and shaders for cone rendering. Uses gl-buffer, gl-shader, gl-texture2d, and gl-vao modules. Sets up mesh and pick shaders with specific attribute locations. ```javascript s=r.shaders;1===arguments.length&&(t=(e=t).gl);var l=function(t,e){var r=n(t,e.meshShader.vertex,e.meshShader.fragment,null,e.meshShader.attributes);return r.attributes.position.location=0,r.attributes.color.location=2,r.attributes.uv.location=3,r.attributes.vector.location=4,r}(t,s),u=function(t,e){var r=n(t,e.pickShader.vertex,e.pickShader.fragment,null,e.pickShader.attributes);return r.attributes.position.location=0,r.attributes.id.location=1,r.attributes.vector.location=4,r}(t,s),h=o(t,c(new Uint8Array([255,255,255,255]),[1,1,4]));h.generateMipmap(),h.minFilter=t.LINEAR_MIPMAP_LINEAR,h.magFilter=t.LINEAR;var p=a(t),d=a(t),g=a(t),v=a(t),m=a(t),y=new f(t,h,l,u,p,d,m,g,v,i(t,[{buffer:p,type:t.FLOAT,size:4},{buffer:m,type:t.UNSIGNED_BYTE,size:4,normalized:!0},{buffer:g,type:t.FLOAT,size:4},{buffer:v,type:t.FLOAT,size:2},{buffer:d,type:t.FLOAT,size:4}]),r.traceType||"cone");return y.update(e),y} ``` -------------------------------- ### Load libraries and eQTLUtils package Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/manuscript/figures/median_TPM_MDS/MDS_median_tpm.Rmd R setup chunk that loads required packages and the local eQTLUtils development package to enable utilities for the downstream analysis. ```R library("dplyr") library("ggplot2") library("readr") library("stringr") library("devtools") library("data.table") load_all("../../../../eQTLUtils/") library("RColorBrewer") ``` -------------------------------- ### Download example raw genotype data (CEDAR) from Zenodo Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Downloads and extracts the CEDAR raw genotype data (HumanOmniExpress-12v1) from Zenodo. The workflow expects PLINK binary format (.bed/.bim/.fam) with GRCh37 coordinates. ```bash wget https://zenodo.org/record/6171348/files/CEDAR_HumanOmniExpress-12v1.tar.gz tar -xzvf CEDAR_HumanOmniExpress-12v1.tar.gz ``` -------------------------------- ### WebGL rendering and camera setup (minified JavaScript) Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/Young_2019_QC_report.html Minified JavaScript from plotly.js that sets up the WebGL camera, handles rendering of point clouds and axes, and manages framebuffer operations. It includes shader code for point rendering and picking. ```javascript T=y.drawingBufferWidth,M=y.drawingBufferHeight;B[0]=T,B[1]=M,V[0]=0|Math.max(T/j.pixelRatio,1),V[1]=0|Math.max(M/j.pixelRatio,1),function(t,e){var r=t.bounds,n=t.cameraParams,a=n.projection,i=n.model,o=t.gl.drawingBufferWidth,s=t.gl.drawingBufferHeight,l=t.zNear,c=t.zFar,u=t.fovy,p=o/s;e?(f(a,-p,p,-1,1,l,c),n._ortho=!0):(h(a,u,p,l,c),n._ortho=!1);for(var d=0;d<16;++d)i[d]=0;i[15]=1;for(var g=0,d=0;d<3;++d)g=Math.max(g,r[1][d]-r[0][d]);for(var d=0;d<3;++d)t.autoScale?i[5*d]=t.aspect[d]/(r[1][d]-r[0][d]):i[5*d]=1/g,t.autoCenter&&(i[12+d]=.5*-i[5*d]*(r[0][d]+r[1][d]))}(j,k);for(var a=0;a 1.0) {\n discard;\n }\n baseColor = mix(borderColor, color, step(radius, centerFraction));\n gl_FragColor = vec4(baseColor.rgb * baseColor.a, baseColor.a);\n }\n}"]) ``` -------------------------------- ### Download sample metadata for CEDAR Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Download the sample metadata file for the CEDAR dataset from Zenodo. ```bash wget https://zenodo.org/record/6171348/files/CEDAR_sample_metadata.tsv ``` -------------------------------- ### Run rnaseq workflow: paired-end, stranded Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Run the workflow with paired-end stranded data. Note: this example completes but ignores ~50% of reads because the GEUVADIS dataset is unstranded. ```bash nextflow run main.nf\ -profile tartu_hpc\ -resume \ --readPathsFile data/read_paths_GEUVADIS_GBR20.tsv\ --reverse_stranded\ --run_mbv\ --mbv_vcf GEUVADIS_GBR20.vcf.gz ``` -------------------------------- ### Bootstrap Popover Component Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/GEUVADIS_QC_report.html Defines the popover plugin, extending tooltip with content and title. Includes methods for setting content, getting content, and handling arrow positioning. ```JavaScript +function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery) ``` -------------------------------- ### Download qcnorm workflow from GitHub Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Clones the eQTL-Catalogue/qcnorm repository and changes into the qcnorm directory. ```bash git clone https://github.com/eQTL-Catalogue/qcnorm.git cd qcnorm ``` -------------------------------- ### Run qcnorm workflow with all quantification methods Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Runs the qcnorm workflow without skipping any normalisation steps, including all quantification methods. Requires absolute paths for VCF, quantification results, and sample metadata. ```bash nextflow run main.nf -profile tartu_hpc \ -resume\ --study_name GEUVADIS_GBR20\ --vcf_file //GEUVADIS_GBR20.vcf.gz\ --quant_results_path //rnaseq/results\ --sample_meta_path //GEUVADIS_GBR20_sample_metadata.tsv\ --outdir //GEUVADIS_GBR20_qcnorm ``` -------------------------------- ### Sort missingness file to find high-missingness samples Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/plink_check.md Sorts the .imiss file by the 6th column (missingness rate) and shows the top 10 rows. In this example, five samples have more than 5% missing genotypes and should be removed. ```bash (base) [a72094@rocket plink_raw]$ sort -k6n plink.imiss | tail -n 10 565 566 Y 17028 759993 0.02241 553 554 Y 19595 759993 0.02578 241 242 Y 22634 752646 0.03007 155 155 Y 22967 759993 0.03022 1086 155_2 Y 24584 759993 0.03235 931 932 Y 43064 752646 0.05722 919 920 Y 45395 752646 0.06031 913 914 Y 73313 752646 0.09741 925 926 Y 90780 752646 0.1206 844 845 Y 176952 752646 0.2351 ``` -------------------------------- ### Download sample metadata file for GEUVADIS_GBR20 Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Downloads the GEUVADIS_GBR20 sample metadata TSV from Zenodo. ```bash wget https://zenodo.org/record/6391156/files/GEUVADIS_GBR20_sample_metadata.tsv ``` -------------------------------- ### Create input data directory Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Create a new directory for input data and change into it before downloading the required files. ```bash mkdir data cd data ``` -------------------------------- ### JavaScript renderer constructor and shader setup Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/Young_2019_QC_report.html Minified JavaScript code that defines the renderer object constructor, initializes shader programs, and sets up attribute locations for mesh, wire, point, pick, and contour shaders. ```javascript function k(t,e,r,n,a,i,o,s,l,c,u,h,f,p,d,g,v,m,y,x,b,_,k,T,M,A,S){this.gl=t,this.pixelRatio=1,this.cells=[],this.positions=[],this.intensity=[],this.texture=e,this.dirty=!0,this.triShader=r,this.lineShader=n,this.pointShader=a,this.pickShader=i,this.pointPickShader=o,this.contourShader=s,this.trianglePositions=l,this.triangleColors=u,this.triangleNormals=f,this.triangleUVs=h,this.triangleIds=c,this.triangleVAO=p,this.triangleCount=0,this.lineWidth=1,this.edgePositions=d,this.edgeColors=v,this.edgeUVs=m,this.edgeIds=g,this.edgeVAO=y,this.edgeCount=0,this.pointPositions=x,this.pointColors=_,this.pointUVs=k,this.pointSizes=T,this.pointIds=b,this.pointVAO=M,this.pointCount=0,this.contourLineWidth=1,this.contourPositions=A,this.contourVAO=S,this.contourCount=0,this.contourColor=[0,0,0],this.contourEnable=!0,this.pickVertex=!0,this.pickId=1,this.bounds=[[1/0,1/0,1/0],[-1/0,-1/0,-1/0]],this.clipBounds=[[-1/0,-1/0,-1/0],[1/0,1/0,1/0]],this.lightPosition=[1e5,1e5,0],this.ambientLight=.8,this.diffuseLight=.8,this.specularLight=2,this.roughness=.5,this.fresnel=1.5,this.opacity=1,this.hasAlpha=!1,this.opacityscale=!1,this._model=w,this._view=w,this._projection=w,this._resolution=[1,1]}var T=k.prototype;function M(t,e){if(!e)return 1;if(!e.length)return 1;for(var r=0;rt&&r>0){var n=(e[r][0]-t)/(e[r][0]-e[r-1][0]);return e[r][1]*(1-n)+n*e[r-1][1]}}return 1}function A(t){var e=n(t,y.vertex,y.fragment);return e.attributes.position.location=0,e.attributes.color.location=2,e.attributes.uv.location=3,e.attributes.pointSize.location=4,e}function S(t){var e=n(t,x.vertex,x.fragment);return e.attributes.position.location=0,e.attributes.id.location=1,e}function E(t){var e=n(t,b.vertex,b.fragment);return e.attributes.position.location=0,e.attributes.id.location=1,e.attributes.pointSize.location=4,e}function L(t){var e=n(t,_.vertex,_.fragment);return e.attributes.position.location=0,e}T.isOpaque=function(){return!this.hasAlpha},T.isTransparent=function(){return this.hasAlpha},T.pickSlots=1,T.setPickBase=function(t){this.pickId=t},T.highlight=function(t){if(t&&this.contourEnable){for(var e=f(this.cells,this.intensity,t.intensity),r=e.cells,n=e.vertexIds,a=e.vertexWeights,i=r.length,o=p.mallocFloat32(6*i),s=0,l=0;l0){for(var w=0;w<24;++w)a.push(a[a.length-12]);u+=2,v=!0}continue t}h[r]=Math.min(h[r],b[r],_[r]),h[r]=Math.max(h[r],b[r],_[r])}Array.isArray(d[0])?(m=d.length>e-1?d[e-1]:d.length>0?d[d.len gth-1]:[0,0,0,1],y=d.length>e?d[e]:d.length>0?d[d.length-1]:[0,0,0,1]):m=y=d,3===m.length&&(m=[m[0],m[1],m[2],1]),3===y.length&&(y=[y[0],y[1],y[2],1]),!this.hasAlpha&&m[3]<1&&(this.hasAlpha=!0),x=Array.isArray(g)? […] 2],c,x,y[0],y[1],y[2],y[3]),u+=4}}if(this.buffer.update(a),i.push(c),o.push(f[f.length-1].slice()),this.bounds=h,this.vertexCount=u,this.points=o,this.arcLength=i,"dashes"in t){var ``` -------------------------------- ### Run qcnorm workflow with Nextflow (skipping normalisation steps) Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Runs the qcnorm workflow with the tartu_hpc profile, skipping exon, transcript, transcript-reverse, and leafcutter normalisation. Requires absolute paths for VCF, quantification results, and sample metadata. ```bash nextflow run main.nf -profile tartu_hpc \ -resume\ --study_name GEUVADIS_GBR20\ --vcf_file //GEUVADIS_GBR20.vcf.gz\ --quant_results_path //rnaseq/results\ --sample_meta_path //GEUVADIS_GBR20_sample_metadata.tsv\ --skip_exon_norm true\ --skip_tx_norm true\ --skip_txrev_norm true\ --skip_leafcutter_norm true\ --outdir //GEUVADIS_GBR20_qcnorm ``` -------------------------------- ### 3D cube rendering with gl-buffer and gl-vao Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/Young_2019_QC_report.html Initializes a cube mesh with position and normal attributes, sets up a VAO, and draws the cube with polygon offset. Used for 3D visualization in the QC report. ```javascript m=n(t,new Float32Array(e)),y=n(t,new Uint16Array(r),t.ELEMENT_ARRAY_BUFFER),x=a(t,[{buffer:m,type:t.FLOAT,size:3,offset:0,stride:24},{buffer:m,type:t.FLOAT,size:3,offset:12,stride:24}],y),b=i(t);return b.attributes.position.location=0,b.attributes.normal.location=1,new o(t,m,x,b)};var n=t("gl-buffer"),a=t("gl-vao"),i=t("./shaders").bg;function o(t,e,r,n){this.gl=t,this.buffer=e,this.vao=r,this.shader=n}var s=o.prototype;s.draw=function(t,e,r,n,a,i){for(var o=!1,s=0;s<3;++s)o=o||a[s];if(o){var l=this.gl;l.enable(l.POLYGON_OFFSET_FILL),l.polygonOffset(1,2),this.shader.bind(),this.shader.uniforms={model:t,view:e,projection:r,bounds:n,enable: a,colors:i},this.vao.bind(),this.vao.draw(this.gl.TRIANGLES,36),this.vao.unbind(),l.disable(l.POLYGON_OFFSET_FILL)}},s.dispose=function(){this.vao.dispose(),this.buffer.dispose(),this.shader.dispose()}} ``` -------------------------------- ### GLSL Vertex Shader for Line Rendering with Miter Joins Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/Young_2019_QC_report.html Vertex shader code that computes line positions, miter cutoffs, and passes varying data to the fragment shader. It handles start and end miter joins with configurable thickness and scale. ```glsl precision highp float; #define GLSLIFY 1 uniform sampler2D dashPattern; uniform float dashSize, pixelRatio, thickness, opacity, id, miterMode; varying vec4 fragColor; varying vec2 tangent; varying vec4 startCutoff, endCutoff; varying vec2 startCoord, endCoord; varying float enableStartMiter, enableEndMiter; float distToLine(vec2 p, vec2 a, vec2 b) { vec2 diff = b - a; vec2 perp = normalize(vec2(-diff.y, diff.x)); return dot(p - a, perp); } void main() { float alpha = 1., distToStart, distToEnd; float cutoff = thickness * .5; //bevel miter if (miterMode == 1.) { if (enableStartMiter == 1.) { distToStart = distToLine(gl_FragCoord.xy, startCutoff.xy, startCutoff.zw); if (distToStart < -1.) { discard; return; } alpha *= min(max(distToStart + 1., 0.), 1.); } if (enableEndMiter == 1.) { distToEnd = distToLine(gl_FragCoord.xy, endCutoff.xy, endCutoff.zw); if (distToEnd < -1.) { discard; return; } alpha *= min(max(distToEnd + 1., 0.), 1.); } } // round miter else if (miterMode == 2.) { if (enableStartMiter == 1.) { distToStart = distToLine(gl_FragCoord.xy, startCutoff.xy, startCutoff.zw); if (distToStart < 0.) { float radius = length(gl_FragCoord.xy - startCoord); if(radius > cutoff + .5) { discard; return; } alpha -= smoothstep(cutoff - .5, cutoff + .5, radius); } } if (enableEndMiter == 1.) { distToEnd = distToLine(gl_FragCoord.xy, endCutoff.xy, endCutoff.zw); if (distToEnd < 0.) { float radius = length(gl_FragCoord.xy - endCoord); if(radius > cutoff + .5) { discard; return; } alpha -= smoothstep(cutoff - .5, cutoff + .5, radius); } } } float t = fract(dot(tangent, gl_FragCoord.xy) / dashSize) * .5 + .25; float dash = texture2D(dashPattern, vec2(t, .5)).r; gl_FragColor = fragColor; gl_FragColor.a *= alpha * opacity * dash; } ``` -------------------------------- ### View modified .fam file with character IDs Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/plink_check.md Shows the first five lines of a .fam file after changing sample IDs to start with a character (e.g., OneK1K_1) and setting family ID to 0, which is recommended to avoid downstream issues in R. ```bash (base) [a72094@rocket plink_raw]$ head -n5 OneK1K_nonmissing.fam 0 OneK1K_1 0 0 2 -9 0 OneK1K_2 0 0 2 -9 0 OneK1K_3 0 0 2 -9 0 OneK1K_4 0 0 2 -9 0 OneK1K_5 0 0 2 -9 ``` -------------------------------- ### Clone the qtlmap workflow from GitHub Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/tutorials/workflow_execution.md Clone the eQTL-Catalogue/qtlmap repository and change into its directory to prepare for running the workflow. ```bash git clone https://github.com/eQTL-Catalogue/qtlmap.git cd qtlmap ``` -------------------------------- ### Error bar rendering with regl (minified) Source: https://github.com/eqtl-catalogue/eqtl-catalogue-resources/blob/master/QC_reports/Young_2019_QC_report.html Minified JavaScript code that sets up a regl draw command for error bars, including shader setup, buffer creation, and attribute configuration. It uses the ANGLE_instanced_arrays extension and defines a vertex shader for projecting coordinates. ```javascript Array.isArray(t)?e={x:t[0],y:t[1],width:t[2]-t[0],height:t[3]-t[1]}:t?(e={x:t.x||t.left||0,y:t.y||t.top||0},t.right?e.width=t.right-e.x:e.width=t.w||t.width||0,t.bottom?e.height=t.bottom-e.y:e.height=t.h||t.height||0):e={x:0,y:0,width:m.drawingBufferWidth,height:m.drawingBufferHeight},e}}]),u):u}),e||r){var f=x.reduce(function(t,e,r){return t+(e?e.count:0)},0),v=new Float64Array(2*f),_=new Uint8Array(4*f),w=new Float32Array(4*f);x.forEach(function(t,e){if(t){var r=t.positions,n=t.count,a=t.offset,i=t.color,o=t.errors;n&&(_.set(i,4*a),w.set(o,4*a),v.set(r,2*a))}}),c(u(v)),p(h(v)),d(_),g(w)}}}function T(){c.destroy(),p.destroy(),d.destroy(),g.destroy(),v.destroy()}};var f=[[1,0,0,1,0,0],[1,0,0,-1,0,0],[-1,0,0,-1,0,0],[-1,0,0,-1,0,0],[-1,0,0,1,0,0],[1,0,0,1,0,0],[1,0,-1,0,0,1],[1,0,-1,0,0,-1],[1,0,1,0,0,-1],[1,0,1,0,0,-1],[1,0,1,0,0,1],[1,0,-1,0,0,1],[-1,0,-1,0,0,1],[-1,0,-1,0,0,-1],[-1,0,1,0,0,-1],[-1,0,1,0,0,-1],[-1,0,1,0,0,1],[-1,0,-1,0,0,1],[0,1,1,0,0,0],[0,1,-1,0,0,0],[0,-1,-1,0,0,0],[0,-1,-1,0,0,0],[0,1,1,0,0,0],[0,-1,1,0,0,0],[0,1,0,-1,1,0],[0,1,0,-1,-1,0],[0,1,0,1,-1,0],[0,1,0,1,1,0],[0,1,0,-1,1,0],[0,1,0,1,-1,0],[0,-1,0,-1,1,0],[0,-1,0,-1,-1,0],[0,-1,0,1,-1,0],[0,-1,0,1,1,0],[0,-1,0,-1,1,0],[0,-1,0,1,-1,0]] ``` ```javascript {"use strict";var n=t("color-normalize"),a=t("array-bounds"),i=t("object-assign"),o=t("glslify"),s=t("pick-by-alias"),l=t("flatten-vertex-data"),c=t("earcut"),u=t("array-normalize"),h=t("to-float32"),f=h.float32,p=h.fract32,d=t("es6-weak-map"),g=t("parse-rect");function v(t,e){if(!(this instanceof v))return new v(t,e);if("function"==typeof t?(e||(e={}),e.regl=t):e=t,e.length&&(e.positions=e),!(t=e.regl).hasExtension("ANGLE_instanced_arrays"))throw Error("regl-error2d: `ANGLE_instanced_arrays` extension should be enabled");this.gl=t._gl,this.regl=t,this.passes=[],this.shaders=v.shaders.has(t)?v.shaders.get(t):v.shaders.set(t,v.createShaders(t)).get(t),this.update(e)}e.exports=v,v.dashMult=2,v.maxPatternLength=256,v.precisionThreshold=3e6,v.maxPoints=1e4,v.maxLines=2048,v.shaders=new d,v.createShaders=function(t){var e,r=t.buffer({usage:"static",type:"float",data:[0,1,0,0,1,1,1,0]}),n={primitive:"triangle strip",instances:t.prop("count"),count:4,offset:0,uniforms:{miterMode:function(t,e){return"round"===e.join?2:1},miterLimit:t.prop("miterLimit"),scale:t.prop("scale"),scaleFract:t.prop("scaleFract"),translateFract:t.prop("translateFract"),translate:t.prop("translate"),thickness:t.prop("thickness"),dashPattern:t.prop("dashTexture"),opacity:t.prop("opacity"),pixelRatio:t.context("pixelRatio"),id:t.prop("id"),dashSize:t.prop("dashLength"),viewport:function(t,e){return[e.viewport.x,e.viewport.y,t.viewportWidth,t.viewportHeight]},depth:t.prop("depth")},blend:{enable:!0,color:[0,0,0,0],equation:{rgb:"add",alpha:"add"},func:{srcRGB:"src alpha",dstRGB:"one minus src alpha",srcAlpha:"one minus dst alpha",dstAlpha:"one"}},depth:{enable:function(t,e){return!e.overlay}},stencil:{enable:!1},scissor:{enable:!0,box:t.prop("viewport")},viewport:t.prop("viewport")},a=t(i({vert:o(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 aCoord, bCoord, aCoordFract, bCoordFract;\nattribute vec4 color;\nattribute float lineEnd, lineTop;\n\nuniform vec2 scale, scaleFract, translate, translateFract;\nuniform float thickness, pixelRatio, id, depth;\nuniform vec4 viewport;\n\nvarying vec4 fragColor;\nvarying vec2 tangent;\n\nvec2 project(vec2 position, vec2 positionFract, vec2 scale, vec2 scaleFract, vec2 translate, vec2 translateFract) {\n\t// the order is important\n\treturn position * scale + translate\n + positionFract * scale + translateFract\n + position * scaleFract\n + positionFract * scaleFract;\n}\n\nvoid main() {\n\tfloat lineStart = 1. - lineEnd;\n\tfloat lineOffset = lineTop * 2. ```