From d74f38d481df5db71aa8818f0baf830dc87c96df Mon Sep 17 00:00:00 2001 From: djwh1tmer Date: Fri, 23 Jan 2026 15:57:32 -0500 Subject: [PATCH 1/5] David Whitmer Test --- .DS_Store | Bin 0 -> 8196 bytes presentations/David Whitmer Test.Rmd | 20 ++++++++++++++++++ .../{test123.html => David Whitmer.html} | 4 ++-- .../libs/header-attrs-2.30/header-attrs.js | 12 +++++++++++ presentations/test123.Rmd | 12 ++--------- 5 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 .DS_Store create mode 100644 presentations/David Whitmer Test.Rmd rename presentations/{test123.html => David Whitmer.html} (98%) create mode 100644 presentations/libs/header-attrs-2.30/header-attrs.js diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4817afa9642f285a1da5fc623340ee356dca7670 GIT binary patch literal 8196 zcmeHMU2GIp6u#fI$jm_L?eJGNKvtTxNDD4dDg^@DKd>pL$o7u{uDd$}OqkBpo!Ko& zh*jeYs8L^hQ2cu}8hy|xM&g@1nTQ)B{wF5B;Da&hlZl=?cNSd!qA!Nv+~nRf=bm%! z%sKZv_x5ZVW9TiJ>ltfijH%QG<@0E`P7`v`uW3p&Q%@9R&zQwr7O)(3`x@J9FFDUHWC0&xWXmk|)>Lz23n>4?rs8Xg@qge3q`Q38aG zo~aH9ZITg9M|4)w(3IAc)dM0^L?s5KImwekooG6uvyw`425HU^y%|x3g7EERmkiYz z(vrqw9Dz6j*G533PXn7~MXKHXn)=fskv4>f(BF*-J`XSq=(H-@JJ+jIRftLPKW@;|0$tO}T!SHx+VDq2%NOtH*IN_QRGx5m?6p@iggs#h@=#oUqAO%w;(* z`PN>G4D7PiPiFq2S}z#1H|H;2v8uH_wQ0-tzFoWbR2mjEa@| znznm*bjCJ=Ba;+MH?R-cR#8)%&@tlXrmPBIvb1?w!Z4)H6`SfR6Q#WUP{|IC^A=UD z@CA(xD~+Unz@%@w&ojkprpn*ZLP?8}H1-QgU(uq`j11b0yYvyC+){Z?Dt74W^pT^q z*&6rd%zAyJG3w;by>Y&AY4C%5VgjfsLcHASxYnw;BV^cW9_*Y3{w z!SJ-@icdOEGIFgyX&C#2tj9FN4{BbrlpBM_kjgKplm3xh(Hfp16jq}7VO0(Hk>3(gk5A`vai^;><9J}`-T01dNiOB98E}|4Xd#R?dU`rJ?O;{_TYYGFoJ`~ zqW}ws;Gu*vj^Q{S!zrA`Q+OKB;}yJ$*YG;d;sbn$bNCpa;sQRy*Z2nC;d@-dulNnW zE2`3@7|KGWRcTXF$|hyI{BWh3I{Rudr|cm9=BX1M4vKTV)JY8N+;wZD&c*p6S(+$W z7O!ksy>>&_)*Y8YB~e%f-rwOIVz>tRA%??UzY2eqFstWS2PjnawNMQr;fVj&s5dy7Vi#p^4} zmNqZhmRPQHrfShLy?wOId9MC@)V|HmvX2P06+-Qg>=OH#{Rx$@nm`h*AzIt97G1ap zo3RDkFo2!dg+apY2u3l62}}}dO~UPA*eJqBK-hf*vv?Gb;|W6UGk6xy;RU>iGk7_| z@LPEQDpU^Eq7r9sj>>YT=sKQzn6#?6u3aGJq6pMU+AQk-fgAt+AIB?>KpcVFI0C5e z&-C|_gEu-aMXjBr{vdVHgx;*Ap$QE_Ma+lgIMK`hFr?>XBuhthR#K8s`_F#}i0^+< R2mFJ-TI2ga1n6x#`~?@JJD>mn literal 0 HcmV?d00001 diff --git a/presentations/David Whitmer Test.Rmd b/presentations/David Whitmer Test.Rmd new file mode 100644 index 0000000..97802d7 --- /dev/null +++ b/presentations/David Whitmer Test.Rmd @@ -0,0 +1,20 @@ +--- +title: "My presentation" +subtitle: "⚔
with xaringan" +author: "David Whitmer" +institute: "RStudio, PBC" +date: "2016/12/12 (updated: `r Sys.Date()`)" +output: + xaringan::moon_reader: + css: xaringan-themer.css + lib_dir: libs + nature: + highlightStyle: github + highlightLines: true + countIncrementalSlides: false +--- + + + + +# This is a test presentation! diff --git a/presentations/test123.html b/presentations/David Whitmer.html similarity index 98% rename from presentations/test123.html rename to presentations/David Whitmer.html index 41fee02..a431152 100644 --- a/presentations/test123.html +++ b/presentations/David Whitmer.html @@ -3,7 +3,7 @@ My presentation - + @@ -18,7 +18,7 @@ ## ⚔
with xaringan ] .author[ -### Eren Bilen +### David Whitmer ] .institute[ ### RStudio, PBC diff --git a/presentations/libs/header-attrs-2.30/header-attrs.js b/presentations/libs/header-attrs-2.30/header-attrs.js new file mode 100644 index 0000000..dd57d92 --- /dev/null +++ b/presentations/libs/header-attrs-2.30/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/presentations/test123.Rmd b/presentations/test123.Rmd index 1cdb3e7..97802d7 100644 --- a/presentations/test123.Rmd +++ b/presentations/test123.Rmd @@ -1,7 +1,7 @@ --- title: "My presentation" subtitle: "⚔
with xaringan" -author: "Eren Bilen" +author: "David Whitmer" institute: "RStudio, PBC" date: "2016/12/12 (updated: `r Sys.Date()`)" output: @@ -14,15 +14,7 @@ output: countIncrementalSlides: false --- -```{r xaringan-themer, include=FALSE, warning=FALSE} -library(xaringanthemer) -style_mono_accent( - base_color = "#1c5253", - header_font_google = google_font("Josefin Sans"), - text_font_google = google_font("Montserrat", "300", "300i"), - code_font_google = google_font("Fira Mono") -) -``` + # This is a test presentation! From bd71ecbfcee3e51a47f827bd531bef8ac515b7ad Mon Sep 17 00:00:00 2001 From: djwh1tmer Date: Thu, 29 Jan 2026 18:28:12 -0500 Subject: [PATCH 2/5] Push --- .DS_Store | Bin 8196 -> 8196 bytes ... Whitmer Mini Project Proposal Idea. .docx | Bin 0 -> 15574 bytes presentations/.DS_Store | Bin 0 -> 6148 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 David Whitmer Mini Project Proposal Idea. .docx create mode 100644 presentations/.DS_Store diff --git a/.DS_Store b/.DS_Store index 4817afa9642f285a1da5fc623340ee356dca7670..b36f6fe200cb747d5c8867ffb09f4e19b83c4b76 100644 GIT binary patch literal 8196 zcmeHMTWl0n7(U;$rDvuTrfY!~SzN3lr3ET2NJZ)Pf|Q$8TG~=B>+a4#CroFSo!Ko& zh*i-CHELpvnkdnzkK!#FV>FRBBED!EA}^9?;)9~`!NkND{m-0Pa0P1OgCRI4Ip?4A zU*^pD=KJUL-!jI~Q!s94tbsAcsSBys&~Sw&?4n=Rlu%Pe5){vv$sFdhG&8p_r zyoT=`9Cs%N{j^{3deZsbVm9QucBXWl&J0`TWJ<5^bsax#Ic7cxund!2_KaAL;ZF9r z1;_A$*g?T_O^~=t%;+ZtJ_)=9qnt69aH(drd8{Aqz>8>j{Ah% z6v7V!?WVjvNz)m2Xn0vWLr*NiXK=HJ(u_EnuAm>}I z;|-g6k7P=p>k%rOv#xVr-W2wctZNr0951EUWz%-HV5fbv+qMU-2TgC(HxK*bYRq%< zesAD7YEi7vrF6aEnLA7hu!?3Mg?aVmn`KZ>&Yl;)d1*`AnmfDt`nTUdT{~y4UKhJT z8zX2P-`a1P`CVx*YdVJI9N0N&8UFZ4(ekW}Z4No<36s~MOP!v-prJOlFt(^vQJTYO%x;mFpkuG3dFryM|cF2rRK!;#SUg3w>|iq*1E1So3lU zNDq0mHF*nd;Bs!$D%IxNJEScJuB zK?l}gEqbsO+prx27{XrcLkel^hl?Bz!NUXqA+WlFQMTxnO+_Kt}B#!a=J3!rs)-w zSV0yyw#QpE9b8WC&^k4}l2S~aZX~*E@eN(7NO+wE>vYF^Wj>m|;&)``+hv#tuui`bljyD1#zmHG;M$Ikd)WoMVQ?odjcWl==Kwc$s zm*3!eomI$}AX}6$P@9ts0{J(GJ`)2<0n`oYBp6rI} zZqKwEF8ix*slAGRT$nJ^t?@)MPDqi*4tW+AMf#$4)H9iBYVFw3lPy`~rYiH6M$_En z@q|7QGlz6Tj{Nw&Y+;Wkww#b%H&Bypra{zT=zGRitxmrS3@gXTyqrFS1T z^i;Nx@0R8L)Sb`gy0vNCO3oE~b4ALHG`C`wI99I+<1pebe-fNX z1`4qdq)?8o6@siWhb$=(A4_o43Itw2Dss)6Uo0!?0)Jb3hkdE^GD3D>aWpf_#vfW7 zdLrUM^&_$(;G)IZJXq?o<+6BCI(&bi zN2r@ND*_hk%2rgAmHW2(m#CD;N}3a;WBt{2|n4jwoT q&KcYJx3MllFm>;%uM8KCH{L5Q|LH2Os$IP%xaGfp4#)rCU&C*pY%PfZ diff --git a/David Whitmer Mini Project Proposal Idea. .docx b/David Whitmer Mini Project Proposal Idea. .docx new file mode 100644 index 0000000000000000000000000000000000000000..5caa646d7a76e62280309086902db485b2357ffc GIT binary patch literal 15574 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 Ee`EXp`Tzg` literal 0 HcmV?d00001 diff --git a/presentations/.DS_Store b/presentations/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2851ba4fdf2a134f8fc97fd60b3045b73cd6039b GIT binary patch literal 6148 zcmeH~F^wCzS%D5ne-@9Kng5F0slS}y0a!*XM8#sVgw)umczJ?S%NHHAZxO9vO=?*9xPie z#t^SZJ6ZC&nrxlD9hSp~<(h|QedXQy62;x|6laq=KooXQYjz> z{+R+coX)2sUnquNP$09 F;0?Mr60ZON literal 0 HcmV?d00001 From da8920537bd04711862d22abc87d59b2dd02bb60 Mon Sep 17 00:00:00 2001 From: djwh1tmer Date: Fri, 30 Jan 2026 15:07:55 -0500 Subject: [PATCH 3/5] Project Idea --- Project_Idea.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Project_Idea.md diff --git a/Project_Idea.md b/Project_Idea.md new file mode 100644 index 0000000..b22db26 --- /dev/null +++ b/Project_Idea.md @@ -0,0 +1,8 @@ +# Project Idea +# David Whitmer +For my three-course sequence to complete the Data Analytics major, I chose English. The goal of this project is to apply data-driven methods to examine narrative time and setting in Karl Ove Knausgaard’s A Death in the Family. Specifically, this project seeks to map the non-chronological movement of the narrative by tracking shifts in temporal position and setting throughout the text. The proposed research question is: How does Knausgaard’s use of non-linear chronology and recurring settings structure the reader’s experience of memory and narration in A Death in the Family? Ultimately, the goal of the project is to help literary scholars and readers make sense of the novel’s fragmented temporal structure by visualizing how the narrative moves across time and place. +The primary text for this project is A Death in the Family, the first volume of Knausgaard’s My Life series. I own a digital copy of the novel, and because the book spans approximately 600 pages, it provides a substantial and ethically sound dataset for analysis. The length and density of the text make it particularly well suited for a data analytics approach, as the narrative repeatedly shifts between different moments in Knausgaard’s life and revisits key locations across decades. +The data for this project will be created through close reading and structured annotation of the text. Each unit of analysis (such as a paragraph or page range) will be tagged for narrative time (for example, childhood, adolescence, early adulthood, or present-day narration following the father’s death) and setting (such as the childhood home, the father’s house, or other significant locations). These annotations will then be organized into a dataset that reflects both the reading order of the novel and the underlying chronological order of the events being narrated. +Once the dataset is constructed, the primary analytical method will be visualization rather than inferential modeling. The central output of the project will be an interactive timeline that displays narrative time and setting in chronological order. When a user hovers over a specific date or time period on the timeline, a representative quotation from the novel will appear, allowing readers to see how Knausgaard’s prose inhabits that moment. By comparing reading order to narrative chronology, the visualization will make visible the extent to which the novel resists linear storytelling and instead organizes memory spatially and temporally. +The intended audience for this project includes literary scholars, students, and readers of contemporary autofiction who may struggle to track the novel’s complex temporal structure through traditional close reading alone. By providing a visual and interactive tool, the project offers a new way to engage with the text that complements, rather than replaces, interpretive literary analysis. The results may also contribute to broader discussions in literary studies about memory, autobiography, and non-linear narrative form. +Ethically, the project poses minimal concerns. Because I own a digital copy of the text, the data is accessed legally and for educational purposes. The project does not involve personal data from living individuals beyond the author himself, and all quotations used in the visualization will be properly cited and limited in length. The goal is not to reproduce the text but to analyze and contextualize it. Overall, this project demonstrates how data analytics methods can be used responsibly to illuminate complex narrative structures in contemporary literature. From 4cd3a37bd666807777bfdffb2c80517a1dc0dca4 Mon Sep 17 00:00:00 2001 From: djwh1tmer Date: Wed, 4 Feb 2026 15:18:05 -0500 Subject: [PATCH 4/5] test --- Mini Project Proposal Idea 2.docx | Bin 0 -> 15511 bytes ~$ni Project Proposal Idea 2.docx | Bin 0 -> 162 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Mini Project Proposal Idea 2.docx create mode 100644 ~$ni Project Proposal Idea 2.docx diff --git a/Mini Project Proposal Idea 2.docx b/Mini Project Proposal Idea 2.docx new file mode 100644 index 0000000000000000000000000000000000000000..cf60372ee54b27267724dddaad76519318354675 GIT binary patch literal 15511 zcmeHuWmII@vS#8?XyGJQxVyW%yF=kpxVyVM6z=Zs6z=X0g-b!Z0gwP_002M$*eaN{)C2(lK0yEgC;(_sEg>6g zM`LS8J!LmrV+S2tS1Zd;dElVrIRMc2=l^s34}Jp;iDTBi^hhH2Nl%Dz%_;^*d1aKK z5xmJXipNlx9-yi(@k1T2T_~UmDj;zmED1@N?l+lK2LonS(=1^=HoB0UV(=vUCFq*7 zQLQZP(fAl)k?thYZwidC`dTt~bYe-fg3uE+_Qg*qeUQt@&j>(Me*i>NCdH@{yGJqM z1wNxQZQplpf~9Pd*iy(fLSZB5<{-l+)Ge`iS&I{58m&0YshcKA2Yzlq4Lk8Xp3hG7 zOp%YZUkh-+{TU6!)ixC(XA3499amI_ctzrc+S2Ryq8* z!v|}>tRBDsfVVd=fc!tXBwie_`QqKqWZyjw_T44*?2RoQ=xBdy|Kp1PgZ=L>KfNNp z$D)rOj{hRyC19pgVYLS{UzW~rdJS_03R+7-8f9(SV(ImTdwCgD=U88CY<4bT+T9^T z)M-0W=O-{(1wOnJX7N$CPwQ8QDcbiX`J zw2?Jm55o_z_*gFpG#d1FY_KzQ1g_sFrhoO1!&}bI#SZ|091Q^Q@%^Q^*w`D<8QB;* zS-sC&zfD+Ynj6+@oXA~zpSS#eP8@^8Kd{LfFmr^;omu;xvzmF-EHwygamR_{#@FrY z{t!AtIZrraDEW5<1q#Fc7n zv3|MJcXwYgShPdCR;IGs(1cxk+CQlFaccz*a8fen;sih&i7h7Gsy zj2Rg>*+JX;56h1 zVw2&qF}BH}+i!MR=;3`h;SoY|UOvSOKjG7uuaVKjg$8m z`l>Vpr$chdwlkBC)U)2&5;IGcy(J19Zw*;;Wih?aSNT~4vnFE(t>sOwj-^fu+H?KR z`cFC%)SDJoM2gD_RO!PVCLw37vp?xe1F88;eT|bAX@3 z1+J&0&YXd+3BvPCX(cu7CWR8g(3{lH)N__t&1+>ARP`jEXtRj(ma1=Z5YxIy#s+C+vq-D16w(juhfu7)OoNAA z2Mfzf;8;q)fh3=l95BUGWSKNvYi@I{UFml{Fy?eIwhgn*?xje0bmpF+p~=a`s(^Z@ z2cD%+T=VX5q;f}yR%1wF^GfA@+#d7gKj7i_`8a&D(;Y76ll{H;nNjXoN}E2fe-S?X z+t=u&o3Fb)pA#MW^uUBV%g)1@_EX%$QI+cEa})^T&UBe!&#IWvzP>9Jllx7tt~ zbPLXZj=U_=bZ>X&A}V=HH`=2MwMG$l+zFWU*7<~@c@#5MiHqBppIws0@pNo-xvkI^ zHnT-|6{4vT=_$upP7<+Gu=ReZN3Bff>I(FE{VJXU(`VKJTkoG75`B~<_tba1{}4iy zbsC!9zJ}OrIei?tT+Q8#pd$~~p6&9h*=6_qCS)Vq>fR&&@H4H|vU-sq3&Ya_s&n_6 zVdhTFT&8m~^>g1*HtUn}xOC5i`_QVMO3-e9^O%#~5@~=<%N>l+C9@^cugnbhMdjeWjRWlS@WqxV8g$t|1%#;>v8rZH7TsmG><;-Sb$fl4k zL(XNr#FSi!;TG>u)Y&ze&@u>Sh_=z20V^KzktmVJ%|%0WOKl&rpq)b|<2ER>sxl*~ z#~v zhyz4ZHTp#@4C^}-4xu1}D&q#N^z#p90|f>)uKFGE7n$^u&qj#IqhxRj0|(JxNHwC9 z)mOK}IISU?&le@5agFKIw|*9MG|QbeoU+;DIeMi_iI8a<`6G&Inz{~7SC_ha_3Fax zD>itvqfIC1xD0L{62_Z-bW0OFi!QB1Lfp*3n(Dkr)D1^fO}m!HKu3_*%oGiqkt}u> zV8m>oCWNZ5!y@ecdF0nSLu!v;_-#+th+}m;aeq~k^V_x7hO5QyCn=D^2$4M4Lp8G4 zpl`nZsk8>7zqUywG5sgp&1a*Rw{F4*fH~D07OrQF5rr%w=TN;R?P>WmqW8k9sL;aP zo8d_lRpK9s*nU?UNpE|9a%zZ-HRaH6pGJPO}q<`gG?co+J^B{@^#5U=10j%CY~`Y-gi;7No4S)_dF zVUh3Pp~M_fKbz^n%|2yR8d3XN6A^aGUlI8Z((Ep4$^3-o zK_K6l=KTtxx-CVk#HoKJ%3BfMMo{#My(@R|;85XU{gR-W!VoNa*L^^a~A>78E^X&4kTKbU$zRAO|mpF_l*C8BK3kB z7__2fNGcqOOwtr7G`K1`_(yBC+ELwQ&}N>KyuicIk9%Y$B-`SxnhL`jV;J8LHL-^< zA{f8l<=sGRIt1b#DVj>+=8CF(WsgoH1vYf?=+oYk zJXs40yb}fT4e;@H%)DhD&FUBX{eI?##pDJu(ULh!g2l?0z!87#PqW2{?ZwWtVOlN(65CqW}s=FJ7L?U zV=I+}kC9PJw^bcvk_j^2elUo!O(`sm7vTp?~(HDnz3dKeIkrp0a=DWvuD6l z*58qwIa>KlhJWd+blb}qg45BK)dylE-^JK(;p`2Z$j6{*3RZ#-fKBQ&mwDb{)Wsc` zAUwMbeK#xM2I{nmx+UpF-;N?*iD7Qv}qU<%A**e=X z?_Qs4+P>!4R>Y{XK8qG(C|gkMQI%-|sD!j-E=LHERq_|&NoXUQ3P{Ruem&&_j>AP&WczG_>6FiTKsVsMR=0gvSLa@t5($c$3N!%?0uIo6pHRJX! zzWE;-E#o5|r7VDzC(41=AW_~cGn`Fbf1%s->Cb;BhHIzr9V*D~LOb@`A4R}kC%sy8 z9oF#!34-m%4v&=Zs$RZKRKs;b z?0PxV>44Mx>icl3AMyId^}evv4dv;e`<>$cD+yjSs#myqmoU69A#niEAitB~|5_>j zl?wl{Y6N)?;JlOR|Jg@H{Mh@d={zic5(Z_gPC< z*D`C`LRM=2)=xN(U2&Qrq%qNm6NlNDH%E#tDkk87c~BM7O4ljEKIzbfQ5H)+i+-R= z70Kn6CDa1$0lZF4(-%?6B?3jlIbQe2_jumFT8*ji zbHgMg05I_h06=>;hTpBm(ahM&nC|zM;rHc}#zX`*8)`Sk6JKa67hX(vifaI0y^M1L z$!WnJ`Px)PDh zGvFf8@qL!J`^E9GhQsY@K&&rHKYNkF7=?}}I~H#1O}DETps zPv_ceFEU)MO@Q-M~eDP=*3fSCOnF9s0M(hnAd zv=`llZ(roE)HiyYb*ks6v0dRM@xEw1NOtSoKSAmSfcodJu(qk%Fk49702vF7rass# zT3B~B2NstYkhUQ|iti0*LdQ^Gi~Bm$qOyY;e9Wi7k<#WuPYl32VDN*5>Zi}sc5c@# zB?hbh?tU86#J(;-Pn78x^{ATi9qb`>N4+5fTd_RBufy~5``P7n{ZMx%kDLA714d2E z3%~l_-RC{ieciW*+pR4hkk_Z%kR`e9+FdvFx06FUy_eUa?otfMN}KFX_t&$17rmFq zIVISRiEVON{O?G1wy>H0T+E5E4br}%XFrI8LHaeqocA0s1xO49?nOT5*wB3PL)V7- z>fAA8)K&vhJrx7rD+ZDdYYDOmCkW=sPjM`7qBAGMqPF6vNrb!3FA!xAbAU(0h9xtk2)ZUDL6nuaK z0nZO2K>;6s_U4gw6WD-r8S?Aog&$BxAJfE1e~t&Qha{TB@o=6((nnTi*r6KLW?z1V zQ-DS&t%=V$Kv1xHkA3d9{lXIsZlBs(b1??iL4^XpGOZ=^&#%Y8G6oG7bxa5n4K!gj ziHez?W9N3pAo&&B`Xjac`U)>+*mpp2jO{m0=`n1Qjy)ZzvJj1w(il%^O&vY34!uIO zH;2Ou6%o~6@2dc)vAdIW)_%a;o#9h zo4V7@wqmGw@PKPHtu;2>|2o)&C1@ZW3ptKtP-7$2tk`esLz&l!(*)W=CM1#_rw@D^)tJG0O8L1}hJH3_={Y6!r92+d*B` zg&4n2 z{bZL?N#MH}jVX0Y4}o6WGjS6S9@l)Xh*qlGStM%S#J{+U>zDLP!vTnp5GB)PWGXr_ z14leVu;SG^2GM*;FyJU$(bhf+eXlJI;V@-UBqmBM=^J*~m_9ap=rtEcb3zpoweKOJ zOJWUk)riM&LHt6XyW7mty5rVoTNpVM_YKuxJ83;mQ?7cK;|0;xP6MQ*$8R@r0=n5^`Q7_}8o#_Y z#;K1s1WzvJE@+7)FUyl#CA zffb4cRz{5v2r;G--Gh1?PhWsI6X;mBfVzMWIA0gPFS%nH~@$ zOP;`g^p9vS^IdgiGA*F41wesYSb^;efp4XAZy6|m<9QMF#twS}F*chS0ZZIB98daw zb|-)FX{p;KzGzddcpp{|JE$RoE~7lZES>n3Q@b(FqCsr^*od>6BVxRBpO_=Wb?%e+ z;$iH{tc-uX_rd1_xhX;>7v2ltt{AZ_>Eg(Bcm9-IVBtsj1^Q zVZ=?!kg2{}8yZwaqdGw{j6WpyixuN6@T+U2gz+U@pYK4i_^J^)4uTdxqp&%sh(3rz z4mD+Hg^jKGqGLdR)8P;1ehrH80Youc9@E+ft)E5KGoAcSYX+*uXTLH@O6Pg>RcX_y z8&%P?VaVi_(6X}vN0hR&yb5xRCQ91Gif*E4tAh3Bs#r?Ioiujg%TAlP>VCNH$k%O@ z*3z0m*g$yprlnY(I;EP@R}YNCj^0l4w`<)nPL0amkgBpC8+Ro=c2d{W<)j3uqFbyW z9OU|r9e)Ha&^C7LC0_B+T6;VP4eM%g_@T%lQlHx7m!szk_wJSKd{@*~KcfqXdMVj{ z%o)7`EUJme!EiZbpBR*-WN;D*2TYdfgUN4$S9hz?(gz z(*M>L>*?C5183?v>CI*d>dt5Q*5}`jH^C14g{epYz-=i2fcOXDc5rmFH2!_GIn!CQ zUlT?4+A4d2O3ZS`N7WHmh^La2jIV6`Vl`B|H*t-G86L_HhXJ6W((85r<1jMhzsVUO zucA@Y=r5dtJGe2IX0zsdeYQ##(Q{KMBJ5t~dfKt2`|d^^&)nU;{L9{@-lqv832h7| zIV?l(jOWt+;xPO5wHY5@FKIz(a7-L@Z@*l_vzD#0?6Eu`fHCU|i^>PdA!{rOMPXc> z1S8^C02UP<`t^(Y_(6r_ka@DI9Mn)qNInm&lB2-K1PS2v5~1$6tFHO40Dn_tg}r^| z%oLVYLyQJ71>$SL{toJWfhooSHbe8SKn@^ijs_4T4>jQg%8kBB3@Dj~k9(q5ZwX=R z55^7&$WQg@)6dX|1T#PWUI2q&+R!h70!3EAguq|NFMxx1;$6Zwy52*XK>79iwna2T zB2D>nV$z&bzeKPQ4rl0K593F^mQ)-zGcu`f#b3YMqIbKyWJmZ%F@+I#GR8-vnSZ|R z-V=M7;d^B3)P;|DVHlZ5=0$U!p*`kfBdi`hxyWv%gj&g?e4CpnOxW z!d(1PrBb}OXiVK*y>#jMHdeXDVY;Bs>Qp-v{<0=z<;v`tRCr&ZiOLvVN)q+CS0_$; zZ1-@h3}S4463Y4WxSnatLAq31iUWFao06rX9o9m$Xh<29Mw$Q7<*`QRPq*9_qX@}m zQD)!A_COv$fWZ}wE#9VuOd32TzpEz5IOBT0IjUX+Ro!{i>dF5cE^n^zi7 ztTM=1TwDip%sbsOZm)%VBNi{!Y^!lU!qutmA3bb2XLS>kM$&B}W;ij*)9iR8Id2<<_s4_eaA^LOftlnAL;uJPMtu zvtvW3LA-D3Fi8@Jh#`#hxKq;2-6i8t&yDne+dzWw5*h@SHi2;}H1NT(hpc1UZJYu( z9YNXHU!f~C3dYl6@_eMmH46z*FG?I4H5q~C`mhvPLUMba2^}NPX9=7r0`X$5?oFK{ z_Q)d6I0O2WC@R9d;DT`E8ki+3RQ}PI=D{RPjuVcCj;ApXWQ|ckG-nO>pJ5sCzzl5KRD~vJTfb){4i0! zPp$o-9kxf&md{>H6IXI@yDFkg!!?2N0_6xFC8;gNP3T5*84BLie@a)2XrER=YGz}8 z^>uBa#R9cb^n`d-E170Iu&H}hePOFl6|_YnB3>GDq6QrASwY4WEfY1)W?}3VS4;mk zWx+(5@JCh<@lj#hwj@gM7Vm@`!CYO)rZ^knSU-{65t2>0Af}!JiBAQ^G4Uf?{bOQM z>15L4r?%{q({{Q%M9a-zzP!fN6XvcS^?Zir=ra?aHaERo@i)R+C7Bk!O#^hp%8;2D zrL|z5hip8b<%&*Qp$gPf$RUpUz#urkU-eY=DBzws4URJ2>I%XS=5wwC zW1d`pk@=v@8Rex?Gq!n_@J2! ziUvdG8wds{%;fZxuup$30Ke%L8Ui`>Nsk6weAC4R6J>_5{Z{fEd2=J@m^1{Ef5ikZ zx^D`M9GzmuOv;AW74u|_OZeQT6bUA=?|?wO5k^}5U`hKymHVSW*T@485qa$U3kXUr zA=4MOw*F4)tITo|XLvb@7-*H!Kt9x`hVW*%y;FY)jyE zoR@IX%o&*6>_Ejixo4^Y^O1E0kNZT6_gT?^D@%fUJ@>I0%o>hWv-U*%615zcW-sd$ zr=~?_l}6L?4ht0?5O=3x!Y7#{Yv@sSt;5WGec3Xdh=wLz`)9*M#9{%m&R}huCSc{b z2&>zR?egIV1Lalz=e<3#;|eN1;q-63*VUz*^@jdM);4bU;Gw_VkvAypU)zw1th=3i zN`DFIT`{#pZ3DSQ-{&)t+-h7`11%sCN{y4$3U=Wg7 z?#ZJ8;{Ofyfk0jm;y^$!h}==K%vj}{|EPEp#T5gpK!X*s#Idv+F8s` z6}b!CUmJ8fE3#hB`1{VekQ=!tx{tMOd=a)J{X+8(+dKS+*c<$_cF7-f^6s=%UF>dY zK9;~{cWXEE?d;~=dmhJop$qCUL2UO`CFc||S~|EbArrgxvC6s7^i()3qkHK{*#dEz zAap9no{CW2I6()k^amMuuTq;uz6{|Y*l9&N!|gyfi=J{l7&Pp-93kzA(i=L5O#yy(N$ujA<63zP~FCh89o;OSLT{ zP^Mo%DvPqv5z)v84%8S%rw4Kbx1iJ+hQdxp>+?75sY97aAqakM0&gwj7&4ZkHTMpz zI(z)sHhUz-e|a3#gK`=o$aEI+As?7R!=ivotIP+QY@yw>SNMM2s2DYttXVo}EahEh zx1xx$&|+B{cJg!kOzi!a{%^$Z*m+^6DU>=4(v08EC0S^-u9V*Oq?Nqukx|~QDgNb z2kMGimT*JJ6P{BdRLqy`ZpGy%r9k^P$>^`{U~SheiUym2FCe$k7xDY1Wr?*X5=Py4 zCTgb$Yh#U1E()U=tLF}`t`1C|Ol?hGGqGBnwU&#zBD|pR)w~{sYuHR~9o;2%pc|tL zR4CYsRBEM5OB3318v0FD87-SbqYYyUw0vLgzCAwYTk2IS!Nzmwo)j)%Obwn`8QOzG z9weCFfti`APW5(79ltDDuEgVtuZf->9xh+dWM?a3Z!J4n{9460TBKIf%TX$?PS(qb zNP10qX~W8jZdf|Xbh2z&HsoZiP%U3mA)a1{5>WT5sp^9J;axLX;lN9R@tu1}_pr7n zY|t&5i+xJ6#-y92mABqwh3>@4shZQo)AXFB#;E<=c=6V;+Ha}zEb0^UIm?6WdO4nb zjE9v&o=(eXZRT917pGG7=`p2Hb@?)vkD0ddL$A*M_-!KRnULJfRqlP_{Iidh`_ht) zyL*4w644p14l|zJm6vOv>d06GE|1qYPn@O^C`)gtU9fzNb13Y1h7EmmT<9Up`a*WrjCX-Pa!#fx&O}7^82j zgN@M6WpBGmx7Dz3)f5Mzhq|vcRLsxWZz7M?ArBmAa#OC$nT*;@p8?SHFnVu)IgP#u}aH zX5FpqFGKe1vpqF!d5U%v!;i)Wa?>@#^=v?xvQY{1UXH$(Gb1=Y+)@YEl7Z($33 z448czD>9Rm37Qi-X82gxB)fE5ar45oUThy`w2X@71&0`l+2o|)9{g4T>N}>I{hc75 zM(OanmW9}0ESXdfL93m1n?Qr1krkhcOt@nCYWqH)z#dP!b8M(DG!#lJ@0V0bKv%q9 zK|gAyXJQ7jg2AZ~oifme6Q<~DmuM$46x;*-S?cKf*Xx%biKzyWG4T$Bl4rx+@;YZ_ z<0iV9wH%8kR&z*(r(b~PBI-g4gQS)vt61c*U#U#W*hxbsQO6c~4}8Ozs|Tyf^_#L4hGr$1CF zd?)Iz=3mMjo_d7MX6I!xo)~4;!(KKTtSFo=5Vb(rtIZq-&(hgwU%A2S9%?Kc)oHcH zFsnDV=HOO-YpW5>gscuOi;M1}v}3=muTdf7!fiE4QBjjo#Xnodp?YcQv$$r(4;Esm zxn)WeDth{m(#Bh;+hwX#Yel;>qmv9}wI$x{DYJQ?A8>!PgHzZ;Bu_T_W3#qzt>H|a zIi%@!s>0GChL&K`s)}Y7UhpdPQ6=v!?KIE5ThTrKx?o+MY+s%c12wc5uYf0e7fb&)`a(jxdKbKYM zgk@=O31?4a%8b}6rWZO>5k79kb?9IeXQs_Ma*AyuuQ!_w+bTD3v}&{7f*^!lQOaG5 z*8ay@uH=<0(@_zImRvCH1-w2ap5{yW^YOnAVvue=iQByI9@D%BPEr2|Vz?L^DE%dF znlZOw-TMg@u>Fg~BP7_PkdsBqkVOMMWrJF(i3iYIN&;F8qU|KdSF*6+YUrYbFnzuM zlTGiuQL?LtGmMlhUtbcL9w&%7J;T$h3NnV+E(@y%6*xQsf}=ruesSQW+V=$3f#}ml zOg?Cwc35!JHA?Q(0Y0&gL`AP($6x*xQKvmOZRJN5&~_f}+MXuq28vU54$Bw4*PQROC&W1W*)Ob^N&z90rMSFoCN3^T$BZ|$IgtJ;3U%!-6+t@ve}PAhhU3hZQ4n1)*6nnxQ|?e(@d+e1ClFMVtXs4dj}+e z?B0Ek{Y5bPTaiOn<^h5OpUzeZJM=0#=C7bs&9bQ%5vZg3q$w)4wsZwUbh)nv=>Bb# z>Dd-Ii13~*P6h=4Aph|PnYSH(DP6T9 z`Z1wfu?l4y38U)8k4Hvq(`_iESZ3C!Z-YUM`Kr(B<{g8Nhp0*7vBR%fPrMQuFN|po zYu+Sv_1e^xnE=ks1fjGTO2YBsQ%rff4dO&z!=RA=EhKsxoy5LZr?}E~(lnfC6FOu< zp;MaMv*VgF(|v8ZP3r>7wLMYN%@A|3qbO%&d$7TnqWz`8qb%&Mq1Q>EU>=M72vD}+ z0H|rGqrf!=0l2GB8Jm+%VFl0H0(u7_Hd#o8!AWLabXfFxmC*YB@^YH$MtCq2ourI!r({7|GGN(VQdB}+az4y=@K7r=F#5LKEG$;=x ze24-!LutI};5_y?Ffz-P@mn`AfWmGgcD*8>ICLpcspF4cYEinX7vwU2R@sR|;j91U zRP1U0opY|~4Hkd106q2@Rpx5U!sK;ZT-MZ4y7*`mb@%dWw!Wh}i40fWsT2?k% zxHK{z2#@#Z%c;Wnp6#bz_jcM^~-h!WE0C688^?zy>P=p_sjvBj%3 z`eB*(B)GY`D?+D7toG!W)37UV=YMA8#c&p74P`B!kAOEjPvB3L*ItlyfGgEf8XHKi z_A`mpQG_2R5tHT8w-h5t!8ld>;0e^9kvnWh4O&J8_&A^)2Y7e`+jS^n*?v^h zy^yw%LUAp0Ml=2hW1zV!$14KE3PRiO6GTi(xn3K%icZ8Dqcuz(I5YTKn_j^;gKd66LT|% zB5|3XvWY4Nt-#ezd#a&={yFJO<3{yZ$idjcP+cgw6;)Jy4Xqr~8205W?iS=BK~AuG zY+%&smG6;Sq==KR?jTknjWH*Ndl+gkkAqGz+B)a$dVmOPbs0$j2Kbtw$39t)y|Om$ zrH_bKaeVi~at8M?%qIUulrYlPT(-#~=NU)3`X+l~(F{-Mm%L(Mn|-{zR0mej*F8b( z0fW|U%RoEYWAuvxd#jOOF%Ag*uaGv_|* zP-ad*bh@S3@}(Yd=@*nD$_!@w_#9n@B+cpj+UQ|6#Zrx8UW_+%PkFLmk!Pcx$0U|c z&qI8P{m0-90!s7F!~T5*=YN^NpY6Y?=aiTFX9fRUZ}uk?07!WEw7*oJ{T=xCLYzOL z_3t@m|5BFoclbZ2F#ZV!09xM5dj3xdjepnl_q4V@b)BR9Z<5^puHx^B0e`Bv0RBV8 zU(*Es4*&Z;-=A&Jc`1l@^Z2c{5f;$%&N;qu{C4%f023)C AmH+?% literal 0 HcmV?d00001 diff --git a/~$ni Project Proposal Idea 2.docx b/~$ni Project Proposal Idea 2.docx new file mode 100644 index 0000000000000000000000000000000000000000..faac151e55ac8ec319cc7b1ec64af12828b286d2 GIT binary patch literal 162 zcmWgj%}g%JFV0UZQSeVo%S=vH2rW)6VjuuS8GIQs8Il=_81fm4fjEt!gh7G9A4sQx z#Z!U2P@qgIPz3`+Q3}Yoh>{zvj6k|VNP&YHNIQr?=prcH0ToYx(k1?rI6&$FeghYh literal 0 HcmV?d00001 From 90c0c75415eca0f84a4a261ae1fcd4c99db8a508 Mon Sep 17 00:00:00 2001 From: djwh1tmer Date: Mon, 16 Feb 2026 11:43:25 -0500 Subject: [PATCH 5/5] Test --- ...hitmer Mini Project Data Capstone V8.ipynb | 913 ++++++++++++++++++ Mini Project Data Capstone V8.md | 873 +++++++++++++++++ tristram_final_fixed.Rmd | 512 ++++++++++ tristram_shandy_complete_analysis.html | 380 ++++++++ 4 files changed, 2678 insertions(+) create mode 100644 David Whitmer Mini Project Data Capstone V8.ipynb create mode 100644 Mini Project Data Capstone V8.md create mode 100644 tristram_final_fixed.Rmd create mode 100644 tristram_shandy_complete_analysis.html diff --git a/David Whitmer Mini Project Data Capstone V8.ipynb b/David Whitmer Mini Project Data Capstone V8.ipynb new file mode 100644 index 0000000..d6a0a5b --- /dev/null +++ b/David Whitmer Mini Project Data Capstone V8.ipynb @@ -0,0 +1,913 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "a414e9e4-1a9c-48f2-897c-65dd421f6f27", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================================================================\n", + "TRISTRAM SHANDY: COMPLETE TEMPORAL ARCHITECTURE PIPELINE\n", + "Advanced Web Scraping + Dual-Panel Visualization + HTML Presentation\n", + "================================================================================\n", + "\n", + "Downloading Tristram Shandy from Project Gutenberg...\n", + "✓ Downloaded (1259736 characters)\n", + "Extracting chapters with full content...\n", + "✓ Extracted 300 chapters\n", + "Annotating chapters with narrative periods and selecting quotations...\n", + "✓ Annotated 300 chapters with quotations\n", + "\n", + "Creating dual-panel visualization...\n", + "✓ Visualization created\n", + "\n", + "Generating comprehensive HTML presentation...\n", + "✓ Complete HTML presentation saved: tristram_shandy_complete_analysis.html\n", + "\n", + "================================================================================\n", + "✓ COMPLETE PIPELINE FINISHED\n", + "================================================================================\n", + "\n", + "📄 Open this file in your browser: tristram_shandy_complete_analysis.html\n", + "\n", + "What you'll find:\n", + " • Comprehensive explanatory sections\n", + " • Dual-panel temporal architecture visualization\n", + " • Interactive quotations on hover\n", + " • Complete methodology and dataset summary\n", + "\n", + "The structure of non-linear time is now visible.\n", + "================================================================================\n", + "\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "COMPLETE TRISTRAM SHANDY PIPELINE WITH HTML PRESENTATION\n", + "==========================================================\n", + "\n", + "This script:\n", + "1. Scrapes full text with intelligent quotation extraction\n", + "2. Creates dual-panel temporal architecture visualization\n", + "3. Generates comprehensive HTML page with explanatory sections\n", + "\n", + "Run this single script for the complete digital humanities presentation.\n", + "\"\"\"\n", + "\n", + "import requests\n", + "from bs4 import BeautifulSoup\n", + "import pandas as pd\n", + "import re\n", + "import json\n", + "from typing import List, Dict\n", + "import plotly.graph_objects as go\n", + "from plotly.subplots import make_subplots\n", + "\n", + "class TristramShandyCompletePipeline:\n", + " def __init__(self):\n", + " self.url = \"https://www.gutenberg.org/files/1079/1079-h/1079-h.htm\"\n", + " self.html_content = None\n", + " self.chapters = []\n", + " self.annotated_data = []\n", + " \n", + " # Narrative time buckets\n", + " self.time_buckets = {\n", + " \"dinah\": {\n", + " \"keywords\": [\"aunt dinah\", \"great aunt\", \"coachman\", \"family disgrace\"],\n", + " \"character_markers\": [\"dinah\"],\n", + " \"description\": \"Aunt Dinah's scandal\",\n", + " \"chronological_order\": -4\n", + " },\n", + " \"yorick_life\": {\n", + " \"keywords\": [\"yorick\", \"parson yorick\", \"denmark\", \"danish\", \"hamlet\"],\n", + " \"character_markers\": [\"yorick\", \"eugenius\"],\n", + " \"description\": \"Parson Yorick's life\",\n", + " \"chronological_order\": -3\n", + " },\n", + " \"toby_namur\": {\n", + " \"keywords\": [\"namur\", \"siege\", \"wound\", \"wounded\", \"groin\", \"flanders\", \"battle\"],\n", + " \"character_markers\": [\"toby\", \"uncle toby\"],\n", + " \"description\": \"Namur\",\n", + " \"chronological_order\": -2\n", + " },\n", + " \"toby_recovery\": {\n", + " \"keywords\": [\"fortification\", \"fortifications\", \"bowling green\", \"trim\", \n", + " \"corporal trim\", \"hobby-horse\", \"ramparts\", \"sieges\"],\n", + " \"character_markers\": [\"toby\", \"trim\", \"uncle toby\", \"corporal\"],\n", + " \"description\": \"Toby Recovery\",\n", + " \"chronological_order\": -1\n", + " },\n", + " \"conception\": {\n", + " \"keywords\": [\"conception\", \"begot\", \"begetting\", \"homunculus\", \"animal spirits\", \n", + " \"clock\", \"wind up\"],\n", + " \"character_markers\": [\"father\", \"mother\"],\n", + " \"description\": \"Conception\",\n", + " \"chronological_order\": 1\n", + " },\n", + " \"birth\": {\n", + " \"keywords\": [\"birth\", \"born\", \"midwife\", \"dr. slop\", \"slop\", \"delivery\", \n", + " \"forceps\", \"nose\", \"crushed\"],\n", + " \"character_markers\": [\"slop\", \"susannah\", \"mother\"],\n", + " \"description\": \"Birth\",\n", + " \"chronological_order\": 2\n", + " },\n", + " \"christening\": {\n", + " \"keywords\": [\"christening\", \"christened\", \"trismegistus\", \"baptism\", \"baptized\", \"name\"],\n", + " \"character_markers\": [\"curate\"],\n", + " \"description\": \"Christening\",\n", + " \"chronological_order\": 3\n", + " },\n", + " \"childhood_accidents\": {\n", + " \"keywords\": [\"circumcision\", \"window\", \"sash\", \"susannah\", \"accident\"],\n", + " \"character_markers\": [\"susannah\", \"obadiah\"],\n", + " \"description\": \"Childhood Accidents\",\n", + " \"chronological_order\": 4\n", + " },\n", + " \"childhood_education\": {\n", + " \"keywords\": [\"tristrapoedia\", \"governor\", \"education\", \"tutor\"],\n", + " \"character_markers\": [],\n", + " \"description\": \"Childhood Education\",\n", + " \"chronological_order\": 5\n", + " },\n", + " \"toby_wadman\": {\n", + " \"keywords\": [\"widow wadman\", \"wadman\", \"amours\", \"courtship\", \"love\", \"bridget\"],\n", + " \"character_markers\": [\"widow wadman\", \"bridget\"],\n", + " \"description\": \"Toby & Wadman\",\n", + " \"chronological_order\": 7\n", + " },\n", + " \"tristram_writing\": {\n", + " \"keywords\": [\"dear reader\", \"writing\", \"pen\", \"author\", \"narrative\", \"i am writing\"],\n", + " \"character_markers\": [\"dear sir\", \"reader\"],\n", + " \"description\": \"Tristram Writing\",\n", + " \"chronological_order\": 10\n", + " },\n", + " \"meta_commentary\": {\n", + " \"keywords\": [\"preface\", \"digression\", \"chapter about\", \"critic\", \"book\"],\n", + " \"character_markers\": [],\n", + " \"description\": \"Meta-commentary\",\n", + " \"chronological_order\": 11\n", + " },\n", + " \"walter_theories\": {\n", + " \"keywords\": [\"theory\", \"hypothesis\", \"auxiliary verbs\", \"nose theory\", \"names\"],\n", + " \"character_markers\": [\"father\", \"walter\"],\n", + " \"description\": \"Walter's Theories\",\n", + " \"chronological_order\": 0\n", + " },\n", + " \"slawkenbergius\": {\n", + " \"keywords\": [\"slawkenbergius\", \"strasbourg\", \"julia\", \"stranger\"],\n", + " \"character_markers\": [\"slawkenbergius\"],\n", + " \"description\": \"Slawkenbergius\",\n", + " \"chronological_order\": 0\n", + " },\n", + " \"sermon\": {\n", + " \"keywords\": [\"sermon\", \"conscience\", \"ernulphus\", \"preached\"],\n", + " \"character_markers\": [],\n", + " \"description\": \"Sermon\",\n", + " \"chronological_order\": 0\n", + " }\n", + " }\n", + " \n", + " # Color scheme\n", + " self.narrative_colors = {\n", + " 'tristram_writing': '#FF8C42',\n", + " 'toby_recovery': '#7FB069',\n", + " 'birth': '#4ECDC4',\n", + " 'toby_wadman': '#9B59B6',\n", + " 'toby_namur': '#E74C3C',\n", + " 'childhood_accidents': '#95A5A6',\n", + " 'conception': '#F1C40F',\n", + " 'meta_commentary': '#E67E22',\n", + " 'sermon': '#8E44AD',\n", + " 'walter_theories': '#C39BD3',\n", + " 'slawkenbergius': '#D7BDE2',\n", + " 'dinah': '#CB4335',\n", + " 'christening': '#45B7D1',\n", + " 'yorick_life': '#5DADE2',\n", + " 'childhood_education': '#F8B739'\n", + " }\n", + " \n", + " def download_book(self) -> bool:\n", + " print(\"Downloading Tristram Shandy from Project Gutenberg...\")\n", + " try:\n", + " response = requests.get(self.url, timeout=30)\n", + " response.raise_for_status()\n", + " self.html_content = response.text\n", + " print(f\"✓ Downloaded ({len(self.html_content)} characters)\")\n", + " return True\n", + " except Exception as e:\n", + " print(f\"✗ Error: {e}\")\n", + " return False\n", + " \n", + " def extract_chapters(self):\n", + " print(\"Extracting chapters with full content...\")\n", + " soup = BeautifulSoup(self.html_content, 'html.parser')\n", + " text_content = soup.get_text()\n", + " \n", + " chapter_pattern = re.compile(r'C\\s*H\\s*A\\s*P\\.?\\s+([IVXLCDM]+)', re.IGNORECASE)\n", + " matches = list(chapter_pattern.finditer(text_content))\n", + " \n", + " for i, match in enumerate(matches):\n", + " chapter_num_roman = match.group(1)\n", + " chapter_num = self._roman_to_int(chapter_num_roman)\n", + " start = match.end()\n", + " end = matches[i + 1].start() if i + 1 < len(matches) else len(text_content)\n", + " \n", + " content = text_content[start:end]\n", + " content = re.sub(r'\\s+', ' ', content).strip()\n", + " content = re.sub(r'\\[Pg \\d+\\]', '', content)\n", + " \n", + " if len(content) > 200:\n", + " self.chapters.append({\n", + " 'chapter': chapter_num,\n", + " 'chapter_roman': chapter_num_roman,\n", + " 'content': content\n", + " })\n", + " \n", + " print(f\"✓ Extracted {len(self.chapters)} chapters\")\n", + " \n", + " def _roman_to_int(self, roman: str) -> int:\n", + " roman = roman.upper().strip()\n", + " roman_values = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}\n", + " total = 0\n", + " prev_value = 0\n", + " for char in reversed(roman):\n", + " value = roman_values.get(char, 0)\n", + " if value >= prev_value:\n", + " total += value\n", + " else:\n", + " total -= value\n", + " prev_value = value\n", + " return total\n", + " \n", + " def extract_candidate_quotations(self, content: str) -> List[Dict]:\n", + " \"\"\"Extract scored candidate quotations.\"\"\"\n", + " sentences = re.split(r'(?<=[.!?])\\s+', content)\n", + " candidates = []\n", + " \n", + " for i, sentence in enumerate(sentences):\n", + " if len(sentence) < 40 or len(sentence) > 400:\n", + " continue\n", + " if re.match(r'^(Chapter|CHAP|Vol)', sentence, re.IGNORECASE):\n", + " continue\n", + " \n", + " score = 0\n", + " sentence_lower = sentence.lower()\n", + " \n", + " # Character names\n", + " character_names = ['toby', 'trim', 'yorick', 'walter', 'slop', 'susannah', \n", + " 'obadiah', 'dinah', 'wadman', 'bobby']\n", + " for name in character_names:\n", + " if name in sentence_lower:\n", + " score += 2\n", + " \n", + " # Temporal markers\n", + " temporal_markers = ['when', 'after', 'before', 'during', 'since', 'until']\n", + " for marker in temporal_markers:\n", + " if marker in sentence_lower:\n", + " score += 1\n", + " \n", + " # Dialogue\n", + " if '\"' in sentence:\n", + " score += 1\n", + " \n", + " candidates.append({'text': sentence.strip(), 'score': score})\n", + " \n", + " return candidates\n", + " \n", + " def select_representative_quotation(self, content: str, narrative_bucket: str) -> str:\n", + " \"\"\"Select most representative quotation using keyword matching.\"\"\"\n", + " candidates = self.extract_candidate_quotations(content)\n", + " \n", + " if not candidates:\n", + " return content[:200] + \"...\"\n", + " \n", + " bucket_info = self.time_buckets.get(narrative_bucket, {})\n", + " keywords = bucket_info.get('keywords', [])\n", + " character_markers = bucket_info.get('character_markers', [])\n", + " \n", + " # Score by relevance to narrative bucket\n", + " for candidate in candidates:\n", + " quote_lower = candidate['text'].lower()\n", + " relevance = 0\n", + " \n", + " for keyword in keywords:\n", + " if keyword.lower() in quote_lower:\n", + " relevance += 3\n", + " \n", + " for character in character_markers:\n", + " if character.lower() in quote_lower:\n", + " relevance += 2\n", + " \n", + " candidate['relevance'] = relevance + candidate['score']\n", + " \n", + " candidates.sort(key=lambda x: x['relevance'], reverse=True)\n", + " return candidates[0]['text'] if candidates else content[:200] + \"...\"\n", + " \n", + " def annotate_chapters(self):\n", + " print(\"Annotating chapters with narrative periods and selecting quotations...\")\n", + " \n", + " for idx, chapter in enumerate(self.chapters):\n", + " content_lower = chapter['content'].lower()\n", + " \n", + " bucket_scores = {}\n", + " for bucket_name, bucket_info in self.time_buckets.items():\n", + " score = 0\n", + " for keyword in bucket_info['keywords']:\n", + " score += content_lower.count(keyword.lower()) * 2\n", + " for character in bucket_info.get('character_markers', []):\n", + " score += content_lower.count(character.lower()) * 3\n", + " if score > 0:\n", + " bucket_scores[bucket_name] = score\n", + " \n", + " primary_bucket = max(bucket_scores, key=bucket_scores.get) if bucket_scores else 'tristram_writing'\n", + " bucket_info = self.time_buckets[primary_bucket]\n", + " \n", + " representative_quote = self.select_representative_quotation(chapter['content'], primary_bucket)\n", + " \n", + " self.annotated_data.append({\n", + " 'chapter': chapter['chapter'],\n", + " 'chapter_roman': chapter['chapter_roman'],\n", + " 'reading_order': idx + 1,\n", + " 'chronological_position': bucket_info['chronological_order'],\n", + " 'narrative_period': primary_bucket,\n", + " 'narrative_description': bucket_info['description'],\n", + " 'representative_quote': representative_quote\n", + " })\n", + " \n", + " print(f\"✓ Annotated {len(self.annotated_data)} chapters with quotations\")\n", + " \n", + " def create_visualization(self) -> go.Figure:\n", + " \"\"\"Create the dual-panel temporal architecture visualization.\"\"\"\n", + " print(\"\\nCreating dual-panel visualization...\")\n", + " \n", + " df = pd.DataFrame(self.annotated_data)\n", + " df['color'] = df['narrative_period'].map(self.narrative_colors).fillna('#95A5A6')\n", + " \n", + " # Create dual-panel figure\n", + " fig = make_subplots(\n", + " rows=2, cols=1,\n", + " row_heights=[0.75, 0.25], # Give more space to top panel\n", + " vertical_spacing=0.10, # Slightly reduced spacing\n", + " subplot_titles=(\n", + " 'Narrative Path of \"Tristram Shandy\"',\n", + " 'Chronological Distribution'\n", + " ),\n", + " specs=[[{\"type\": \"scatter\"}], [{\"type\": \"bar\"}]]\n", + " )\n", + " \n", + " # TOP PANEL: Connected line graph\n", + " for i in range(len(df) - 1):\n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x=[df.iloc[i]['reading_order'], df.iloc[i+1]['reading_order']],\n", + " y=[df.iloc[i]['chronological_position'], df.iloc[i+1]['chronological_position']],\n", + " mode='lines',\n", + " line=dict(color=df.iloc[i]['color'], width=1.5), # Reduced from 2 to 1.5\n", + " showlegend=False,\n", + " hoverinfo='skip'\n", + " ),\n", + " row=1, col=1\n", + " )\n", + " \n", + " # Add markers with quotations\n", + " for period in df['narrative_period'].unique():\n", + " period_data = df[df['narrative_period'] == period]\n", + " \n", + " fig.add_trace(\n", + " go.Scatter(\n", + " x=period_data['reading_order'],\n", + " y=period_data['chronological_position'],\n", + " mode='markers',\n", + " marker=dict(\n", + " size=6, # Reduced from 7 to 6 for less visual clutter\n", + " color=self.narrative_colors.get(period, '#95A5A6'),\n", + " line=dict(width=0.5, color='white')\n", + " ),\n", + " name=period_data.iloc[0]['narrative_description'] if len(period_data) > 0 else period,\n", + " text=period_data.apply(\n", + " lambda row: f\"Chapter {row['chapter']}
\" +\n", + " f\"Period: {row['narrative_description']}

\" +\n", + " f\"\\\"{row['representative_quote'][:200]}{'...' if len(row['representative_quote']) > 200 else ''}\\\"\",\n", + " axis=1\n", + " ),\n", + " hovertemplate='%{text}',\n", + " legendgroup=period\n", + " ),\n", + " row=1, col=1\n", + " )\n", + " \n", + " # Add temporal labels\n", + " fig.add_annotation(x=10, y=-4, text=\"-4 Past\", showarrow=False,\n", + " font=dict(size=10, color='#7F8C8D'), xanchor='left', row=1, col=1)\n", + " fig.add_annotation(x=10, y=0, text=\"0 Digressions\", showarrow=False,\n", + " font=dict(size=10, color='#7F8C8D'), xanchor='left', row=1, col=1)\n", + " fig.add_annotation(x=10, y=11, text=\"11 Present\", showarrow=False,\n", + " font=dict(size=10, color='#7F8C8D'), xanchor='left', row=1, col=1)\n", + " \n", + " # BOTTOM PANEL: Distribution bars\n", + " chronological_counts = df.groupby(['chronological_position', 'narrative_period']).size().reset_index(name='count')\n", + " positions = sorted(df['chronological_position'].unique())\n", + " \n", + " for period in df['narrative_period'].unique():\n", + " period_counts = []\n", + " for pos in positions:\n", + " count = chronological_counts[\n", + " (chronological_counts['chronological_position'] == pos) & \n", + " (chronological_counts['narrative_period'] == period)\n", + " ]['count'].sum()\n", + " period_counts.append(count)\n", + " \n", + " fig.add_trace(\n", + " go.Bar(\n", + " x=positions,\n", + " y=period_counts,\n", + " name=df[df['narrative_period'] == period].iloc[0]['narrative_description'] if len(df[df['narrative_period'] == period]) > 0 else period,\n", + " marker_color=self.narrative_colors.get(period, '#95A5A6'),\n", + " showlegend=False,\n", + " legendgroup=period\n", + " ),\n", + " row=2, col=1\n", + " )\n", + " \n", + " # Layout\n", + " fig.update_xaxes(\n", + " title_text=\"Reading Order (Chapters)\", \n", + " showgrid=True,\n", + " gridwidth=0.3, # Thinner gridlines\n", + " gridcolor='rgba(200,200,200,0.25)', # Lighter gridlines\n", + " range=[0, df['reading_order'].max() + 10], # Add padding on right\n", + " row=1, col=1\n", + " )\n", + " fig.update_yaxes(\n", + " title_text=\"Chronological Position\", \n", + " showgrid=True,\n", + " gridwidth=0.3, # Thinner gridlines\n", + " gridcolor='rgba(200,200,200,0.25)', # Lighter gridlines\n", + " zeroline=True, \n", + " zerolinewidth=1, \n", + " zerolinecolor='rgba(100,100,100,0.4)',\n", + " tickmode='linear', \n", + " tick0=-4, \n", + " dtick=1,\n", + " range=[-5, 12], # Add padding top and bottom\n", + " row=1, col=1\n", + " )\n", + " fig.update_xaxes(\n", + " title_text=\"Chronological Position\", \n", + " tickmode='linear',\n", + " tick0=-4, \n", + " dtick=1, \n", + " row=2, col=1\n", + " )\n", + " fig.update_yaxes(\n", + " title_text=\"Number of Chapters\", \n", + " row=2, col=1\n", + " )\n", + " \n", + " fig.update_layout(\n", + " height=800,\n", + " width=1800, # Increased width for more horizontal space\n", + " plot_bgcolor='white',\n", + " paper_bgcolor='white',\n", + " font=dict(family=\"Arial, sans-serif\", size=11),\n", + " title_font=dict(size=16, color='#2C3E50'),\n", + " hovermode='closest',\n", + " margin=dict(l=80, r=250, t=80, b=60),\n", + " legend=dict(\n", + " title=dict(text=\"Narrative Periods\", font=dict(size=11)),\n", + " orientation=\"v\",\n", + " yanchor=\"top\",\n", + " y=0.95,\n", + " xanchor=\"left\",\n", + " x=1.01,\n", + " bgcolor=\"rgba(255,255,255,0.9)\",\n", + " bordercolor=\"#BDC3C7\",\n", + " borderwidth=1,\n", + " font=dict(size=9)\n", + " ),\n", + " barmode='stack'\n", + " )\n", + " \n", + " print(\"✓ Visualization created\")\n", + " return fig\n", + " \n", + " def create_html_presentation(self, fig: go.Figure):\n", + " \"\"\"Generate comprehensive HTML page with explanatory sections.\"\"\"\n", + " print(\"\\nGenerating comprehensive HTML presentation...\")\n", + " \n", + " df = pd.DataFrame(self.annotated_data)\n", + " \n", + " html_content = \"\"\"\n", + "\n", + "\n", + " \n", + " Tristram Shandy: Temporal Architecture Analysis\n", + " \n", + " \n", + "\n", + "\n", + "
\n", + "

THE LIFE AND OPINIONS OF TRISTRAM SHANDY, GENTLEMAN

\n", + "

by Laurence Sterne (1759-1767)

\n", + "

\n", + " A Digital Humanities Analysis of Non-Linear Narrative Structure\n", + "

\n", + "
\n", + "\n", + "
\n", + "

About the Novel

\n", + "

\n", + " The Life and Opinions of Tristram Shandy, Gentleman is one of literature's \n", + " first experimental novels and a masterpiece of non-linear storytelling. The narrator, \n", + " Tristram, attempts to tell his life story but constantly digresses into tangents, \n", + " backstories, and philosophical musings. The result is a chaotic, playful narrative \n", + " that jumps backward and forward in time.\n", + "

\n", + "
\n", + " 💡 Key Insight: Tristram famously doesn't even get to his own birth \n", + " until Volume 3 — he's too busy telling us about everything that led up to it! The \n", + " novel's structure itself becomes an argument about memory, digression, and the \n", + " impossibility of linear self-narration.\n", + "
\n", + "
\n", + "\n", + "
\n", + "

The Dual-Panel Visualization Explained

\n", + "

\n", + " This is not a generic timeline. It is a temporal architecture visualization \n", + " designed to make the novel's non-chronological structure legible. The visualization consists \n", + " of two synchronized panels:\n", + "

\n", + " \n", + "

Top Panel: Narrative Path Timeline

\n", + "
    \n", + "
  • X-axis: Reading Order (Chapters 1–300 sequentially)
  • \n", + "
  • Y-axis: Chronological Position (when events actually occur: -4 to 11)
  • \n", + "
  • Connected Line: Shows the temporal path a reader takes through the narrative
  • \n", + "
  • Color-Coded Dots: Each chapter colored by its narrative period
  • \n", + "
  • Hover Interaction: Displays representative quotations from each chapter
  • \n", + "
\n", + "

\n", + " If the novel were linear, the line would ascend steadily from bottom-left \n", + " to top-right. Instead, you see dramatic vertical jumps—Sterne constantly yanking the reader \n", + " backward and forward through time.\n", + "

\n", + " \n", + "

Bottom Panel: Chronological Distribution

\n", + "

\n", + " A stacked bar chart showing how many chapters occupy each chronological position. This reveals \n", + " where the novel dwells chronologically—notice how much time Sterne spends on \"present \n", + " narration\" (position 10) compared to actual life events.\n", + "

\n", + "
\n", + "\n", + "
\n", + "

Understanding the Chronological Scale

\n", + " \n", + "
\n", + "
\n", + " -4 to -1\n", + "
Before Tristram's Birth
\n", + " Family history, Uncle Toby's war injury at Namur, Parson Yorick's life and death\n", + "
\n", + " \n", + "
\n", + " 0\n", + "
Digressions
\n", + " Timeless stories-within-stories, philosophical theories, embedded tales like Slawkenbergius\n", + "
\n", + " \n", + "
\n", + " 1 to 8\n", + "
Tristram's Life
\n", + " Conception → Birth → Christening → Childhood → Youth (chronological progression)\n", + "
\n", + " \n", + "
\n", + " 10-11\n", + "
Present Narrative
\n", + " Tristram writing the book, meta-commentary on the act of storytelling itself\n", + "
\n", + "
\n", + "\n", + "

Why Negative Numbers?

\n", + "

\n", + " Tristram doesn't start his story at his birth — he goes backward to tell us about \n", + " his family's history first. Uncle Toby's war wound at the Siege of Namur happened years \n", + " before Tristram was conceived, so it gets a negative chronological position (-2). \n", + " Think of position 0 as Tristram's birth (the origin point), with negative numbers representing \n", + " the years before that event. This shows how far back in time the narrative reaches before \n", + " the protagonist even exists.\n", + "

\n", + "
\n", + "\n", + "
\n", + "

What the Visualization Reveals

\n", + "
    \n", + "
  • The connected line traces the reader's journey through narrative time—every \n", + " vertical movement is a temporal jump
  • \n", + "
  • Steep drops reveal flashbacks to pre-birth history (e.g., from present \n", + " narration back to Uncle Toby at Namur)
  • \n", + "
  • Steep rises show returns to the present narrative frame
  • \n", + "
  • Horizontal plateaus indicate sustained focus on a single time period \n", + " across multiple chapters
  • \n", + "
  • Frequency of crossings at y=0 shows how often Sterne interrupts with \n", + " timeless digressions
  • \n", + "
  • Bottom panel density reveals that Sterne spends disproportionate time \n", + " on \"present narration\" rather than life events
  • \n", + "
\n", + "
\n", + " 💡 Literary Significance: The visualization quantifies narrative disorder. \n", + " A linear biography would show a smooth upward slope. Sterne's jagged line—with its wild \n", + " oscillations between past, present, and digression—reveals a narrator unable or unwilling \n", + " to tell his story in chronological order. The structure itself becomes an argument \n", + " about memory, digression, and the impossibility of linear self-narration.\n", + "
\n", + "
\n", + "\n", + "
\n", + "

Interactive Temporal Architecture

\n", + "

\n", + " How to interact: Hover over any point to see chapter details and representative \n", + " quotations. Click and drag to zoom into specific regions. Double-click to reset the view. \n", + " The line connects chapters in reading order—watch how it oscillates through time.\n", + "

\n", + "
\n", + "
\n", + "\n", + "
\n", + "

Methodology

\n", + " \n", + "
\n", + "

Data Collection & Processing

\n", + "

Source: Full text from Project Gutenberg

\n", + "

Chapters Analyzed: \"\"\" + str(len(df)) + \"\"\"

\n", + "

Quotation Selection: Automated intelligent extraction based on:

\n", + "
    \n", + "
  • Temporal markers (when, after, before, during)
  • \n", + "
  • Character name relevance to narrative period
  • \n", + "
  • Keyword matching to narrative buckets
  • \n", + "
  • Sentence quality (50-400 characters, avoids fragments)
  • \n", + "
\n", + "
\n", + " \n", + "

Dataset Summary

\n", + "

Total chapters analyzed: \"\"\" + str(len(df)) + \"\"\"

\n", + "

Reading order range: 1 to \"\"\" + str(df['reading_order'].max()) + \"\"\"

\n", + "

Chronological range: \"\"\" + str(df['chronological_position'].min()) + \"\"\" to \"\"\" + str(df['chronological_position'].max()) + \"\"\"

\n", + " \n", + "

Narrative Period Distribution

\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\"\"\"\n", + " \n", + " for bucket, count in df['narrative_period'].value_counts().items():\n", + " chrono_pos = df[df['narrative_period'] == bucket].iloc[0]['chronological_position']\n", + " description = df[df['narrative_period'] == bucket].iloc[0]['narrative_description']\n", + " html_content += f\"\"\" \n", + " \n", + " \n", + " \n", + " \n", + "\"\"\"\n", + " \n", + " html_content += \"\"\"
Narrative PeriodNumber of ChaptersChronological Position
{description}{count}{chrono_pos}
\n", + "
\n", + "\n", + "
\n", + "

\n", + " Citation: Sterne, Laurence. The Life and Opinions of Tristram Shandy, \n", + " Gentleman. Project Gutenberg. \n", + " \n", + " https://www.gutenberg.org/ebooks/1079\n", + " \n", + "

\n", + "
\n", + "\n", + " \n", + "\n", + "\n", + "\"\"\"\n", + " \n", + " filename = \"tristram_shandy_complete_analysis.html\"\n", + " with open(filename, 'w', encoding='utf-8') as f:\n", + " f.write(html_content)\n", + " \n", + " print(f\"✓ Complete HTML presentation saved: {filename}\")\n", + " return filename\n", + "\n", + "def main():\n", + " print(\"=\"*80)\n", + " print(\"TRISTRAM SHANDY: COMPLETE TEMPORAL ARCHITECTURE PIPELINE\")\n", + " print(\"Advanced Web Scraping + Dual-Panel Visualization + HTML Presentation\")\n", + " print(\"=\"*80 + \"\\n\")\n", + " \n", + " pipeline = TristramShandyCompletePipeline()\n", + " \n", + " # Step 1: Download\n", + " if not pipeline.download_book():\n", + " print(\"\\n✗ Failed to download. Exiting.\")\n", + " return\n", + " \n", + " # Step 2: Extract chapters\n", + " pipeline.extract_chapters()\n", + " \n", + " # Step 3: Annotate with intelligent quotation extraction\n", + " pipeline.annotate_chapters()\n", + " \n", + " # Step 4: Create visualization\n", + " fig = pipeline.create_visualization()\n", + " \n", + " # Step 5: Generate comprehensive HTML presentation\n", + " html_file = pipeline.create_html_presentation(fig)\n", + " \n", + " # Success\n", + " print(\"\\n\" + \"=\"*80)\n", + " print(\"✓ COMPLETE PIPELINE FINISHED\")\n", + " print(\"=\"*80)\n", + " print(f\"\\n📄 Open this file in your browser: {html_file}\")\n", + " print(\"\\nWhat you'll find:\")\n", + " print(\" • Comprehensive explanatory sections\")\n", + " print(\" • Dual-panel temporal architecture visualization\")\n", + " print(\" • Interactive quotations on hover\")\n", + " print(\" • Complete methodology and dataset summary\")\n", + " print(\"\\nThe structure of non-linear time is now visible.\")\n", + " print(\"=\"*80 + \"\\n\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94c7c0c1-f5de-4ba7-9b83-eae8a41d5c4a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Mini Project Data Capstone V8.md b/Mini Project Data Capstone V8.md new file mode 100644 index 0000000..f21f002 --- /dev/null +++ b/Mini Project Data Capstone V8.md @@ -0,0 +1,873 @@ +```python +""" +COMPLETE TRISTRAM SHANDY PIPELINE WITH HTML PRESENTATION +========================================================== + +This script: +1. Scrapes full text with intelligent quotation extraction +2. Creates dual-panel temporal architecture visualization +3. Generates comprehensive HTML page with explanatory sections + +Run this single script for the complete digital humanities presentation. +""" + +import requests +from bs4 import BeautifulSoup +import pandas as pd +import re +import json +from typing import List, Dict +import plotly.graph_objects as go +from plotly.subplots import make_subplots + +class TristramShandyCompletePipeline: + def __init__(self): + self.url = "https://www.gutenberg.org/files/1079/1079-h/1079-h.htm" + self.html_content = None + self.chapters = [] + self.annotated_data = [] + + # Narrative time buckets + self.time_buckets = { + "dinah": { + "keywords": ["aunt dinah", "great aunt", "coachman", "family disgrace"], + "character_markers": ["dinah"], + "description": "Aunt Dinah's scandal", + "chronological_order": -4 + }, + "yorick_life": { + "keywords": ["yorick", "parson yorick", "denmark", "danish", "hamlet"], + "character_markers": ["yorick", "eugenius"], + "description": "Parson Yorick's life", + "chronological_order": -3 + }, + "toby_namur": { + "keywords": ["namur", "siege", "wound", "wounded", "groin", "flanders", "battle"], + "character_markers": ["toby", "uncle toby"], + "description": "Namur", + "chronological_order": -2 + }, + "toby_recovery": { + "keywords": ["fortification", "fortifications", "bowling green", "trim", + "corporal trim", "hobby-horse", "ramparts", "sieges"], + "character_markers": ["toby", "trim", "uncle toby", "corporal"], + "description": "Toby Recovery", + "chronological_order": -1 + }, + "conception": { + "keywords": ["conception", "begot", "begetting", "homunculus", "animal spirits", + "clock", "wind up"], + "character_markers": ["father", "mother"], + "description": "Conception", + "chronological_order": 1 + }, + "birth": { + "keywords": ["birth", "born", "midwife", "dr. slop", "slop", "delivery", + "forceps", "nose", "crushed"], + "character_markers": ["slop", "susannah", "mother"], + "description": "Birth", + "chronological_order": 2 + }, + "christening": { + "keywords": ["christening", "christened", "trismegistus", "baptism", "baptized", "name"], + "character_markers": ["curate"], + "description": "Christening", + "chronological_order": 3 + }, + "childhood_accidents": { + "keywords": ["circumcision", "window", "sash", "susannah", "accident"], + "character_markers": ["susannah", "obadiah"], + "description": "Childhood Accidents", + "chronological_order": 4 + }, + "childhood_education": { + "keywords": ["tristrapoedia", "governor", "education", "tutor"], + "character_markers": [], + "description": "Childhood Education", + "chronological_order": 5 + }, + "toby_wadman": { + "keywords": ["widow wadman", "wadman", "amours", "courtship", "love", "bridget"], + "character_markers": ["widow wadman", "bridget"], + "description": "Toby & Wadman", + "chronological_order": 7 + }, + "tristram_writing": { + "keywords": ["dear reader", "writing", "pen", "author", "narrative", "i am writing"], + "character_markers": ["dear sir", "reader"], + "description": "Tristram Writing", + "chronological_order": 10 + }, + "meta_commentary": { + "keywords": ["preface", "digression", "chapter about", "critic", "book"], + "character_markers": [], + "description": "Meta-commentary", + "chronological_order": 11 + }, + "walter_theories": { + "keywords": ["theory", "hypothesis", "auxiliary verbs", "nose theory", "names"], + "character_markers": ["father", "walter"], + "description": "Walter's Theories", + "chronological_order": 0 + }, + "slawkenbergius": { + "keywords": ["slawkenbergius", "strasbourg", "julia", "stranger"], + "character_markers": ["slawkenbergius"], + "description": "Slawkenbergius", + "chronological_order": 0 + }, + "sermon": { + "keywords": ["sermon", "conscience", "ernulphus", "preached"], + "character_markers": [], + "description": "Sermon", + "chronological_order": 0 + } + } + + # Color scheme + self.narrative_colors = { + 'tristram_writing': '#FF8C42', + 'toby_recovery': '#7FB069', + 'birth': '#4ECDC4', + 'toby_wadman': '#9B59B6', + 'toby_namur': '#E74C3C', + 'childhood_accidents': '#95A5A6', + 'conception': '#F1C40F', + 'meta_commentary': '#E67E22', + 'sermon': '#8E44AD', + 'walter_theories': '#C39BD3', + 'slawkenbergius': '#D7BDE2', + 'dinah': '#CB4335', + 'christening': '#45B7D1', + 'yorick_life': '#5DADE2', + 'childhood_education': '#F8B739' + } + + def download_book(self) -> bool: + print("Downloading Tristram Shandy from Project Gutenberg...") + try: + response = requests.get(self.url, timeout=30) + response.raise_for_status() + self.html_content = response.text + print(f"✓ Downloaded ({len(self.html_content)} characters)") + return True + except Exception as e: + print(f"✗ Error: {e}") + return False + + def extract_chapters(self): + print("Extracting chapters with full content...") + soup = BeautifulSoup(self.html_content, 'html.parser') + text_content = soup.get_text() + + chapter_pattern = re.compile(r'C\s*H\s*A\s*P\.?\s+([IVXLCDM]+)', re.IGNORECASE) + matches = list(chapter_pattern.finditer(text_content)) + + for i, match in enumerate(matches): + chapter_num_roman = match.group(1) + chapter_num = self._roman_to_int(chapter_num_roman) + start = match.end() + end = matches[i + 1].start() if i + 1 < len(matches) else len(text_content) + + content = text_content[start:end] + content = re.sub(r'\s+', ' ', content).strip() + content = re.sub(r'\[Pg \d+\]', '', content) + + if len(content) > 200: + self.chapters.append({ + 'chapter': chapter_num, + 'chapter_roman': chapter_num_roman, + 'content': content + }) + + print(f"✓ Extracted {len(self.chapters)} chapters") + + def _roman_to_int(self, roman: str) -> int: + roman = roman.upper().strip() + roman_values = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + total = 0 + prev_value = 0 + for char in reversed(roman): + value = roman_values.get(char, 0) + if value >= prev_value: + total += value + else: + total -= value + prev_value = value + return total + + def extract_candidate_quotations(self, content: str) -> List[Dict]: + """Extract scored candidate quotations.""" + sentences = re.split(r'(?<=[.!?])\s+', content) + candidates = [] + + for i, sentence in enumerate(sentences): + if len(sentence) < 40 or len(sentence) > 400: + continue + if re.match(r'^(Chapter|CHAP|Vol)', sentence, re.IGNORECASE): + continue + + score = 0 + sentence_lower = sentence.lower() + + # Character names + character_names = ['toby', 'trim', 'yorick', 'walter', 'slop', 'susannah', + 'obadiah', 'dinah', 'wadman', 'bobby'] + for name in character_names: + if name in sentence_lower: + score += 2 + + # Temporal markers + temporal_markers = ['when', 'after', 'before', 'during', 'since', 'until'] + for marker in temporal_markers: + if marker in sentence_lower: + score += 1 + + # Dialogue + if '"' in sentence: + score += 1 + + candidates.append({'text': sentence.strip(), 'score': score}) + + return candidates + + def select_representative_quotation(self, content: str, narrative_bucket: str) -> str: + """Select most representative quotation using keyword matching.""" + candidates = self.extract_candidate_quotations(content) + + if not candidates: + return content[:200] + "..." + + bucket_info = self.time_buckets.get(narrative_bucket, {}) + keywords = bucket_info.get('keywords', []) + character_markers = bucket_info.get('character_markers', []) + + # Score by relevance to narrative bucket + for candidate in candidates: + quote_lower = candidate['text'].lower() + relevance = 0 + + for keyword in keywords: + if keyword.lower() in quote_lower: + relevance += 3 + + for character in character_markers: + if character.lower() in quote_lower: + relevance += 2 + + candidate['relevance'] = relevance + candidate['score'] + + candidates.sort(key=lambda x: x['relevance'], reverse=True) + return candidates[0]['text'] if candidates else content[:200] + "..." + + def annotate_chapters(self): + print("Annotating chapters with narrative periods and selecting quotations...") + + for idx, chapter in enumerate(self.chapters): + content_lower = chapter['content'].lower() + + bucket_scores = {} + for bucket_name, bucket_info in self.time_buckets.items(): + score = 0 + for keyword in bucket_info['keywords']: + score += content_lower.count(keyword.lower()) * 2 + for character in bucket_info.get('character_markers', []): + score += content_lower.count(character.lower()) * 3 + if score > 0: + bucket_scores[bucket_name] = score + + primary_bucket = max(bucket_scores, key=bucket_scores.get) if bucket_scores else 'tristram_writing' + bucket_info = self.time_buckets[primary_bucket] + + representative_quote = self.select_representative_quotation(chapter['content'], primary_bucket) + + self.annotated_data.append({ + 'chapter': chapter['chapter'], + 'chapter_roman': chapter['chapter_roman'], + 'reading_order': idx + 1, + 'chronological_position': bucket_info['chronological_order'], + 'narrative_period': primary_bucket, + 'narrative_description': bucket_info['description'], + 'representative_quote': representative_quote + }) + + print(f"✓ Annotated {len(self.annotated_data)} chapters with quotations") + + def create_visualization(self) -> go.Figure: + """Create the dual-panel temporal architecture visualization.""" + print("\nCreating dual-panel visualization...") + + df = pd.DataFrame(self.annotated_data) + df['color'] = df['narrative_period'].map(self.narrative_colors).fillna('#95A5A6') + + # Create dual-panel figure + fig = make_subplots( + rows=2, cols=1, + row_heights=[0.75, 0.25], # Give more space to top panel + vertical_spacing=0.10, # Slightly reduced spacing + subplot_titles=( + 'Narrative Path of "Tristram Shandy"', + 'Chronological Distribution' + ), + specs=[[{"type": "scatter"}], [{"type": "bar"}]] + ) + + # TOP PANEL: Connected line graph + for i in range(len(df) - 1): + fig.add_trace( + go.Scatter( + x=[df.iloc[i]['reading_order'], df.iloc[i+1]['reading_order']], + y=[df.iloc[i]['chronological_position'], df.iloc[i+1]['chronological_position']], + mode='lines', + line=dict(color=df.iloc[i]['color'], width=1.5), # Reduced from 2 to 1.5 + showlegend=False, + hoverinfo='skip' + ), + row=1, col=1 + ) + + # Add markers with quotations + for period in df['narrative_period'].unique(): + period_data = df[df['narrative_period'] == period] + + fig.add_trace( + go.Scatter( + x=period_data['reading_order'], + y=period_data['chronological_position'], + mode='markers', + marker=dict( + size=6, # Reduced from 7 to 6 for less visual clutter + color=self.narrative_colors.get(period, '#95A5A6'), + line=dict(width=0.5, color='white') + ), + name=period_data.iloc[0]['narrative_description'] if len(period_data) > 0 else period, + text=period_data.apply( + lambda row: f"Chapter {row['chapter']}
" + + f"Period: {row['narrative_description']}

" + + f"\"{row['representative_quote'][:200]}{'...' if len(row['representative_quote']) > 200 else ''}\"", + axis=1 + ), + hovertemplate='%{text}', + legendgroup=period + ), + row=1, col=1 + ) + + # Add temporal labels + fig.add_annotation(x=10, y=-4, text="-4 Past", showarrow=False, + font=dict(size=10, color='#7F8C8D'), xanchor='left', row=1, col=1) + fig.add_annotation(x=10, y=0, text="0 Digressions", showarrow=False, + font=dict(size=10, color='#7F8C8D'), xanchor='left', row=1, col=1) + fig.add_annotation(x=10, y=11, text="11 Present", showarrow=False, + font=dict(size=10, color='#7F8C8D'), xanchor='left', row=1, col=1) + + # BOTTOM PANEL: Distribution bars + chronological_counts = df.groupby(['chronological_position', 'narrative_period']).size().reset_index(name='count') + positions = sorted(df['chronological_position'].unique()) + + for period in df['narrative_period'].unique(): + period_counts = [] + for pos in positions: + count = chronological_counts[ + (chronological_counts['chronological_position'] == pos) & + (chronological_counts['narrative_period'] == period) + ]['count'].sum() + period_counts.append(count) + + fig.add_trace( + go.Bar( + x=positions, + y=period_counts, + name=df[df['narrative_period'] == period].iloc[0]['narrative_description'] if len(df[df['narrative_period'] == period]) > 0 else period, + marker_color=self.narrative_colors.get(period, '#95A5A6'), + showlegend=False, + legendgroup=period + ), + row=2, col=1 + ) + + # Layout + fig.update_xaxes( + title_text="Reading Order (Chapters)", + showgrid=True, + gridwidth=0.3, # Thinner gridlines + gridcolor='rgba(200,200,200,0.25)', # Lighter gridlines + range=[0, df['reading_order'].max() + 10], # Add padding on right + row=1, col=1 + ) + fig.update_yaxes( + title_text="Chronological Position", + showgrid=True, + gridwidth=0.3, # Thinner gridlines + gridcolor='rgba(200,200,200,0.25)', # Lighter gridlines + zeroline=True, + zerolinewidth=1, + zerolinecolor='rgba(100,100,100,0.4)', + tickmode='linear', + tick0=-4, + dtick=1, + range=[-5, 12], # Add padding top and bottom + row=1, col=1 + ) + fig.update_xaxes( + title_text="Chronological Position", + tickmode='linear', + tick0=-4, + dtick=1, + row=2, col=1 + ) + fig.update_yaxes( + title_text="Number of Chapters", + row=2, col=1 + ) + + fig.update_layout( + height=800, + width=1800, # Increased width for more horizontal space + plot_bgcolor='white', + paper_bgcolor='white', + font=dict(family="Arial, sans-serif", size=11), + title_font=dict(size=16, color='#2C3E50'), + hovermode='closest', + margin=dict(l=80, r=250, t=80, b=60), + legend=dict( + title=dict(text="Narrative Periods", font=dict(size=11)), + orientation="v", + yanchor="top", + y=0.95, + xanchor="left", + x=1.01, + bgcolor="rgba(255,255,255,0.9)", + bordercolor="#BDC3C7", + borderwidth=1, + font=dict(size=9) + ), + barmode='stack' + ) + + print("✓ Visualization created") + return fig + + def create_html_presentation(self, fig: go.Figure): + """Generate comprehensive HTML page with explanatory sections.""" + print("\nGenerating comprehensive HTML presentation...") + + df = pd.DataFrame(self.annotated_data) + + html_content = """ + + + + Tristram Shandy: Temporal Architecture Analysis + + + + +
+

THE LIFE AND OPINIONS OF TRISTRAM SHANDY, GENTLEMAN

+

by Laurence Sterne (1759-1767)

+

+ A Digital Humanities Analysis of Non-Linear Narrative Structure +

+
+ +
+

About the Novel

+

+ The Life and Opinions of Tristram Shandy, Gentleman is one of literature's + first experimental novels and a masterpiece of non-linear storytelling. The narrator, + Tristram, attempts to tell his life story but constantly digresses into tangents, + backstories, and philosophical musings. The result is a chaotic, playful narrative + that jumps backward and forward in time. +

+
+ 💡 Key Insight: Tristram famously doesn't even get to his own birth + until Volume 3 — he's too busy telling us about everything that led up to it! The + novel's structure itself becomes an argument about memory, digression, and the + impossibility of linear self-narration. +
+
+ +
+

The Dual-Panel Visualization Explained

+

+ This is not a generic timeline. It is a temporal architecture visualization + designed to make the novel's non-chronological structure legible. The visualization consists + of two synchronized panels: +

+ +

Top Panel: Narrative Path Timeline

+
    +
  • X-axis: Reading Order (Chapters 1–300 sequentially)
  • +
  • Y-axis: Chronological Position (when events actually occur: -4 to 11)
  • +
  • Connected Line: Shows the temporal path a reader takes through the narrative
  • +
  • Color-Coded Dots: Each chapter colored by its narrative period
  • +
  • Hover Interaction: Displays representative quotations from each chapter
  • +
+

+ If the novel were linear, the line would ascend steadily from bottom-left + to top-right. Instead, you see dramatic vertical jumps—Sterne constantly yanking the reader + backward and forward through time. +

+ +

Bottom Panel: Chronological Distribution

+

+ A stacked bar chart showing how many chapters occupy each chronological position. This reveals + where the novel dwells chronologically—notice how much time Sterne spends on "present + narration" (position 10) compared to actual life events. +

+
+ +
+

Understanding the Chronological Scale

+ +
+
+ -4 to -1 +
Before Tristram's Birth
+ Family history, Uncle Toby's war injury at Namur, Parson Yorick's life and death +
+ +
+ 0 +
Digressions
+ Timeless stories-within-stories, philosophical theories, embedded tales like Slawkenbergius +
+ +
+ 1 to 8 +
Tristram's Life
+ Conception → Birth → Christening → Childhood → Youth (chronological progression) +
+ +
+ 10-11 +
Present Narrative
+ Tristram writing the book, meta-commentary on the act of storytelling itself +
+
+ +

Why Negative Numbers?

+

+ Tristram doesn't start his story at his birth — he goes backward to tell us about + his family's history first. Uncle Toby's war wound at the Siege of Namur happened years + before Tristram was conceived, so it gets a negative chronological position (-2). + Think of position 0 as Tristram's birth (the origin point), with negative numbers representing + the years before that event. This shows how far back in time the narrative reaches before + the protagonist even exists. +

+
+ +
+

What the Visualization Reveals

+
    +
  • The connected line traces the reader's journey through narrative time—every + vertical movement is a temporal jump
  • +
  • Steep drops reveal flashbacks to pre-birth history (e.g., from present + narration back to Uncle Toby at Namur)
  • +
  • Steep rises show returns to the present narrative frame
  • +
  • Horizontal plateaus indicate sustained focus on a single time period + across multiple chapters
  • +
  • Frequency of crossings at y=0 shows how often Sterne interrupts with + timeless digressions
  • +
  • Bottom panel density reveals that Sterne spends disproportionate time + on "present narration" rather than life events
  • +
+
+ 💡 Literary Significance: The visualization quantifies narrative disorder. + A linear biography would show a smooth upward slope. Sterne's jagged line—with its wild + oscillations between past, present, and digression—reveals a narrator unable or unwilling + to tell his story in chronological order. The structure itself becomes an argument + about memory, digression, and the impossibility of linear self-narration. +
+
+ +
+

Interactive Temporal Architecture

+

+ How to interact: Hover over any point to see chapter details and representative + quotations. Click and drag to zoom into specific regions. Double-click to reset the view. + The line connects chapters in reading order—watch how it oscillates through time. +

+
+
+ +
+

Methodology

+ +
+

Data Collection & Processing

+

Source: Full text from Project Gutenberg

+

Chapters Analyzed: """ + str(len(df)) + """

+

Quotation Selection: Automated intelligent extraction based on:

+
    +
  • Temporal markers (when, after, before, during)
  • +
  • Character name relevance to narrative period
  • +
  • Keyword matching to narrative buckets
  • +
  • Sentence quality (50-400 characters, avoids fragments)
  • +
+
+ +

Dataset Summary

+

Total chapters analyzed: """ + str(len(df)) + """

+

Reading order range: 1 to """ + str(df['reading_order'].max()) + """

+

Chronological range: """ + str(df['chronological_position'].min()) + """ to """ + str(df['chronological_position'].max()) + """

+ +

Narrative Period Distribution

+ + + + + + +""" + + for bucket, count in df['narrative_period'].value_counts().items(): + chrono_pos = df[df['narrative_period'] == bucket].iloc[0]['chronological_position'] + description = df[df['narrative_period'] == bucket].iloc[0]['narrative_description'] + html_content += f""" + + + + +""" + + html_content += """
Narrative PeriodNumber of ChaptersChronological Position
{description}{count}{chrono_pos}
+
+ +
+

+ Citation: Sterne, Laurence. The Life and Opinions of Tristram Shandy, + Gentleman. Project Gutenberg. + + https://www.gutenberg.org/ebooks/1079 + +

+
+ + + + +""" + + filename = "tristram_shandy_complete_analysis.html" + with open(filename, 'w', encoding='utf-8') as f: + f.write(html_content) + + print(f"✓ Complete HTML presentation saved: {filename}") + return filename + +def main(): + print("="*80) + print("TRISTRAM SHANDY: COMPLETE TEMPORAL ARCHITECTURE PIPELINE") + print("Advanced Web Scraping + Dual-Panel Visualization + HTML Presentation") + print("="*80 + "\n") + + pipeline = TristramShandyCompletePipeline() + + # Step 1: Download + if not pipeline.download_book(): + print("\n✗ Failed to download. Exiting.") + return + + # Step 2: Extract chapters + pipeline.extract_chapters() + + # Step 3: Annotate with intelligent quotation extraction + pipeline.annotate_chapters() + + # Step 4: Create visualization + fig = pipeline.create_visualization() + + # Step 5: Generate comprehensive HTML presentation + html_file = pipeline.create_html_presentation(fig) + + # Success + print("\n" + "="*80) + print("✓ COMPLETE PIPELINE FINISHED") + print("="*80) + print(f"\n📄 Open this file in your browser: {html_file}") + print("\nWhat you'll find:") + print(" • Comprehensive explanatory sections") + print(" • Dual-panel temporal architecture visualization") + print(" • Interactive quotations on hover") + print(" • Complete methodology and dataset summary") + print("\nThe structure of non-linear time is now visible.") + print("="*80 + "\n") + +if __name__ == "__main__": + main() +``` + + ================================================================================ + TRISTRAM SHANDY: COMPLETE TEMPORAL ARCHITECTURE PIPELINE + Advanced Web Scraping + Dual-Panel Visualization + HTML Presentation + ================================================================================ + + Downloading Tristram Shandy from Project Gutenberg... + ✓ Downloaded (1259736 characters) + Extracting chapters with full content... + ✓ Extracted 300 chapters + Annotating chapters with narrative periods and selecting quotations... + ✓ Annotated 300 chapters with quotations + + Creating dual-panel visualization... + ✓ Visualization created + + Generating comprehensive HTML presentation... + ✓ Complete HTML presentation saved: tristram_shandy_complete_analysis.html + + ================================================================================ + ✓ COMPLETE PIPELINE FINISHED + ================================================================================ + + 📄 Open this file in your browser: tristram_shandy_complete_analysis.html + + What you'll find: + • Comprehensive explanatory sections + • Dual-panel temporal architecture visualization + • Interactive quotations on hover + • Complete methodology and dataset summary + + The structure of non-linear time is now visible. + ================================================================================ + + + + +```python + +``` diff --git a/tristram_final_fixed.Rmd b/tristram_final_fixed.Rmd new file mode 100644 index 0000000..57e28e5 --- /dev/null +++ b/tristram_final_fixed.Rmd @@ -0,0 +1,512 @@ +--- +title: "Mapping Narrative Time in Tristram Shandy" +subtitle: "A Computational Model of Temporal Digression" +author: "David Whitmer" +institute: "Dickinson College | Data Capstone 400 Mini Project" +date: "February 17, 2026" +output: + xaringan::moon_reader: + lib_dir: libs + nature: + highlightStyle: github + highlightLines: true + countIncrementalSlides: false + ratio: "16:9" + css: [default, default-fonts] +--- + +```{r setup, include=FALSE} +options(htmltools.dir.version = FALSE) +knitr::opts_chunk$set(echo = FALSE, warning = FALSE, message = FALSE) +library(knitr) +``` + +```{css, echo=FALSE} +.title-slide { + background-color: #ffffff; + color: #000000; +} + +.title-slide h1 { + font-size: 2.5em; + font-weight: 600; + margin-bottom: 0.3em; + color: #000000; +} + +.title-slide h2 { + font-size: 1.5em; + font-weight: 300; + margin-bottom: 1em; + color: #000000; +} + +.title-slide h3 { + font-size: 1.2em; + font-weight: 400; + margin-top: 2em; + color: #000000; +} + +.remark-slide-content { + font-size: 24px; + padding: 1em 2em 1em 2em; +} + +.remark-slide-content h1 { + font-size: 2em; + color: #2c3e50; + margin-bottom: 0.5em; +} + +.remark-slide-content h2 { + font-size: 1.5em; + color: #34495e; + margin-bottom: 0.5em; +} + +.large { + font-size: 1.3em; +} + +.medium { + font-size: 1.1em; +} + +.small { + font-size: 0.9em; +} + +.pull-left-narrow { + float: left; + width: 35%; +} + +.pull-right-wide { + float: right; + width: 60%; +} + +.highlight-box { + background-color: #fff3cd; + border-left: 5px solid #ffc107; + padding: 15px; + margin: 15px 0; +} + +.key-point { + background-color: #e3f2fd; + border-left: 5px solid #2196f3; + padding: 15px; + margin: 15px 0; + font-weight: 500; +} + +.methodology { + background-color: #f5f5f5; + padding: 15px; + border-radius: 5px; + margin: 10px 0; +} + +.timeline-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 15px; + margin: 20px 0; +} + +.timeline-item { + padding: 15px; + border-radius: 5px; + border-left: 4px solid; + font-size: 0.85em; +} + +.timeline-item strong { + display: block; + font-size: 1.3em; + margin-bottom: 5px; +} + +.pre-birth { + background-color: #e3f2fd; + border-color: #2196f3; +} + +.digressions { + background-color: #fff9e6; + border-color: #ffc107; +} + +.life { + background-color: #e8f5e9; + border-color: #4caf50; +} + +.present { + background-color: #f3e5f5; + border-color: #9c27b0; +} +``` + + + +# The Problem of Narrative Time: + +.large[ +Tristram Shandy attempts to tell his life story but **never arrives at the present** +] + +-- + +.highlight-box[ +By Volume 4, Tristram has covered only **one day** of his life + +Yet the novel spans **9 volumes** and **~300 chapters** +] + +-- + +.medium[ +**The central question:** +How does Sterne's temporal disorder function as narrative structure? +] + +??? +Speaker notes: +- Published 1759-1767, revolutionary experimental novel +- Narrator constantly digresses backward and forward in time +- Not random chaos—there's a pattern we can computationally model +- This talk shows how data visualization makes temporal structure visible + +--- + +# Why Linear Chronology Fails + +.pull-left-narrow[ +### Traditional Biography +- Birth → Childhood → Youth → Death +- Chronological progression +- Linear narrative arc +] + +.pull-right-wide[ +### Tristram Shandy +- Begins with conception... +- ...then jumps to Uncle Toby's war injury **decades earlier** +- ...then to Yorick's death **years before birth** +- ...then to present-day writing +- ...then back to childhood accidents +- **No sustained chronological sequence** +] + +-- + +.key-point[ +**Sterne's structure is not broken—it's deliberate** +Digression becomes the primary narrative mode +] + +??? +Speaker notes: +- Traditional autobiography: Franklin, Rousseau follow chronological order +- Sterne deliberately frustrates this expectation +- The digressions ARE the point—not obstacles to the "real" story +- Question: Can we map this disorder systematically? + +--- + +# Data Collection & Web Scraping Pipeline + +.methodology[ +**Source:** Project Gutenberg full text (HTML) +**Method:** Python web scraping with BeautifulSoup +] + +-- + +### Pipeline Architecture + +1. **Chapter Extraction** + - Regex pattern matching: `C H A P. [Roman numeral]` + - 300+ chapters across 9 volumes + - Full text preservation + +-- + +2. **Intelligent Quotation Selection** + - Temporal markers & character names + - Keyword matching to narrative period + +--- +# Narrative Classification System + +3\. **Narrative Classification** + - 18 time period categories + - Chronological position (-4 to 11) + +??? +Speaker notes: +- Not manual coding—fully automated and reproducible +- Quotation algorithm selects contextually relevant excerpts +- Each chapter gets chronological position based on story time +- Output: structured JSON with 300 annotated chapters + +--- + +# Modeling Time: The -4 to 11 Scale + +.timeline-grid[ +.timeline-item.pre-birth[ +**-4 to -1** +Before Birth +Family history, Namur, Yorick +] + +.timeline-item.digressions[ +**0** +Digressions +Timeless embedded narratives +] + +.timeline-item.life[ +**1 to 8** +Tristram's Life +Conception → Youth +] + +.timeline-item.present[ +**10-11** +Present +Tristram writing, meta-commentary +] +] + +-- + +.highlight-box[ +**Key Innovation:** Negative numbers represent *years before birth* + +Position -2 = Uncle Toby wounded at Namur (decades before Tristram exists) +Position 0 = Digressions outside story time +Position 10 = Present-day narration +] + +-- + +.medium[ +**This allows us to plot:** Reading Order (1–300) vs. Chronological Position (-4 to 11) +] + +??? +Speaker notes: +- Not arbitrary—based on actual temporal relationships in text +- Negative scale shows how far back Sterne reaches +- Zero marks timeless philosophical asides +- Positive numbers follow life chronology +- Creates two-dimensional temporal map + +--- + +# Visualization Architecture + +### Dual-Panel Design + +.pull-left[ +**Top Panel: Narrative Path** +- X-axis: Reading order (1→300) +- Y-axis: Chronological position +- Connected line = reader's path through time +- Color-coded by narrative period +] + +.pull-right[ +**Bottom Panel: Distribution** +- Shows density at each position +- Reveals where novel "dwells" +- Stacked bars by period +] + +-- + +.key-point[ +**If the novel were linear:** smooth diagonal line +**What we actually see:** wild temporal oscillation +] + +??? +Speaker notes: +- Two complementary views of same data +- Top: shows temporal MOVEMENT (reader's journey) +- Bottom: shows temporal DENSITY (where Sterne lingers) +- Not decorative—reveals structure of delay +- Every vertical jump = temporal disruption + +--- +class: center, middle + +# Interactive Narrative Model + +```{r, echo=FALSE, out.width="100%"} +knitr::include_graphics("newplot.png") +``` + +.footnote[ +Dual-panel temporal architecture visualization +] + +??? +Speaker notes: +- This is the actual working model +- Notice the jagged line—not smooth progression +- Hover over points to see quotations from chapters +- Bottom panel shows Sterne spends ~80 chapters at position 10 (present) +- But spreads life events thinly across positive positions +- Pattern visible: oscillation between past/present/digression + +--- + +# Key Insights from the Model + +### Quantified Temporal Disruption + +-- + +1. **Oscillation Pattern** + - Novel jumps constantly: past (-4) → present (10) → digression (0) + - No sustained chronological progression + - Average jump magnitude: **6 chronological positions** + +-- + +2. **Narrative Density** + - **~80 chapters** at position 10 (present narration) + - Only **~40 chapters** cover positions 1-8 (entire life) + - **Present overwhelms chronology** by 2:1 ratio + +-- + +3. **Structured Delay** + - Toby's story split across positions -2, -1, and 7 + - Birth delayed until reading order ~60 + - Childhood scattered non-consecutively + +-- + +.highlight-box[ +**Finding:** Digressions are not chaos—they form a **temporal architecture** +] + +??? +Speaker notes: +- These are empirical findings from the data +- Not impressionistic—computationally measured +- The 2:1 ratio quantifies the "problem" of Tristram Shandy +- More time spent commenting than narrating +- This is the architecture of delay made visible + +--- + +# What This Reveals About Sterne + +.large[ +**Thesis:** Sterne's digressions are **structural**, not ornamental +] + +-- + +### Three Interpretive Claims: + +-- + +1. **Memory operates non-linearly** + - Flashbacks interrupt forward progress + - Past intrudes on present constantly + - The visualization **models memory itself** + +-- + +2. **Narration is impossible** + - To tell one story requires telling ten others + - Each explanation demands further backstory + - The act of writing **delays the story indefinitely** + +-- + +3. **Form enacts argument** + - Structure performs the impossibility of autobiography + +??? +Speaker notes: +- Not just showing disorder—arguing disorder is meaningful +- Visualization proves form and content are inseparable +- Sterne demonstrates autobiography is always incomplete +- Each digression reveals narrative as construct +- Modern readers frustrated by this—18th century readers delighted + +--- + +# Conclusion + +.pull-left[ +### What I Built +- Web scraping pipeline +- 300-chapter dataset +- Chronological coding +- Interactive visualization +- Hoverable quotations +] + +.pull-right[ +### What I Learned +- Temporal disorder is **systematic** +- Digressions form **architecture** +- Visualization makes **structure visible** +- Computational methods reveal **literary patterns** +] + +-- + +.key-point.large[ +**Core finding:** +Tristram Shandy's "chaos" is actually a **quantifiable oscillation** +The jagged line reveals the **structure of delay** +] + +??? +Speaker notes: +- Started with question: how does temporal disorder work? +- Answer: it's patterned, measurable, visualizable +- DH methods don't replace close reading—they enable new close reading +- We can now SEE the structure Sterne built +- This approach applies to any non-linear narrative +- Questions? + +--- +class: center, middle + +# Thank You + +.large[ +**Questions?** +] + +.medium[ +David Whitmer +Dickinson College +Data Capstone 400 +] + +.center[ +.small[ +Project code and visualization available upon request +Source: Sterne, Laurence. *The Life and Opinions of Tristram Shandy, Gentleman*. Project Gutenberg. +] +] + +??? +Speaker notes: +- Open to questions about methodology, findings, or technical implementation +- Happy to discuss extensions: other non-linear novels, comparative analysis +- All code is reproducible and available diff --git a/tristram_shandy_complete_analysis.html b/tristram_shandy_complete_analysis.html new file mode 100644 index 0000000..75f42c7 --- /dev/null +++ b/tristram_shandy_complete_analysis.html @@ -0,0 +1,380 @@ + + + + + Tristram Shandy: Temporal Architecture Analysis + + + + +
+

THE LIFE AND OPINIONS OF TRISTRAM SHANDY, GENTLEMAN

+

by Laurence Sterne (1759-1767)

+

+ A Digital Humanities Analysis of Non-Linear Narrative Structure +

+
+ +
+

About the Novel

+

+ The Life and Opinions of Tristram Shandy, Gentleman is one of literature's + first experimental novels and a masterpiece of non-linear storytelling. The narrator, + Tristram, attempts to tell his life story but constantly digresses into tangents, + backstories, and philosophical musings. The result is a chaotic, playful narrative + that jumps backward and forward in time. +

+
+ 💡 Key Insight: Tristram famously doesn't even get to his own birth + until Volume 3 — he's too busy telling us about everything that led up to it! The + novel's structure itself becomes an argument about memory, digression, and the + impossibility of linear self-narration. +
+
+ +
+

The Dual-Panel Visualization Explained

+

+ This is not a generic timeline. It is a temporal architecture visualization + designed to make the novel's non-chronological structure legible. The visualization consists + of two synchronized panels: +

+ +

Top Panel: Narrative Path Timeline

+
    +
  • X-axis: Reading Order (Chapters 1–300 sequentially)
  • +
  • Y-axis: Chronological Position (when events actually occur: -4 to 11)
  • +
  • Connected Line: Shows the temporal path a reader takes through the narrative
  • +
  • Color-Coded Dots: Each chapter colored by its narrative period
  • +
  • Hover Interaction: Displays representative quotations from each chapter
  • +
+

+ If the novel were linear, the line would ascend steadily from bottom-left + to top-right. Instead, you see dramatic vertical jumps—Sterne constantly yanking the reader + backward and forward through time. +

+ +

Bottom Panel: Chronological Distribution

+

+ A stacked bar chart showing how many chapters occupy each chronological position. This reveals + where the novel dwells chronologically—notice how much time Sterne spends on "present + narration" (position 10) compared to actual life events. +

+
+ +
+

Understanding the Chronological Scale

+ +
+
+ -4 to -1 +
Before Tristram's Birth
+ Family history, Uncle Toby's war injury at Namur, Parson Yorick's life and death +
+ +
+ 0 +
Digressions
+ Timeless stories-within-stories, philosophical theories, embedded tales like Slawkenbergius +
+ +
+ 1 to 8 +
Tristram's Life
+ Conception → Birth → Christening → Childhood → Youth (chronological progression) +
+ +
+ 10-11 +
Present Narrative
+ Tristram writing the book, meta-commentary on the act of storytelling itself +
+
+ +

Why Negative Numbers?

+

+ Tristram doesn't start his story at his birth — he goes backward to tell us about + his family's history first. Uncle Toby's war wound at the Siege of Namur happened years + before Tristram was conceived, so it gets a negative chronological position (-2). + Think of position 0 as Tristram's birth (the origin point), with negative numbers representing + the years before that event. This shows how far back in time the narrative reaches before + the protagonist even exists. +

+
+ +
+

What the Visualization Reveals

+
    +
  • The connected line traces the reader's journey through narrative time—every + vertical movement is a temporal jump
  • +
  • Steep drops reveal flashbacks to pre-birth history (e.g., from present + narration back to Uncle Toby at Namur)
  • +
  • Steep rises show returns to the present narrative frame
  • +
  • Horizontal plateaus indicate sustained focus on a single time period + across multiple chapters
  • +
  • Frequency of crossings at y=0 shows how often Sterne interrupts with + timeless digressions
  • +
  • Bottom panel density reveals that Sterne spends disproportionate time + on "present narration" rather than life events
  • +
+
+ 💡 Literary Significance: The visualization quantifies narrative disorder. + A linear biography would show a smooth upward slope. Sterne's jagged line—with its wild + oscillations between past, present, and digression—reveals a narrator unable or unwilling + to tell his story in chronological order. The structure itself becomes an argument + about memory, digression, and the impossibility of linear self-narration. +
+
+ +
+

Interactive Temporal Architecture

+

+ How to interact: Hover over any point to see chapter details and representative + quotations. Click and drag to zoom into specific regions. Double-click to reset the view. + The line connects chapters in reading order—watch how it oscillates through time. +

+
+
+ +
+

Methodology

+ +
+

Data Collection & Processing

+

Source: Full text from Project Gutenberg

+

Chapters Analyzed: 300

+

Quotation Selection: Automated intelligent extraction based on:

+
    +
  • Temporal markers (when, after, before, during)
  • +
  • Character name relevance to narrative period
  • +
  • Keyword matching to narrative buckets
  • +
  • Sentence quality (50-400 characters, avoids fragments)
  • +
+
+ +

Dataset Summary

+

Total chapters analyzed: 300

+

Reading order range: 1 to 300

+

Chronological range: -4 to 11

+ +

Narrative Period Distribution

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Narrative PeriodNumber of ChaptersChronological Position
Toby Recovery87-1
Namur55-2
Conception461
Tristram Writing4310
Birth242
Toby & Wadman127
Parson Yorick's life11-3
Childhood Accidents84
Slawkenbergius40
Meta-commentary411
Walter's Theories30
Aunt Dinah's scandal2-4
Sermon10
+
+ +
+

+ Citation: Sterne, Laurence. The Life and Opinions of Tristram Shandy, + Gentleman. Project Gutenberg. + + https://www.gutenberg.org/ebooks/1079 + +

+
+ + + +