Облако тегов
Сегодня будем рассматривать такую задачку как генерация облака тегов. Мы все конечно ни раз встречали это облако на других сайтах и блогах, но не все задумывались над реализацией этого облака на php. Общие моменты ясны из определения с wiki:
“визуальное представление списка ярлыков (или категорий). Частота упоминаний, поисков, ссылок в интернете с определенного сайта неких слов, терминов, имен, отображается на специальной странице в виде изображения этих слов в формате гиперссылок. Размер изображения тем больше, чем выше релевантность данного слова (термина, имени).”
Релевантность в нашем случае определяется количеством вхождений одного тега в их общую массу.
Учитывая все вышесказанное, весь алгоритм построения облака тегов можно разделить на два этапа:
- Генерация списка пар Тег-Количество вхождений
- Вывод облака с учетом релевантности тегов
Первая задача решается довольно просто с технической точки зрения. Вторая тоже, но здесь возможны вариации.
Ниже приведу небольшой класс, который я написал для генерации облака тегов.
<?
class TagsCloud {
private $tags;
private $font_size_min = 14;
private $font_size_step = 5;
function __construct($tags) {
shuffle($tags);
$this->tags = $tags;
}
private function get_tag_count($tag_name, $tags) {
$count = 0;
foreach ($tags as $tag) {
if ($tag == $tag_name) {
$count++;
}
}
return $count;
}
private function tagscloud($tags) {
$tags_list = array();
foreach ($tags as $tag) {
$tags_list[$tag] = self::get_tag_count($tag, $tags);
}
return $tags_list;
}
private function get_min_count($tags_list) {
$min = $tags_list[$this->tags[0]];
foreach ($tags_list as $tag_count) {
if ($tag_count < $min) $min = $tag_count;
}
return $min;
}
public function get_cloud() {
$cloud = Array();
$tags_list = self::tagscloud($this->tags);
$min_count = self::get_min_count($tags_list);
foreach ($tags_list as $tag=>$count) {
$font_steps = $count - $min_count;
$font_size = $this->font_size_min + $this->font_size_step * $font_steps;
$cloud[] = "<span style='font-size:".$font_size."px'>".$tag."</span>";
}
return $cloud;
}
}
?>
Скачать этот класс можно здесь: tagscloud.php, а работать с этим классом примерно так:
<?
$tags = array(
'ajax', 'javascript', 'php', 'dojo',
'ajax', 'jquery', 'seo', 'seo',
'php', 'blog', 'ajax', 'php',
'html', 'css', 'ajax', 'javascript',
'css', 'jquery', 'php', 'smo'
);
$mycloud = new TagsCloud($tags);
$tags_list = $mycloud->get_cloud();
foreach ($tags_list as $tag) {
echo $tag.' ';
}
?>
В результате работы этого примера в окне браузера Вы получите следующее:

Второй этап построения облака тегов (вывод облака) заключается в преобразовании показателя релевантности (кол-во вхождений) в размер шрифта результирующей надписи.
В классе я реализовал это следующим образом: в настройках задается минимальный размер шрифта, который соответствует минимальному уровню релевантности (одно вхождение). Все теги с большей релевантностью имеют размер на столько пикселей больше, на сколько больше они имеют вхождений. Шаг изменения можно задавать полем font_size_step, а минимальный размер шрифта полем font_size_min.
Для дальнейшего усовершенствования внешнего вида можно прикрутить облако к небольшому js-скрипту. В результате чего получится такое облако: http://nacmnogo.ru/cloud.html. Подробнее про этот скрипт можно почитать здесь http://habrahabr.ru/blogs/javascript/38264/.
Что ж. У меня все. Удачи!
Сентябрь 1st, 2008
При такой реализации наличие очень популярного тега приведет к тому, что все остальные теги будут отображены одним шрифтом.
Сентябрь 2nd, 2008
Думал про этот баг, но для решения этой задачи в голову приходит только нелинейная зависимость между размером шрифта и уровнем релевантности. Например логарифм натуральный.
Сентябрь 2nd, 2008
ууу до решения таких задачек мне еще рано. что-нибудь попроще бы, это да…..
Сентябрь 2nd, 2008
Классное облако, эффект 3D поражает. Респектище
Сентябрь 2nd, 2008
Да. Респект чуваку, который написал этот плагин на js
Сентябрь 2nd, 2008
2 mr. Hide: Ну это только звучит сложно. На деле – пара строк
Сентябрь 3rd, 2008
ну…. как знать) я сча думаю как писать свой дорген)
Сентябрь 3rd, 2008
Решается с помощью кластерного анализа. В двух словах: все теги разбиваются на заданные группы (кластеры) в соответствии их частотности. Теги из одной группы отображаются одним шрифтом.
Очень популярный тег попадет в отдельную группу, но остальные группы при этом не пострадают.
Подробнее на английском и реализация:
Я подобный алгоритм сделал на asp.net, если кому надо – обращайтесь.
Сентябрь 4th, 2008
Спасибо за линк и за новую тему для размышлений
В посте рассмотрен алгоритм K-средних, где известно заранее кол-во кластеров, которые получатся в результате – самое то, для облака тегов. Но все равно хочется попробывать реализовать какой-нибудь алгоритм с другими исходными данными, поэтому постараюсь к этой теме вернуться еще в этом блоге
Сентябрь 15th, 2008
честно говоря, никогда не задумывался какими методам это достигается)
вот они, азы Веб 2.0
Сентябрь 19th, 2008
foreach ($tags_list as $tag) {
echo $tag.’ ‘;
}
} – лишнее закрытие…
Сентябрь 19th, 2008
Спасибо, исправил.
Январь 21st, 2009
Спасибо, позновательно. Попробую в своей теме использовать это.
Февраль 10th, 2009
Спасибо огромное, с вашего позволения использую это у себя на сайте.
Август 30th, 2009
Алгоритм страшный, почему не сделать вот так:
private function tagscloud($tags) {
$tags_list = array();
foreach ($tags as $tag) {
if(!isset($tags_list[$tag])) {
$tags_list[$tag] = 1;
}
else {
$tags_list[$tag] += 1;
}
}
return $tags_list;
}
Работает быстрее и выглядит понятнее.
Август 30th, 2009
2 Дмитрий: Лучше на примере показать почему такая версия не будет работать.
Допустим есть 3 слова – Картошка (1), Макароны(2) и Телефон(20). В скобках указано кол-во вхождений.
После преобразования этих чисел в размеры шрифтов с сохранением пропорций мы можем получить 2 слова мелким, почти неразличимым, шрифтом и одно большим шрифтом.
Октябрь 28th, 2009
Я как сделать, если при добавлении поста, новости и т.д., в строку через запятую вводить тэги, добавлять в БД, но если совпадения, не предпринимать действий.
Январь 17th, 2010
А можно пример вбивания тегов в базу, с отрезанием запятулек и грамотным запросом к бд ?
Февраль 12th, 2010
Как-то очень много возни с генерацией тег => кол-во.
Почему бы не воспользоваться функцией array-count-values (.
Тогда всё сведётся к
private function tagscloud($tags) {
return array-count-values(tags);
}
Ну и поиск min/max – оптимально – отсортировать по кол-ву
через asort и взять первый и последний элементы