From 9264ea2833d8665639a08544381820b158a8e63f Mon Sep 17 00:00:00 2001 From: Chris Parmer Date: Mon, 3 Aug 2026 22:16:51 -0700 Subject: [PATCH 1/3] SEO: update /graphing-libraries/ meta title and description From the "Plotly: Metadata Optimization" sheet (7/26), the row for https://plotly.com/graphing-libraries/: - title: "Plotly Open Source Graphing Libraries" -> "Open-Source Graphing Libraries for Python & JavaScript | Plotly" - description: now leads with the platforms people actually search for (Dash, Streamlit, Hex, Notebooks, LLMs) instead of listing every language binding. The page's permalink is /api/ and /graphing-libraries/ redirects to it, so both branches of the conditional are updated together. Verified with a local `jekyll build`: title renders at 63 chars, description at 157. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YM2aoEs6ZN6SNrw9udWEnm --- _includes/layouts/seo.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_includes/layouts/seo.html b/_includes/layouts/seo.html index 0f1abb169..39bb74dba 100755 --- a/_includes/layouts/seo.html +++ b/_includes/layouts/seo.html @@ -4,7 +4,7 @@ {% capture title %} {% if page.permalink == '/python/' or page.language == '/julia/' or page.language == '/r/' or page.language == '/ggplot2/' or page.language == '/f_sharp/' or page.language == '/matlab/' or page.language == '/javascript/' %}{{page.name}} {% elsif page.name == '404' %} 404 Page Not Found - {% elsif page.permalink == '/api/' or page.permalink == '/graphing-libraries/' %} Plotly Open Source Graphing Libraries + {% elsif page.permalink == '/api/' or page.permalink == '/graphing-libraries/' %} Open-Source Graphing Libraries for Python & JavaScript | Plotly {% elsif page.name %} {{page.name | capitalize}} in {{language}}{% else %} Plotly Open Source Graphing Libraries{% endif %} {% endcapture %} @@ -23,7 +23,7 @@ {% if page.layout == 'langindex' %} {% capture description %}{{page.description}}{% endcapture %} {% elsif page.permalink == '/api/' or page.permalink == '/graphing-libraries/' %} - {% capture description %}"Interactive charts and maps for Python, R, Julia, Javascript, ggplot2, F#, MATLABĀ®, and Dash."{% endcapture %} + {% capture description %}"Access interactive charts and maps for Python, and Javascript, for use with Dash, Streamlit, Hex, Notebooks and LLMs. Graphing libraries for data analytics."{% endcapture %} {% else %} {% assign counter = 0 %} {% for code_block in code_blocks %} From 4d134770f00f870175d8880014086a25a38d9d9a Mon Sep 17 00:00:00 2001 From: Chris Parmer Date: Mon, 3 Aug 2026 23:29:26 -0700 Subject: [PATCH 2/3] SEO: update /javascript/ meta title and description - title: "Plotly javascript graphing library in JavaScript" -> "Open Source JavaScript Graphing & Chart Library | Plotly" - description: "A" (!) -> "Build interactive JavaScript charts and graphs with Plotly's open-source JavaScript chart library. Explore over 40+ advanced JavaScript data visualizations." Two pre-existing bugs made the old values what they were. 1. The title condition on line 5 compares page.language against permalink-style values ('/julia/', '/r/', '/javascript/', ...), which can never match, so only the page.permalink == '/python/' arm ever fired. /javascript/ therefore fell through to "{{page.name | capitalize}} in {{language}}" -- and Liquid's capitalize downcases the rest of the string, producing "Plotly javascript graphing library in JavaScript". Rather than rewrite that condition (and risk changing other languages' titles), this adds an explicit /javascript/ arm above it. 2. The content= attributes were unquoted, so every description was truncated at its first space. /javascript/ served literally content=A. 530 of the 533 pages with a description tag were affected; the 3 that weren't are the branches that wrap their text in literal double quotes to compensate. This quotes all five title/description attributes and normalizes the captured values once (strip padding from the multi-line capture blocks, drop the now-redundant literal quotes). Verified with a full `jekyll build --config _config.yml` (the production config -- _config_dev.yml excludes _posts/plotly_js, so /javascript/ isn't built locally by default): /javascript/ title 56 chars, description 156 chars, both exact /api/ unchanged (63 / 157) /python/ title unchanged, description now complete at 258 chars /javascript/line-charts/ "Line charts in JavaScript" / "Over 33 examples..." Across all 1620 built HTML files: 0 unquoted description attributes remain (was 530 truncated), 0 word-collapse from the whitespace normalization, and 404.html's empty description is unchanged from before. front-matter-ci.py and all five check-or-enforce-order.py runs pass. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YM2aoEs6ZN6SNrw9udWEnm --- _includes/layouts/seo.html | 21 ++++++++++++++----- .../plotly_js/2015-04-05-plotly_js-index.html | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/_includes/layouts/seo.html b/_includes/layouts/seo.html index 39bb74dba..87df12095 100755 --- a/_includes/layouts/seo.html +++ b/_includes/layouts/seo.html @@ -4,6 +4,7 @@ {% capture title %} {% if page.permalink == '/python/' or page.language == '/julia/' or page.language == '/r/' or page.language == '/ggplot2/' or page.language == '/f_sharp/' or page.language == '/matlab/' or page.language == '/javascript/' %}{{page.name}} {% elsif page.name == '404' %} 404 Page Not Found + {% elsif page.permalink == '/javascript/' %} Open Source JavaScript Graphing & Chart Library | Plotly {% elsif page.permalink == '/api/' or page.permalink == '/graphing-libraries/' %} Open-Source Graphing Libraries for Python & JavaScript | Plotly {% elsif page.name %} {{page.name | capitalize}} in {{language}}{% else %} Plotly Open Source Graphing Libraries{% endif %} {% endcapture %} @@ -42,26 +43,36 @@ {% endif %} + +{% assign title = title | strip_newlines | strip | replace: '"', '' %} +{% assign description = description | strip_newlines | strip | replace: '"', '' %} + {{title}} - + - + - + - + - + diff --git a/_posts/plotly_js/2015-04-05-plotly_js-index.html b/_posts/plotly_js/2015-04-05-plotly_js-index.html index 1e7a81041..39630faec 100755 --- a/_posts/plotly_js/2015-04-05-plotly_js-index.html +++ b/_posts/plotly_js/2015-04-05-plotly_js-index.html @@ -1,7 +1,7 @@ --- name: Plotly JavaScript Graphing Library permalink: /javascript/ -description: A free open source interactive javascript graphing library. Plotly.js is built on d3.js and webgl and supports over 20 types of interactive charts. +description: Build interactive JavaScript charts and graphs with Plotly's open-source JavaScript chart library. Explore over 40+ advanced JavaScript data visualizations. language: plotly_js layout: langindex display_as: false From 1eb235716a79bbe1a08e606eec56404a59760807 Mon Sep 17 00:00:00 2001 From: Chris Parmer Date: Mon, 3 Aug 2026 23:41:01 -0700 Subject: [PATCH 3/3] Update /javascript/ home page copy and link affordances Applies the requested changes from the SEO doc plus Nick Hartsell's five review comments on it. Copy (from the doc): - H1: "Plotly JavaScript Open Source Graphing Library" -> "Open Source JavaScript Graphing & Chart Library", matching the new meta title. - "declarative charting library" -> "declarative JavaScript charting library" - "high performance 2D and 3D charting" -> "... 3D JavaScript charting" - "Most plotly graphs" -> "Most Plotly graphs" - Feature headings to title case: Sophisticated Chart Types, Fully Customizable, High Performance. - Oxford commas: "report issues, or contribute", "R, and MATLAB". - The collapsible section's summary becomes the "plotly.js Features" H2 from the doc, replacing "Read more about plotly.js features". Review comments: 1. "The link here is unnecessary i would remove it" -- dropped the /javascript/is-plotly-free link from "free and open source". (The sidebar nav entry for that page stays.) 2. "unclear ... that this is how you open a collapsible section" -- the global `summary::-webkit-details-marker { display:none !important }` hid the native triangle, and the replacement arrow was scoped to .--sidebar-fixed only, so this
had no affordance at all. Added a scoped arrow (rotates when open), pointer cursor, and underlined heading-sized text. 3. "not clear to users that these are clickable links" -- .langindexlink ("More Fundamentals >>" etc.) had text-decoration:none and a muted slate colour, underlining only on hover. Now underlined and blue by default. 4. "This links to a 410. Remove it" -- removed "view the interactive version". All four Chart Studio ~user/N.embed links on the page are in fact 410 (verified with curl), so the other three, which wrapped images, are unwrapped too: the images stay, the dead links go. 5. "all of these have self referencing on page links that serve no purpose" -- the 19 section headings in mainlang_documentation_eg.html were Text, linking to themselves. Now s that keep their id/name so the anchors still resolve. Extended the two a-scoped CSS rules (darkmode colour, ::before reset) to cover the spans. Note: scss/ is compiled to the tracked all_static/css/*.css by gulp, which needs Node <=11 and won't run here. The three rule changes were hand-applied to the compiled files in their existing nested style, then verified equal to `sass` output after normalising comments/whitespace/brace style -- the js-splash--features, langindexlink and section-header>span rules match the compiler byte for byte. A full recompile was deliberately avoided: it would rewrite all 1109 lines (2046 diff lines) and pick up unrelated pre-existing drift between scss/ and the committed css. Verified with a production-config build, then screenshotted collapsed and expanded: H1, arrow, blue underlined links and title-case headings all render, and the turbulence image still shows now that its dead link wrapper is gone. front-matter-ci.py and all five check-or-enforce-order.py runs pass. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YM2aoEs6ZN6SNrw9udWEnm --- .../posts/mainlang_documentation_eg.html | 38 ++++++------ .../plotly_js/2015-04-05-plotly_js-index.html | 29 ++++----- all_static/css/improve.css | 36 +++++++++-- all_static/css/main.css | 2 +- scss/_pages/_tutorial-index.scss | 3 +- scss/improve.scss | 59 +++++++++++++++++-- 6 files changed, 122 insertions(+), 45 deletions(-) diff --git a/_includes/posts/mainlang_documentation_eg.html b/_includes/posts/mainlang_documentation_eg.html index 0443c98b7..39f721d59 100644 --- a/_includes/posts/mainlang_documentation_eg.html +++ b/_includes/posts/mainlang_documentation_eg.html @@ -58,7 +58,7 @@ {% if file_settings %}
- Fundamentals + Fundamentals {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -96,7 +96,7 @@ {% if chart_type %}
- Basic Charts + Basic Charts {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -135,7 +135,7 @@ {% if statistical %}
- Statistical Charts + Statistical Charts {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -168,7 +168,7 @@ {% if scientific %}
- Scientific Charts + Scientific Charts {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -201,7 +201,7 @@ {% if financial %}
- Financial Charts + Financial Charts {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -234,7 +234,7 @@ {% if maps %}
- Maps + Maps {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -267,7 +267,7 @@ {% if ai_ml %}
- Artificial Intelligence and Machine Learning + Artificial Intelligence and Machine Learning {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -301,7 +301,7 @@ {% if bio %}
-
Bioinformatics +
Bioinformatics More Bioinformatics »
@@ -321,7 +321,7 @@ {% if 3d_charts %}
- 3D Charts + 3D Charts {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -354,7 +354,7 @@ {% if multiple_axes %}
- Subplots + Subplots {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -387,7 +387,7 @@ {% if chart_events and page.language =="python" %}
- Jupyter Widgets Interaction + Jupyter Widgets Interaction {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -420,7 +420,7 @@ {% if chart_events and page.language =="r" %}
- Custom Interaction With JavaScript + Custom Interaction With JavaScript {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -453,7 +453,7 @@ {% if chart_events and page.language == 'plotly_js' %}
- Custom Chart Events + Custom Chart Events {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -486,7 +486,7 @@ {% if controls %}
- Add Custom Controls + Add Custom Controls {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -519,7 +519,7 @@ {% if animations %}
- Animations + Animations {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -552,7 +552,7 @@ {% if financial_analysis %}
- Financial Analysis + Financial Analysis {% assign forloop_idx = 0 %} {%- for page in languagelist -%} @@ -585,7 +585,7 @@ {% if advanced_opt %}
- Advanced + Advanced
    @@ -611,7 +611,7 @@ {% if style_options %}
    - Style Options + Style Options
      @@ -637,7 +637,7 @@ {% if layout_options %}
      - Layout Options + Layout Options
        diff --git a/_posts/plotly_js/2015-04-05-plotly_js-index.html b/_posts/plotly_js/2015-04-05-plotly_js-index.html index 39630faec..514f2cd2a 100755 --- a/_posts/plotly_js/2015-04-05-plotly_js-index.html +++ b/_posts/plotly_js/2015-04-05-plotly_js-index.html @@ -15,10 +15,10 @@
        -

        Plotly JavaScript Open Source Graphing Library

        +

        Open Source JavaScript Graphing & Chart Library

        - Built on top of d3.js and stack.gl, Plotly.js is a high-level, declarative charting library. plotly.js ships with over 40 chart types, including 3D charts, statistical graphs, and SVG maps. -
        plotly.js is free and open source and you can view the source, report issues or contribute on GitHub. + Built on top of d3.js and stack.gl, Plotly.js is a high-level, declarative JavaScript charting library. plotly.js ships with over 40 chart types, including 3D charts, statistical graphs, and SVG maps. +
        plotly.js is free and open source, and you can view the source, report issues, or contribute on GitHub.

        @@ -26,14 +26,14 @@

        Plotly JavaScript Open Source Graphing Library

        {% include layouts/dashplug.html %}
        -
        - Read more about plotly.js features +
        + plotly.js Features
        - Sophisticated chart types + Sophisticated Chart Types
        plotly.js abstracts the types of statistical and scientific charts that you would find in packages like matplotlib, ggplot2, or MATLAB. @@ -41,7 +41,7 @@

        Plotly JavaScript Open Source Graphing Library

        - +
        d3.json('https://plotly.com/~DanielCarrera/13.json', function(figure){
                           var trace = {
        @@ -82,7 +82,7 @@ 

        Plotly JavaScript Open Source Graphing Library

        -
        Fully customizable
        +
        Fully Customizable
        plotly.js charts are described declaratively as JSON objects. Every aspect of the charts, such as colors, grid lines, and the legend, has a corresponding set of JSON attributes.
        @@ -132,15 +132,15 @@

        Plotly JavaScript Open Source Graphing Library

        -
        High performance
        +
        High Performance
        - Most plotly graphs are drawn with SVG. This offers great compatibility across browsers and publication-quality vector image export. Unfortunately, there are inherent performance limitations with the number of SVG elements that you can draw in the DOM.

        - plotly.js uses stack.gl for high performance 2D and 3D charting.

        + Most Plotly graphs are drawn with SVG. This offers great compatibility across browsers and publication-quality vector image export. Unfortunately, there are inherent performance limitations with the number of SVG elements that you can draw in the DOM.

        + plotly.js uses stack.gl for high performance 2D and 3D JavaScript charting.

        - +
        This chart was drawn with the plotly.js chart type scattergl. scattergl charts render an order of magnitude faster than their SVG counterparts.
        @@ -148,19 +148,16 @@

        Plotly JavaScript Open Source Graphing Library

        - -
        All 3D charts in plotly.js are rendered with WebGL, leveraging the power of the GPU for fast interactivity. - view the interactive version
        Universal
        - By abstracting charts to a declarative JSON structure, plotly.js is used as a browser-based charting library for Python, R, MATLAB. + By abstracting charts to a declarative JSON structure, plotly.js is used as a browser-based charting library for Python, R, and MATLAB.
        diff --git a/all_static/css/improve.css b/all_static/css/improve.css index e92cc5a02..311905bd2 100644 --- a/all_static/css/improve.css +++ b/all_static/css/improve.css @@ -308,11 +308,11 @@ aside.\--sidebar-container .\--sidebar-fixed.affix #modal-button { width: 195px; } .langindexlink { - text-decoration: none; - color: #506784; } + text-decoration: underline; + color: #2186f4; } .langindexlink:hover { text-decoration: underline; - color: #2186f4 !important; } + color: #1266c4 !important; } /*********fix dark sidebar*********/ body p a { @@ -445,6 +445,34 @@ aside.\--sidebar-container .\--sidebar-fixed #modal-button { summary::-webkit-details-marker { display: none !important; } +details.js-splash--features > summary { + cursor: pointer; + list-style: none; + padding-left: 22px; + position: relative; } + details.js-splash--features > summary::-webkit-details-marker { + display: none !important; } + details.js-splash--features > summary:before { + content: ""; + position: absolute; + left: 4px; + top: 0.45em; + border: 5px solid transparent; + border-width: 5px 7px; + border-left-color: #506784; + transition: transform 0.15s ease; } + details.js-splash--features > summary .js-splash--features-title { + font-size: 22px; + font-weight: 500; + color: #506784; + text-decoration: underline; } + details.js-splash--features > summary:hover .js-splash--features-title { + color: #2186f4; } + +details.js-splash--features[open] > summary:before { + transform: rotate(90deg); + transform-origin: 30% 50%; } + .\--footer-meta { border-top: none; background: #fff; } @@ -972,7 +1000,7 @@ body header.header-main.\--default nav.--nav-meta > ul > li.languages { color: #a0aaba; } .dark-mode .nav-breadcrumb-container .--fork svg path { fill: #a0aaba; } -.dark-mode .--section-header a { +.dark-mode .--section-header a, .dark-mode .--section-header > span { color: #fff !important; } .dark-mode .\--tutorial-section .\--grid-item { background: transparent !important; } diff --git a/all_static/css/main.css b/all_static/css/main.css index 6a01a9a26..0116f6277 100644 --- a/all_static/css/main.css +++ b/all_static/css/main.css @@ -8382,7 +8382,7 @@ body:not(:-moz-handler-blocked) main.\--page .\--page-body { padding-left: 0; position: relative; } - .\--tutorial-index .\--tutorial-section header.\--section-header a::before { + .\--tutorial-index .\--tutorial-section header.\--section-header a::before, .\--tutorial-index .\--tutorial-section header.\--section-header > span::before { display: none; } .\--tutorial-index .\--tutorial-section header.\--section-header div.icon { margin-top: 4px; diff --git a/scss/_pages/_tutorial-index.scss b/scss/_pages/_tutorial-index.scss index f21d11718..2d42b4f3b 100644 --- a/scss/_pages/_tutorial-index.scss +++ b/scss/_pages/_tutorial-index.scss @@ -160,7 +160,8 @@ body:not(:-moz-handler-blocked) { position: absolute; } - a { + a, + > span { &::before { display: none; } diff --git a/scss/improve.scss b/scss/improve.scss index 9c0de0232..dd3ba4328 100644 --- a/scss/improve.scss +++ b/scss/improve.scss @@ -457,13 +457,16 @@ aside.\--sidebar-container .\--sidebar-fixed.affix #modal-button { width: 195px; } +/* These "More
        >>" links previously had no underline and a muted + slate colour, so they didn't read as clickable until hover. Make the + affordance permanent rather than hover-only. */ .langindexlink { - text-decoration: none; - color: #506784; + text-decoration: underline; + color: #2186f4; &:hover { text-decoration: underline; - color: #2186f4 !important; + color: #1266c4 !important; } } @@ -661,6 +664,51 @@ summary::-webkit-details-marker { display: none !important; } +/* The global rule above hides the native disclosure triangle, and the + replacement arrow is scoped to .--sidebar-fixed only -- so a
        in + page content had no affordance at all and read as static text. Give the + plotly.js features section its own arrow, colour and underline so it's + obviously an expandable control. */ +details.js-splash--features { + > summary { + cursor: pointer; + list-style: none; + padding-left: 22px; + position: relative; + + &::-webkit-details-marker { + display: none !important; + } + + &:before { + content: ""; + position: absolute; + left: 4px; + top: 0.45em; + border: 5px solid transparent; + border-width: 5px 7px; + border-left-color: #506784; + transition: transform 0.15s ease; + } + + .js-splash--features-title { + font-size: 22px; + font-weight: 500; + color: #506784; + text-decoration: underline; + } + + &:hover .js-splash--features-title { + color: #2186f4; + } + } + + &[open] > summary:before { + transform: rotate(90deg); + transform-origin: 30% 50%; + } +} + .\--footer-meta { border-top: none; background: #fff; @@ -1476,7 +1524,10 @@ body header.header-main.\--default nav.--nav-meta { fill: #a0aaba; } - .--section-header a { + /* Section headings are now that their pointless self-links were + removed; keep the darkmode colour applying to both. */ + .--section-header a, + .--section-header > span { color: #fff !important; }