<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>graphs &#8211; Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/tag/graphs/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Wed, 18 Mar 2026 08:55:15 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>graphs &#8211; Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Graphing the connections between my blog posts]]></title>
		<link>https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/</link>
					<comments>https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 09 Jan 2025 12:34:56 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[graphs]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=55159</guid>

					<description><![CDATA[I love ripping off good ideas from other people&#039;s blogs.  I was reading Alvaro Graves-Fuenzalida&#039;s blog when I saw this nifty little force-directed graph:    When zoomed in, it shows the relation between posts and tags.    In this case, I can see that the posts about Small Gods and Pyramids both share the tags of Discworld, Fantasy, and Book Review. But only Small Gods has the tag of Religion. …]]></description>
										<content:encoded><![CDATA[<p>I love ripping off good ideas from other people's blogs.  I was reading <a href="https://stuff.graves.cl/posts/2024-03-05_20_41-book-review---small-gods-by-terry-pratchett.html">Alvaro Graves-Fuenzalida's blog</a> when I saw this nifty little force-directed graph:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/12/Graph-fs8.png" alt="A graph of interconnected nodes." width="800" height="600" class="aligncenter size-full wp-image-55160">

<p>When zoomed in, it shows the relation between posts and tags.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/12/Graph-detail-fs8.png" alt="Text labels on the nodes show that the two of the posts share a common tag." width="1600" height="1200" class="aligncenter size-full wp-image-55161">

<p>In this case, I can see that the posts about Small Gods and Pyramids both share the tags of Discworld, Fantasy, and Book Review. But only Small Gods has the tag of Religion.</p>

<p>Isn't that cool! It is a native feature of <a href="https://quartz.jzhao.xyz/features/graph-view">Quartz's GraphView</a>. How can I build something like that for my WordPress blog?</p>

<h2 id="aim"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#aim">Aim</a></h2>

<p>Create an interactive graph which shows the relationship between a post, its links, and their tags.</p>

<p>It will end up looking something like this:</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/12/fdg.png" alt="A force directed graph showing how four different posts link to each other and how their hashtags relate." width="1188" height="1088" class="aligncenter size-full wp-image-55169">

<p>You can <a href="https://gitlab.com/edent/blog-theme/-/blob/master/includes/graph.php">get the code</a> or follow along to see how it works.</p>

<p>This is a multi-stage process. Let's begin!</p>

<h2 id="what-we-need"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#what-we-need">What We Need</a></h2>

<p>When on a single Post, we need the following:</p>

<ul>
<li>The tags assigned to that Post.</li>
<li>Internal links back to that Post.</li>
<li>Internal links from that Post.</li>
<li>The tags assigned to links to and from that Post.</li>
</ul>

<h2 id="tags-assigned-to-that-post"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#tags-assigned-to-that-post">Tags assigned to that Post.</a></h2>

<p>This is pretty easy!  Using the <a href="https://developer.wordpress.org/reference/functions/get_the_tag_list/"><code>get_the_tag_list()</code> function</a> we can, unsurprisingly, get all the tags associated with a post.</p>

<pre><code class="language-php">$post_tags_text = get_the_tag_list( "", ",", $ID );
$post_tags_array = explode( "," , $post_tags_text );
</code></pre>

<p>That just gets the list of tag names. If we want the tag IDs as well, we need to use <a href="https://developer.wordpress.org/reference/functions/get_the_tags/">the <code>get_the_tags()</code> function</a>.</p>

<pre><code class="language-php">$post_tags = get_the_tags($ID);
$tags = array();
foreach($post_tags as $tag) {
    $tags[$tag-&gt;term_id] = $tag-&gt;name; 
}
</code></pre>

<h2 id="backlinks"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#backlinks">Backlinks</a></h2>

<p>Internal links back to the Post is slightly trickier. WordPress doesn't save relational information like that. Instead, we get the Post's URl and <a href="https://shkspr.mobi/blog/2023/10/displaying-internal-linkbacks-on-wordpress/">search for that in the database</a>. Then we get the post IDs of all the posts which contain that string.</p>

<pre><code class="language-php">//  Get all the posts which link to this one, oldest first
$the_query = new WP_Query(
    array(
        's' =&gt; $search_url,
        'post_type' =&gt; 'post',
        "posts_per_page" =&gt; "-1",
        "order" =&gt; "ASC"
    )
);

//  Nothing to do if there are no inbound links
if ( !$the_query-&gt;have_posts() ) {
    return;
}
</code></pre>

<h2 id="backlinks-tags"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#backlinks-tags">Backlinks' Tags</a></h2>

<p>Once we have an array of posts which link back here, we can get their tags as above:</p>

<pre><code class="language-php">//  Loop through the posts
while ( $the_query-&gt;have_posts() ) {
    //  Set it up
    $the_query-&gt;the_post();
    $id                  = get_the_ID();
    $title               = esc_html( get_the_title() );
    $url                 = get_the_permalink();
    $backlink_tags_text  = get_the_tag_list( "", ",", $ID );
    $backlink_tags_array = explode( "," , $backlink_tags_text );
}
</code></pre>

<h2 id="links-from-the-post"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#links-from-the-post">Links from the Post</a></h2>

<p>Again, WordPress's lack of relational links is a weakness. In order to get internal links, we need to:</p>

<ol>
<li>Render the HTML using all the filters</li>
<li>Search for all <code>&lt;a href="…"&gt;</code></li>
<li>Extract the ones which start with the blog's domain</li>
<li>Get those posts' IDs.</li>
</ol>

<p>Rendering the content into HTML is done with:</p>

<pre><code class="language-php">$content = apply_filters( "the_content", get_the_content( null, false, $ID ) );
</code></pre>

<p>Searching for links is slightly more complex. The easiest way is to load the HTML into a DOMDocument, then extract all the anchors. All my blog posts start <code>/blog/YYYY</code> so I can avoid selecting links to tags, uploaded files, or other things. Your blog may be different.</p>

<pre><code class="language-php">$dom = new DOMDocument();
libxml_use_internal_errors( true ); //  Suppress warnings from malformed HTML
$dom-&gt;loadHTML( $content );
libxml_clear_errors();

$links = [];
foreach ( $dom-&gt;getElementsByTagName( "a" ) as $anchor ) {
    $href = $anchor-&gt;getAttribute( "href" );
    if (preg_match('/^https:\/\/shkspr\.mobi\/blog\/\d{4}$/', $href)) {
        $links[] = $href;
    }
}
</code></pre>

<p>The ID of each post can be found with <a href="https://developer.wordpress.org/reference/functions/url_to_postid/">the <code>url_to_postid()</code> function</a>. That means we can re-use the earlier code to see what tags those posts have.</p>

<h2 id="building-a-graph"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#building-a-graph">Building a graph</a></h2>

<p>OK, so we have all our constituent parts. Let's build a graph!</p>

<p>Graphs consist of nodes (posts and tags) and edges (links between them). The exact format of the graph is going to depend on the graph library we use.</p>

<p>I've decided to use <a href="https://github.com/d3/d3-force?tab=readme-ov-file">D3.js's Force Graph</a> as it is relatively simple and produces a reasonably good looking interactive SVG.</p>

<p>Imagine there are two blog posts and two hashtags.</p>

<pre><code class="language-js">const nodes = [
    { id: 1, label: "Blog Post 1",    url: "https://example.com/post/1", group: "post" },
    { id: 2, label: "Blog Post 2",    url: "https://example.com/post/2", group: "post" },
    { id: 3, label: "hashtag",        url: "https://example.com/tag/3",  group: "tag"  },
    { id: 4, label: "anotherHashtag", url: "https://example.com/tag/4",  group: "tag"  },
];
</code></pre>

<ul>
<li>Blog Post 1 links to Blog Post 2.</li>
<li>Blog Post 1 has a #hashtag.</li>
<li>Both 1 &amp; 2 share #anotherHashtag.</li>
</ul>

<pre><code class="language-js">const links = [
    { source: 1, target: 2 },
    { source: 3, target: 1 },
    { source: 4, target: 1 },
    { source: 4, target: 2 },
];
</code></pre>

<p>Here's how to create a list of nodes and their links.  You will need to edit it for your own blog's peculiarities.</p>

<pre><code class="language-php">&lt;?php 
// Load WordPress environment
require_once( "wp-load.php" );

//  Set up arrays for nodes and links
$nodes = array();
$links = array();

//  ID of the Post
$main_post_id = 12345;

//  Get the Post's details
$main_post_url   = get_permalink( $main_post_id );
$main_post_title = get_the_title( $main_post_id );

//  Function to add new nodes
function add_item_to_nodes( &amp;$nodes, $id, $label, $url, $group ) {
    $nodes[] = [ 
        "id"    =&gt; $id, 
        "label" =&gt; $label, 
        "url"   =&gt; $url, 
        "group" =&gt; $group
    ];

}

//  Function to add new relationships
function add_relationship( &amp;$links, $source, $target ) {
    $links[] = [
        "source" =&gt; $source,
        "target" =&gt; $target
    ];
}

//  Add Post to the nodes
add_item_to_nodes( $nodes, $main_post_id, $main_post_title, $main_post_url, "post" );

//  Get the tags of the Post
$main_post_tags = get_the_tags( $main_post_id );

//  Add the tags as nodes, and create links to main Post
foreach( $main_post_tags as $tag ) {
    $id   = $tag-&gt;term_id;
    $name = $tag-&gt;name;

    //  Add the node
    add_item_to_nodes( $nodes, $id, $name, "https://shkspr.mobi/blog/tag/" . $name, "tag" );
    //  Add the relationship
    add_relationship( $links, $id, $main_post_id );
}

//  Get all the posts which link to this one, oldest first
$the_query = new WP_Query(
    array(
        's'              =&gt; $main_post_url,
        'post_type'      =&gt; 'post',
        "posts_per_page" =&gt; "-1",
        "order"          =&gt; "ASC"
    )
);

//  Nothing to do if there are no inbound links
if ( $the_query-&gt;have_posts() ) {
    //  Loop through the posts
    while ( $the_query-&gt;have_posts() ) {
        //  Set up the query
        $the_query-&gt;the_post();
        $post_id = get_the_ID();
        $title = esc_html( get_the_title() );
        $url   = get_the_permalink();

        //  Add the node
        add_item_to_nodes( $nodes, $post_id, $title, $url, "post" );
        //  Add the relationship
        add_relationship( $links, $post_id, $main_post_id );

        //  Get the tags of the Post
        $post_tags = get_the_tags( $post_id );

        //  Add the tags as nodes, and create links to main Post
        foreach($post_tags as $tag) {

            $id   = $tag-&gt;term_id;
            $name = $tag-&gt;name;

            //  Add the node
            add_item_to_nodes( $nodes, $id, $name, "https://shkspr.mobi/blog/tag/" . $name, "tag" );
            //  Add the relationship
            add_relationship( $links, $id, $post_id );
        }

    }
}

//  Get all the internal links from this post
//  Render the post as HTML
$content = apply_filters( "the_content", get_the_content( null, false, $ID ) );

//  Load it into HTML
$dom = new DOMDocument();
libxml_use_internal_errors( true );
$dom-&gt;loadHTML( $content );
libxml_clear_errors();

//  Get any &lt;a href="…" which starts with https://shkspr.mobi/blog/
$internal_links = [];
foreach ( $dom-&gt;getElementsByTagName( "a" ) as $anchor ) {
    $href = $anchor-&gt;getAttribute( "href" );
    if (preg_match('/^https:\/\/shkspr\.mobi\/blog\/\d{4}$/', $href)) {
        $internal_links[] = $href;
    }
}

//  Loop through the internal links, get their hashtags
foreach ( $internal_links as $url ) {
    $post_id = url_to_postid( $url );
    //  Get the Post's details
    $post_title = get_the_title( $id );

    //  Add the node
    add_item_to_nodes( $nodes, $post_id, $post_title, $url, "post" );
    //  Add the relationship
    add_relationship($links, $main_post_id, $post_id );

    //  Get the tags of the Post
    $post_tags = get_the_tags( $post_id );

    //  Add the tags as nodes, and create links to main Post
    foreach( $post_tags as $tag ) {
        $id   = $tag-&gt;term_id;
        $name = $tag-&gt;name;

        //  Add the node
        add_item_to_nodes( $nodes, $id, $name, "https://shkspr.mobi/blog/tag/" . $name, "tag" );
        //  Add the relationship
        add_relationship( $links, $id, $post_id );
    }
}

//  Deduplicate the nodes and links
$nodes_unique = array_unique( $nodes, SORT_REGULAR );
$links_unique = array_unique( $links, SORT_REGULAR );

//  Put them in the keyless format that D3 expects
$nodes_output = array();
$links_output = array();

foreach ( $nodes_unique as $node ) {
    $nodes_output[] = $node;
}

foreach ( $links_unique as $link ) {
    $links_output[] = $link;
}

//  Return the JSON
echo json_encode( $nodes_output, JSON_PRETTY_PRINT );
echo "\n";
echo json_encode( $links_output, JSON_PRETTY_PRINT );
</code></pre>

<h2 id="creating-a-force-directed-svg"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#creating-a-force-directed-svg">Creating a Force Directed SVG</a></h2>

<p>Once the data are spat out, you can include them in a web-page. Here's a basic example:</p>

<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
        &lt;title&gt;Force Directed Graph&lt;/title&gt;
        &lt;script src="https://d3js.org/d3.v7.min.js"&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;svg width="800" height="600"&gt;
            &lt;defs&gt;
                &lt;marker id="arrowhead" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto" fill="#999"&gt;
                &lt;path d="M0,0 L10,3.5 L0,7 Z"&gt;&lt;/path&gt;
                &lt;/marker&gt;
            &lt;/defs&gt;
        &lt;/svg&gt;
        &lt;script&gt;
</code></pre>

<pre><code class="language-js">            const nodes = [];
            const links = [];

            const width  = 800;
            const height = 600;

            const svg = d3.select("svg")
                .attr( "width",  width  )
                .attr( "height", height );

            const simulation = d3.forceSimulation( nodes )
                .force( "link",   d3.forceLink( links ).id( d =&gt; d.id ).distance( 100 ) )
                .force( "charge", d3.forceManyBody().strength( -300 ) )
                .force( "center", d3.forceCenter( width / 2, height / 2 ) );

            //  Run simulation with simple animation
            simulation.on("tick", () =&gt; {
                link
                    .attr("x1", d =&gt; d.source.x)
                    .attr("y1", d =&gt; d.source.y)
                    .attr("x2", d =&gt; d.target.x)
                    .attr("y2", d =&gt; d.target.y);   node
                    .attr("transform", d =&gt; `translate(${d.x},${d.y})`);
            });

            // Draw links
            const link = svg.selectAll( ".link" )
                .data(links)
                .enter().append("line")
                .attr( "stroke", "#999" )
                .attr( "stroke-width", 2 )
                .attr( "x1", d =&gt; d.source.x )
                .attr( "y1", d =&gt; d.source.y )
                .attr( "x2", d =&gt; d.target.x )
                .attr( "y2", d =&gt; d.target.y )
                .attr( "marker-end", "url(#arrowhead)" );

            //  Draw nodes
            const node = svg.selectAll( ".node" )
                .data( nodes )
                .enter().append( "g" )
                .attr( "class", "node" )
                .attr( "transform", d =&gt; `translate(${d.x},${d.y})` )
                .call(d3.drag() //  Make nodes draggable
                    .on( "start", dragStarted )
                    .on( "drag",  dragged )
                    .on( "end",   dragEnded ) 
                );

            //  Add hyperlink
            node.append("a")
            .attr( "xlink:href", d =&gt; d.url ) //    Link to the node's URL
            .attr( "target", "_blank" ) //  Open in a new tab
            .each(function (d) {
                const a = d3.select(this);
                //  Different shapes for posts and tags
                if ( d.group === "post" ) {
                    a.append("circle")
                        .attr("r", 10)
                        .attr("fill", "blue");
                } else if ( d.group === "tag" ) {
                    //  White background rectangle
                    a.append("rect")
                            .attr("width", 20)
                            .attr("height", 20)
                            .attr("x", -10)
                            .attr("y", -10)
                            .attr("fill", "white"); 
                    // Red octothorpe
                    a.append("path")
                            .attr("d", "M-10,-5 H10 M-10,5 H10 M-5,-10 V10 M5,-10 V10") 
                            .attr("stroke", "red")
                            .attr("stroke-width", 2)
                            .attr("fill", "none");
                }
                //  Text label
                a.append( "text")
                    .attr( "dy", 4 )
                    .attr( "x", d =&gt; ( d.group === "post" ? 12 : 14 ) )
                    .attr( "fill", "black" )
                    .style("font-size", "12px" )
                    .text( d.label );
            });

            //  Standard helper functions to make nodes draggable
            function dragStarted( event, d ) {
                if ( !event.active ) simulation.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;
            }
            function dragged( event, d ) {
                d.fx = event.x;
                d.fy = event.y;
            }
            function dragEnded( event, d ) {
                if (!event.active) simulation.alphaTarget(0);
                d.fx = null;
                d.fy = null;
            }
</code></pre>

<pre><code class="language-html">        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/#next-steps">Next Steps</a></h2>

<p>It needs a bit of cleaning up if I want to turn it into a WordPress plugin. It might be nice to make it a static SVG rather than relying on JavaScript. And the general æsthetic needs a bit of work.</p>

<p>Perhaps I could make it 3D like my <a href="https://shkspr.mobi/blog/2023/04/msc-dissertation-exploring-the-visualisation-of-hierarchical-cybersecurity-data-within-the-metaverse/">MSc Dissertation</a>?</p>

<p>But I'm pretty happy with that for an afternoon hack!</p>

<p>You can <a href="https://gitlab.com/edent/blog-theme/-/blob/master/includes/graph.php">get the code</a> if you want to play.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=55159&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/01/graphing-the-connections-between-my-blog-posts/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Surrey Police and the Case of The Misleading Pie Charts]]></title>
		<link>https://shkspr.mobi/blog/2013/03/surrey-police-and-the-case-of-the-misleading-pie-charts/</link>
					<comments>https://shkspr.mobi/blog/2013/03/surrey-police-and-the-case-of-the-misleading-pie-charts/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 18 Mar 2013 07:30:10 +0000</pubDate>
				<category><![CDATA[politics]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[graphs]]></category>
		<category><![CDATA[police]]></category>
		<category><![CDATA[statistics]]></category>
		<category><![CDATA[stats]]></category>
		<category><![CDATA[surrey]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=7820</guid>

					<description><![CDATA[Surrey County Council have sent every household in the county a booklet explaining how our council tax is being spent.  Within it is a highly political comment from Kevin Hurley, the newly elected Police and Crime Commissioner.  He presents a pie chart showing how the police force spend its money.  Take a look at it and ask yourself this question: what percentage is spent on &#34;Employees&#34;.   …]]></description>
										<content:encoded><![CDATA[<p>Surrey County Council have sent every household in the county a booklet explaining how our council tax is being spent.  Within it is a highly political comment from Kevin Hurley, the newly elected Police and Crime Commissioner.</p>

<p>He presents a pie chart showing how the police force spend its money.  Take a look at it and ask yourself this question: what percentage is spent on "Employees".</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2013/03/Surrey-Police-Pie-Chart1.jpg" alt="Surrey Police Pie Chart" width="600" height="363" class="aligncenter size-full wp-image-7817">

<p><del datetime="2025-01-23T06:42:40+00:00">Please use this poll to record your guess - answers at the end of this blog.</del></p>

<p>Pie charts have a long and noble history.  They were popularised by Florence Nightingale and were hugely effective in helping politicians understand the causes of death among soldiers during the Crimean War.
<a title="By w:Florence Nightingale (1820–1910). (http://www.royal.gov.uk/output/Page3943.asp) [Public domain], via Wikimedia Commons" href="http://commons.wikimedia.org/wiki/File%3ANightingale-mortality.jpg"><img width="512" alt="Nightingale-mortality" src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Nightingale-mortality.jpg/960px-Nightingale-mortality.jpg"></a></p>

<p>As we understand more about the human brain and how we perceive shapes, it is becoming clear that <a href="https://en.wikipedia.org/wiki/Pie_chart#Use_and_effectiveness">pie charts are ineffective for representing complex information</a>.</p>

<p>2D pie charts can still serve a useful purpose in limited circumstances.  The real problem is with <em>3D</em> pie charts.  As far as I can tell, these abominations were popularised by Microsoft's Excel charting software.</p>

<p>3D charts distort the view of the data in such a way that it becomes increasingly hard to understand the information being presented.  A picture being worth 1000 words, allow me to demonstrate:
<img src="https://shkspr.mobi/blog/wp-content/uploads/2013/03/GraphJam3d.jpg" alt="GraphJam3d" width="499" height="335" class="aligncenter size-full wp-image-7818"></p>

<p>So, just how bad is Surrey Police's Pie Chart?  In an <em>extremely</em> scientific study of asking half a dozen people, they all guessed between 75% and 85%.  That's quite a wide range considering it's a multi-million pound difference.</p>

<p>On the opposite page to the pie chart is this summary of spending.
<img src="https://shkspr.mobi/blog/wp-content/uploads/2013/03/Police-Spending.jpg" alt="Police Spending" width="600" height="320" class="aligncenter size-full wp-image-7816"></p>

<p>In slightly more readable format, it is:</p>

<table>
    <tbody><tr>
        <td><b>Category</b></td>
        <td><b>£</b></td>
        <td><b>%</b></td>
    </tr>
    <tr>
        <td><b>Employees</b></td>
        <td>£181.70</td>
        <td>81.9%</td>
    </tr>
    <tr>
        <td><b>Premises</b></td>
        <td>£8.00</td>
        <td>3.6%</td>
    </tr>
    <tr>
        <td><b>Supplies</b></td>
        <td>£27.20</td>
        <td>12.3%</td>
    </tr>
    <tr>
        <td><b>Transport</b></td>
        <td>£5.00</td>
        <td>2.3%</td>
    </tr>
    <tr>
        <td><b>Total</b></td>
        <td>£216.90</td>
        <td>97.7%</td>
    </tr>
</tbody></table>

<p><br>
A few interesting things to note here.</p>

<p>Firstly, how do we calculate the percentages?  The total spend isn't mentioned in the report (£216.90).  If we use that, "Employees" accounts for 81.9% of spending.</p>

<p>If we take into account the gross expenditure (£207.70) the figure jumps to <strong>87.5%</strong>.</p>

<p>Secondly, if we do assume that we're using the unreported total spend - there is at least 2% missing.  Some of which can be explained by rounding - but I wonder what the rest of the money is spent on.</p>

<p>Given the above, I don't think the provided pie chart allows Surrey residents to see an accurate view of how their hard earned money is being spent.</p>

<p>Hopefully, this side-by-side - of the above data - will show you how 3D pie charts distort data and end up misleading their audience.
<img src="https://shkspr.mobi/blog/wp-content/uploads/2013/03/3d-2d-pie-chart-side-by-side.jpg" alt="3d 2d pie chart side by side" width="600" height="266" class="aligncenter size-full wp-image-7827"></p>

<p>With this overlay, we can see the distortion much more clearly.  The smaller sections of the chart look disproportionately larger.
<img src="https://shkspr.mobi/blog/wp-content/uploads/2013/03/Pie-Charts-Overlayed.png" alt="Pie Charts Overlayed" width="408" height="377" class="aligncenter size-full wp-image-7828">
It's time to announce a zero tolerance crackdown on dodgy data representation.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=7820&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2013/03/surrey-police-and-the-case-of-the-misleading-pie-charts/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
