我脑子里有一些心理地图,我一直试图弄清楚如何在R中编程,我有点磕磕绊绊(也许R不是最佳的)所以我正在寻求你的输入这个。
这就是这个想法:
(1)我每天有两个列表,其中包含民主党人和共和党人最常用的30个单词中的每个[字,频率]两位信息。
(2)我想有一个像digram那样的维恩或欧拉 (A)使用相对于频率的字体大小呈现单词的文本 (B)自动将双方使用的单词放入图表的中心部分,并将独特的民主人士或共和主义单词放在他们自己的部分中
到目前为止,我一直在使用包VennDiagram和Vennerable以及Venneuler,但没有什么是正确的,文本显示和自动调整使我无法理解。有一些在线工具可以得到密切关注(http://bioinfogp.cnb.csic.es/tools/venny/),但我想我想要每天都能自动更新。
有什么想法吗?
答案 0 :(得分:2)
我很无聊:
import numpy as np
import matplotlib.pyplot as plt
FIG_SIZE = (10,6)
class word_list_venn_diagram(object):
def __init__(self, words, fontsizes, polarities, scale=1.):
"""
Arguments:
----------
words: [str 1, ... str N]
list of strings
fontsizes: [float 1, ... float N]
corresponding list of (relative) fontsizes
polarity: [-1, 0, 1, ..., 0, 1]
corresponding list of area designations;
polarity of 0 corresponds to intersection;
polarities -1 and 1 correspond to the disjoint sets
scale: float
scales the size of the circles with respect to the text
(w.r.t. the maximum joint height of the bounding boxes of the 3 word lists)
Returns:
--------
None
"""
self.words = np.array(words)
self.fontsizes = np.array(fontsizes)
# get bounding boxes of text
self.bboxes = [self._get_bbox(word, size) for word, size in zip(self.words, self.fontsizes)]
# determine minimum radius of circles
diameter = 0.
unique_polarities = np.unique(polarities)
for polarity in unique_polarities:
idx, = np.where(polarities == polarity)
heights = [self.bboxes[ii].height for ii in idx]
total = np.sum(heights)
if total > diameter:
diameter = total
radius = diameter / 2.
# rescale
radius *= scale
self.radius = radius
# arrange bboxes vertically
for polarity in unique_polarities:
idx, = np.where(polarities == polarity)
order = self._argsort(self.fontsizes[idx])
heights = [self.bboxes[ii].height for ii in idx]
total = np.sum(heights)
current_height = 0.
for ii in idx[order]:
self.bboxes[ii].y = current_height - total/2.
current_height += self.bboxes[ii].height
# arrange bboxes horizontally
# NB: slightly cheeky use of polarity argument
for ii, _ in enumerate(self.bboxes):
self.bboxes[ii].x = polarities[ii] * self._get_shift(self.bboxes[ii].y, self.radius)
# draw
self.fig, self.ax = self.draw()
return
def draw(self):
"""
Draws the Venn diagram.
"""
fig, ax = plt.subplots(1,1,figsize=FIG_SIZE)
# draw circles
circle_left = plt.Circle((-0.5*self.radius, 0), self.radius, color='b', fill=False, axes=ax, linewidth=5)
circle_right = plt.Circle((+0.5*self.radius, 0), self.radius, color='r', fill=False, axes=ax, linewidth=5)
ax.add_artist(circle_left)
ax.add_artist(circle_right)
# draw words
for ii, (word, bb, fs) in enumerate(zip(self.words, self.bboxes, self.fontsizes)):
ax.text(bb.x, bb.y, word,
horizontalalignment='center',
verticalalignment='center',
fontsize=fs,
bbox=dict(pad=0., facecolor='none', edgecolor='none')
)
# update data limits as circles are not registered automatically
corners = (-1.5*self.radius, -self.radius), (1.5*self.radius, self.radius)
ax.update_datalim(corners)
ax.autoscale_view()
# make figure pretty-ish
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal')
ax.get_figure().set_facecolor('w')
ax.set_frame_on(False)
ax.get_figure().canvas.draw()
return fig, ax
def _get_bbox(self, word, fontsize):
"""
Get the bounding box for each word.
Unfortunately, the bbox is dependent on the renderer,
so a figure has to be created.
"""
fig = plt.figure(figsize=FIG_SIZE)
renderer = fig.canvas.get_renderer()
text = plt.text(0.5, 0.5, word,
fontsize=fontsize,
bbox=dict(pad=0., facecolor='none', edgecolor='red'))
bbox = text.get_window_extent(renderer=renderer)
plt.close(fig)
return bbox
def _argsort(self, arr):
"""
Returns indices to create a sorted array.
Entries are sorted in such a way that the largest element is in the middle,
and the size of the elements falls off towards the ends.
"""
order = np.argsort(arr)
order = np.r_[order[::2], order[1::2][::-1]]
return order
def _get_shift(self, y, r):
"""
Get point along midline of a waxing moon formed by two overlapping
circles of radius r as a function of y.
"""
x1 = np.sqrt(r**2 - y**2) + r/2. # right circle
x2 = np.sqrt(r**2 - y**2) - r/2. # left circle
x = x2 + (x1 - x2)/2. # midpoint
return x
def test():
test_string = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
# get a word list
words = test_string.split(' ')
# remove non alphanumeric characters
words = [''.join(ch for ch in word if ch.isalnum()) for word in words]
# count occurrences; remove duplicates
from collections import Counter
counter = Counter()
for word in words:
counter[word] += 1
words, counts = counter.keys(), np.array(counter.values())
# convert counts to reasonable fontsizes
max_fontsize = 25
max_count = np.float(np.max(counts))
fontsizes = counts / max_count * max_fontsize
# assign random polarities
polarities = np.random.choice([-1, 0, 1], len(words))
venn = word_list_venn_diagram(words, fontsizes, polarities, scale=1.5)
return