Stacked bar graph with variable width elements?
<p>In Tableau I'm used to making graphs like the one below. It has for each day (or some other discrete variable), a stacked bar of categories of different colours, heights and widths.</p>

<p>You can imagine the categories to be different advertisements that I show to people. The heights correspond to the percentage of people I've shown the advertisement to, and the widths correspond to the rate of acceptance.</p>

<p>It allows me to see very easily which advertisements I should probably show more often (short, but wide bars, like the 'C' category on September 13th and 14th) and which I should show less often (tall, narrow bars, like the 'H' category on September 16th).</p>

<p>Any ideas on how I could create a graph like this in R or Python?</p>

<p><a href="http://i.stack.imgur.com/qDSKv.jpg" rel="nofollow"><img src="http://i.stack.imgur.com/qDSKv.jpg" alt="enter image description here"></a></p>

<p>Unfortunately, this is not so trivial to achieve with <code>ggplot2</code> (I think), because <code>geom_bar</code> does not really support changing widths for the same x position. But with a bit of effort, we can achieve the same result:</p>

<h3>Create some fake data</h3>

<pre><code>set.seed(1234)
d &lt;- as.data.frame(expand.grid(adv = LETTERS[1:7], day = 1:5))
d$height &lt;- runif(7*5, 1, 3)
d$width &lt;- runif(7*5, 0.1, 0.3)
</code></pre>

<p>My data doesn't add up to 100%, cause I'm lazy.</p>

<pre><code>head(d, 10)

#    adv day   height     width
# 1    A   1 1.227407 0.2519341
# 2    B   1 2.244599 0.1402496
# 3    C   1 2.218549 0.1517620
# 4    D   1 2.246759 0.2984301
# 5    E   1 2.721831 0.2614705
# 6    F   1 2.280621 0.2106667
# 7    G   1 1.018992 0.2292812
# 8    A   2 1.465101 0.1623649
# 9    B   2 2.332168 0.2243638
# 10   C   2 2.028502 0.1659540
</code></pre>

<h3>Make a new variable for stacking</h3>

<p>We can't easily use <code>position_stack</code> I think, so we'll just do that part ourselves. Basically, we need to calculate the cumulative height for every bar, grouped by day. Using <code>dplyr</code> we can do that very easily.</p>

<pre><code>library(dplyr)
d2 &lt;- d %&gt;% group_by(day) %&gt;% mutate(cum_height = cumsum(height))
</code></pre>

<h3>Make the plot</h3>

<p>Finally, we create the plot. Note that the <code>x</code> and <code>y</code> refer to the <em>middle</em> of the tiles.</p>

<pre><code>library(ggplot2)
ggplot(d2, aes(x = day, y = cum_height - 0.5 * height, fill = adv)) +
  geom_tile(aes(width = width, height = height), show.legend = FALSE) +
  geom_text(aes(label = adv)) +
  scale_fill_brewer(type = 'qual', palette = 2) +
  labs(title = "Views and other stuff", y = "% of views")
</code></pre>

<p>If you don't want to play around with correctly scaling the widths (to something &lt; 1), you can use facets instead:</p>

<pre><code>ggplot(d2, aes(x = 1, y = cum_height - 0.5 * height, fill = adv)) +
  geom_tile(aes(width = width, height = height), show.legend = FALSE) +
  geom_text(aes(label = adv)) +
  facet_grid(~day) +
  scale_fill_brewer(type = 'qual', palette = 2) +
  labs(title = "Views and other stuff", y = "% of views", x = "")
</code></pre>

<h3>Result</h3>

<p><a href="http://i.stack.imgur.com/h6CVN.png"><img src="http://i.stack.imgur.com/h6CVN.png" alt="enter image description here"></a></p>

<p><a href="http://i.stack.imgur.com/N1i1v.png"><img src="http://i.stack.imgur.com/N1i1v.png" alt="enter image description here"></a></p>

python graph ggplot2 data-visualization