views:

720

answers:

10

Lets say i have an array like such

$artist = array("the roots","michael jackson","billy idol","more","and more","and_YET_MORE");
$count = array(5,3,9,1,1,3);

and i want to generate a tag clound that will have artist with a higher number in count be a H6 tag and the lowest being H1?

any ideas?

+14  A: 

Off the top of my head...

$artist = array("the roots","michael jackson","billy idol","more","and more","and_YET_MORE");
$count = array(5,3,9,1,1,3);
$highest = max($count);
for (int $x = 0; x < count($artist); $x++)
{
$normalized = $count[$x] / $highest;
$heading = ceil($normalized * 6); // 6 heading types
echo "<h".$heading.">".$artist[$x]."</h".$heading.">";
}
Ryan Fox
+1  A: 

@Ryan

That's correct but it actually makes the tags with the least number, larger. This code has been tested:

$artist = array("the roots","michael jackson","billy idol","more","and more","and_YET_MORE");
$count = array(5,3,9,1,1,3);
$highest = max($count);
for ($x = 0; $x < count($artist); $x++) {
$normalized = ($highest - $count[$x]+1) / $highest;
$heading = ceil($normalized * 6); // 6 heading types
echo "<h$heading>{$artist[$x]}</h$heading>";
}
Kevin
+1  A: 

kevind wrote:

@Ryan

That's correct but it actually makes the tags with the least number, larger. This code has been tested:

I actually meant to mention this in my answer- the original poster specified higher frequencies in higher-number tags, but HTML uses lower numbers for more significant headings.

I wrote my code to spec. ;P

Ryan Fox
Comment on his answer next time please. Don't make a non-answer answer.
TheSoftwareJedi
If you consider the date of this answer, you might notice that it occurred on the second day of the beta. This is long before the commenting feature was implemented.
Ryan Fox
A: 

I actually meant to mention this in my answer- the original poster specified higher frequencies in higher-number tags, but HTML uses lower numbers for more significant headings.

I wrote my code to spec. ;P

AH I see now, it seemed counter-intuitive to me that the higher the count the smaller the tag?

My mistake.

Kevin
Comment on his answer next time please. Don't make a non-answer answer
TheSoftwareJedi
@TheSoftwareJedi Comments did not exist on StackOverflow before Sept. 2008.
Kevin
DOH! Thanks, I forget...
TheSoftwareJedi
A: 

Personaly I would do somthing like this:

    <?php
$data = array($rating[0] => array('word0', 'word1', 'word2'), $rating[1] => array('word3', 'word4', 'word8',...));
//assums that $rating is an array with the weight of each word so the more popular words would have a higher value in rating
usort($data); //sort the $data variable, this should give us the most popular words first
$size = '1';
foreach($data as $rank)
{
$i=0;
while($i<$count($rank))
{
echo "<h" . $size . ">" . $rank[$i] . "</h" . $size . ">";
$i++;
}
$size++;
}
?>

Assuming I'm not a complete idiot this should work. But it is untested.

Unkwntech
Couple of things: lose the $ in front of count in the while loop; put $size++ inside the while loop. The way you have it now $count($rank) will be a fatal error and $size will not get incremented until everything is finished.
gaoshan88
+12  A: 

Perhaps this is a little academic and OT but hX tags are probably not the best choice for a tag cloud for reasons of document structure and all that sort of thing ...

Maybe spans or an ol with appropriate class attributes (plus some css)?

Brendan
+2  A: 

Have used this snippet for a while, credit is prism-perfect.net. Doesnt use H tags though

<div id="tags">
<div class="title">Popular Searches</div>
<?php
// Snippet taken from [prism-perfect.net]

include "/path/to/public_html/search/settings/database.php";
include "/path/to/public_html/search/settings/conf.php";

$query = "SELECT query AS tag, COUNT(*) AS quantity
FROM sphider_query_log
WHERE results > 0
GROUP BY query
ORDER BY query ASC
LIMIT 10";

$result = mysql_query($query) or die(mysql_error());

while ($row = mysql_fetch_array($result)) {

$tags[$row['tag']] = $row['quantity'];
}

// change these font sizes if you will
$max_size = 30; // max font size in %
$min_size = 11; // min font size in %

// get the largest and smallest array values
$max_qty = max(array_values($tags));
$min_qty = min(array_values($tags));

// find the range of values
$spread = $max_qty - $min_qty;
if (0 == $spread) { // we don't want to divide by zero
$spread = 1;
}

// determine the font-size increment
// this is the increase per tag quantity (times used)
$step = ($max_size - $min_size)/($spread);

// loop through our tag array
foreach ($tags as $key => $value) {

// calculate CSS font-size
// find the $value in excess of $min_qty
// multiply by the font-size increment ($size)
// and add the $min_size set above
$size = $min_size + (($value - $min_qty) * $step);
// uncomment if you want sizes in whole %:
// $size = ceil($size);

// you'll need to put the link destination in place of the /search/search.php...
// (assuming your tag links to some sort of details page)
echo '<a href="/search/search.php?query='.$key.'&search=1" style="font-size: '.$size.'px"';
// perhaps adjust this title attribute for the things that are tagged
echo ' title="'.$value.' things tagged with '.$key.'"';
echo '>'.$key.'</a> ';
// notice the space at the end of the link
}

?>
</div>
This seems a good approach to me. If your data is in an array just skip the database part. I'd recommend you store the artist name I would agree don't use H tags since it messes up your semantics. Spans would be my choice. Finally, a helper exists in Zend Framework that may just do what you need. See http://framework.zend.com/manual/en/zend.tag.html
simonrjones
sorry, no formatting in the above comment it seems!
simonrjones
A: 

As a helper in Rails:

def tag_cloud (strings, counts)
    max = counts.max
    strings.map { |a| "<span style='font-size:#{((counts[strings.index(a)] * 4.0)/max).ceil}em'>#{a}</span> "  }
end

Call this from the view:

<%= tag_cloud($artists, $counts) %>

This outputs elements in an array that will be converted to a string in the view to ultimately render like so:

<span style='font-size:3em'>the roots</span>
<span style='font-size:2em'>michael jackson</span> 
<span style='font-size:4em'>billy idol</span> 
<span style='font-size:1em'>more</span> 
<span style='font-size:1em'>and more</span> 
<span style='font-size:2em'>and_YET_MORE</span>

It would be better to have a 'class' attribute and reference the classes in a style sheet as mentioned by Brendan above. Much better than using h1-h6 semantically and there's less style baggage with a <span>.

why did someone give it a -1?
berkes
+4  A: 

You will want to add a logarithmic function to it too. (taken from tagadelic, my Drupal module to create tag clouds http://drupal.org/project/tagadelic):

  db_query('SELECT COUNT(*) AS count, id, name FROM ... ORDER BY count DESC');
  $steps = 6;
  $tags = array();
  $min = 1e9;
  $max = -1e9;
  while ($tag = db_fetch_object($result)) {
    $tag->number_of_posts = $tag->count; #sets the amount of items a certain tag has attached to it
    $tag->count = log($tag->count);
    $min = min($min, $tag->count);
    $max = max($max, $tag->count);
    $tags[$tag->tid] = $tag;
  }
  // Note: we need to ensure the range is slightly too large to make sure even
  // the largest element is rounded down.
  $range = max(.01, $max - $min) * 1.0001;

  foreach ($tags as $key => $value) {
    $tags[$key]->weight = 1 + floor($steps * ($value->count - $min) / $range);
  }

Then in your view or template:

foreach ($tags as $tag) {
  $output .= "<h$tag->weight>$tag->name</h$tag->weight>"
}
berkes
@berkes nice one! ;)
Frankie
A: 

This method is for SQL/PostgreSQL fanatics. It does the entire job in the database, and it prints text with "slugified" link. It uses Doctrine ORM just for the sql call, I'm not using objects. Suppose we have 10 sizes:

public function getAllForTagCloud($fontSizes = 10)
{
   $sql = sprintf("SELECT count(tag) as tagcount,tag,slug, 
   floor((count(*) * %d )/(select max(t) from 
     (select count(tag) as t from magazine_tag group by tag) t)::numeric(6,2)) 
     as ranking 
     from magazine_tag mt group by tag,slug", $fontSizes);

  $q = Doctrine_Manager::getInstance()->getCurrentConnection();
  return $q->execute($sql);
}

then you print them with some CSS class, from .tagranking10 (the best) to .tagranking1 (the worst):

<?php foreach ($allTags as $tag): ?>
  <span class="<?php echo 'tagrank'.$tag['ranking'] ?>">
    <?php echo sprintf('<a rel="tag" href="/search/by/tag/%s">%s</a>', 
        $tag['slug'], $tag['tag']
        ); ?>
  </span>
  <?php endforeach; ?>

and this is the CSS:

/* put your size of choice */
.tagrank1{font-size: 0.3em;}
.tagrank2{font-size: 0.4em;}
.tagrank3{font-size: 0.5em;} 
/* go on till tagrank10 */

This method displays all tags. If you have a lot of them, you probably don't want your tag cloud to become a tag storm. In that case you would append an HAVING TO clause to your SQL query:

-- minimum tag count is 8 --

HAVING count(tag) > 7

That's all

danieli