Thursday, 4 November 2010

Il file di configurazione di Wordpress

Wordpress è innegabilmente il CMS più utilizzato al momento in Europa e nel mondo Occidentale. Per installarlo è sufficiente scaricarlo dal sito Wordpress-it, copiare tutte le directory e file sul nostro hosting, e infine configurare il file wp-config.php. Fatto questo, potremo far partire lo script di installazione e configurazione del db da /PATH_TO_WP/wp-admin/. Ci occupiamo in questo post del file di configurazione. Ecco una versione pronta per l'uso senza commenti per gli "addetti ai lavori":


<?php
/* File base di configurazione di WordPress. */

define('DB_NAME', 'sql_name');
define('DB_USER', 'sql_user');
define('DB_PASSWORD', 'sql_pwd');
define('DB_HOST', 'sql_ip');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

/**#@+
* Chiavi Univoche di Identificazione
* Per generarle: https://api.wordpress.org/secret-key/1.1/salt/
*/
define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');
/**#@-*/

$table_prefix = 'wp_';
define ('WPLANG', 'it_IT');
define('WP_DEBUG', false);
/* Path assoluto alla directory di WordPress. */
if ( !defined('ABSPATH') )
define('ABSPATH', dirname(__FILE__) . '/');
require_once(ABSPATH . 'wp-settings.php');
?>

Wednesday, 3 November 2010

Sharing Social Code

Sempre più spesso si ha la necessità di implementare le icone di social networking nei nostri siti Web. Ecco gli snippet di codice per i due più diffusi, Facebook e Twitter, per il primo - in particolare - sia l'icona del "Mi Piace" sia l'icone per condividere la pagina.



Il codice CSS e JavaScript per gestire il codice PHP va posto prima:
<!-- Social Share v.1.1 -->
<style type="text/css">
html .fb_share_button {
display: -moz-inline-block;
display:inline-block;
padding:0px 20px 0 5px;
height:20px;
border:0px solid #d8dfea;
background:url(images/facebook.png) no-repeat top right;
font-family: Verdana, sans-serif;
font-size: 12px;
color: #777;
text-decoration:none;
}

.social-footer {
font-family: verdana, sans-serif;
font-size: 11px;
padding:0px;
margin-top:0px;
text-align:left;
color: #777;
}
.share {
font-family: verdana, sans-serif;
font-size: 11px;
color: #444;
}
</style>
<script type="text/javascript" xml:space="preserve">
function fbs_click() {
var u = location.href;
var t = document.title;
window.open('http://www.facebook.com/sharer.php?u='+encodeURIComponent(u)+'&t=<?php echo addslashes($titolo);?>&spref=fb','sharer','toolbar=0,status=0,width=626,height=436');
return false;
}
function twi_click() {
var u = location.href;
var t = "<?php echo addslashes($titolo);?>";
window.open('http://twitter.com/share?url='+encodeURIComponent(u)+'&text='+encodeURIComponent(t),'sharer','toolbar=0,status=0,width=626,height=436');
return false;
}
</script>

Infine il codice HTML (con IFrame) e PHP per le nostre esigenze:
<div style="text-align:left;">
<?php
$Fb_url = "http://".$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF']."?".$_SERVER['QUERY_STRING'];
?>
<iframe src="http://www.facebook.com/plugins/like.php?href=<?php echo urlencode($Fb_url); ?>&layout=standard&show_faces=false&width=450&action=like&colorscheme=light&height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px;" allowTransparency="true"></iframe>
</div>


<div class="social-footer">

<table>
<td class="share">
Condividi questo elemento:
</td>
<td valign="top">
<!-- FACEBOOK -->
<a title="Condividi su Facebook!" href="http://www.facebook.com/share.php?u=<url>" class="fb_share_button" target="_blank" rel="nofollow" onclick="return fbs_click()"></a>
</td>
<td>
<!-- TWITTER share -->
<a title="Condividi su Twitter!" href="#" target="_blank" rel="nofollow" onclick="return twi_click()">
<img src="images/twitter-icon.png" border="0" title="Twitta questo evento" /></a>
<!-- TWITTER Solo Status
<a title="ReTwitta questo elemento" href="http://twitter.com/home?status=<?php //echo "http://".$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];?>"
target="_blank" rel="nofollow"><img src="images/twitter-icon.png" border="0" title="Twitta questo evento" /></a>
-->
</td>
</table>


</div>
<!-- Fine Share -->


Tuesday, 21 September 2010

Generatore di Feed RSS/Atom

Una delle funzionalità più utili e ricercate dei siti è la gestione dei feed RSS (2.0). Per implementarla in PHP, utilizziamo la comoda classe FeedWriter di Anis Ahmad e disponibile nel suo sito per il download.



Ci dobbiamo ricordare solo di due cose, per la gestione dei feed in lingua italiana ed in generale per le lingue con caratteri accentati (ASCII code > 127): tutte le occorrenze dei caratteri accentati NON vanno escapate tranne la & commerciale (&amp;), e la tabella codici deve essere sempre lo stesso, e cioè UTF-8. Il Feed RSS è un file XML e dunque le entità HTML supportate sono solo 5 (lt, gt, amp, quote, apos)*.

Bisogna dunque controllare che nella prima riga del feed RSS corrispondente ci sia

<?xml version="1.0" encoding="UTF-8" ?>

Una prima versione del codice, molto banale, potrebbe essere la seguente:

$titolo = str_replace("&", "&amp;", $titolo);

Addendum "Check and Escape".

Una procedura completa, in caso di necessità, per trovare tutti i caratteri maggiori di ASCII(127) in un dato testo con un controllo esadecimale prevede un ciclo di controllo:

// Controlla se c'e' un Ascii > 127
$titolo = $row['titolo'];
        $strl = strlen($titolo);
         for ($i = 0;$i < $strl; $i++)
        {
            $char = '0x' . bin2hex(substr($titolo,$i,1));
            $pos = in_array($char, $arr_hex);
            if ($pos == 1)
            {
                    // Neutralizza carattere Ascii>127 trasformandolo in Html
                    // Esempio: 0xe0 diventa .....
                $titolo = str_replace($char, ' ', $titolo);
            }
        }
      

L'array di cui si parla nel frammento di codice precedente è:

// Ascii Hex > 128 (see http://www.table-ascii.com/)
$arr_hex = array(
"0x80","0x81","0x82","0x83","0x84","0x85","0x86","0x87","0x88","0x89","0x8A",
"0x8B","0x8C","0x8D","0x8E","0x8F",
"0x90","0x91","0x92","0x93","0x94","0x95","0x96","0x97","0x98","0x99","0x9A",
"0x9B","0x9C","0x9D","0x9E","0x9F",
"0xA0","0xA1","0xA2","0xA3","0xA4","0xA5","0xA6","0xA7","0xA8","0xA9","0xAA",
"0xAB","0xAC","0xAD","0xAE","0xAF",
"0xB0","0xB1","0xB2","0xB3","0xB4","0xB5","0xB6","0xB7","0xB8","0xB9","0xBA",
"0xBB","0xBC","0xBD","0xBE","0xBF",
"0xC0","0xC1","0xC2","0xC3","0xC4","0xC5","0xC6","0xC7","0xC8","0xC9","0xCA",
"0xCB","0xCC","0xCD","0xCE","0xCF",
"0xD0","0xD1","0xD2","0xD3","0xD4","0xD5","0xD6","0xD7","0xD8","0xD9","0xDA",
"0xDB","0xDC","0xDD","0xDE","0xDF",
"0xE0","0xE1","0xE2","0xE3","0xE4","0xE5","0xE6","0xE7","0xE8","0xE9","0xEA",
"0xEB","0xEC","0xED","0xEE","0xEF",
"0xF0","0xF1","0xF2","0xF3","0xF4","0xF5","0xF6","0xF7","0xF8","0xF9","0xFA",
"0xFB","0xFC","0xFD","0xFE","0xFF"
);

Nella lingua italiana, in generale, può bastare anche (come workaround) trasformare le accentate in apostrofate, poiché ogni lettera accentata è alla fine della parola:

$accentate = array ("à","è","ì","ò","ù");
$apostrofate = array ("a'","e'","i'","o'","u'");
$titolo = str_replace($accentate, $apostrofate, $row['titolo']);

Per le altre lingue, un ulteriore funzione è quella che prevede di trasformare qualsiasi accentata nella corrispondente parola piana (utile dove le lettere accentate sono in mezzo alla frase):

function replace_accents($str) {
$str = htmlentities($str, ENT_COMPAT, "UTF-8");
$str = preg_replace('/&([a-zA-Z])(uml|acute|grave|circ|tilde);/','$1',$str);
    return html_entity_decode($str);
}

Infine, un ultimo metodo per ottenere un feed accentato consiste nel porre tra CDATA anche il campo titolo (gli altri campi di descrizione sono già in questo contenitore), che corrisponde a trattare come Binario tale dato:

<title><![CDATA[Prova titolo che sarà accentato]]></title>

Il corrispondente feed non sarà però completamente standard.

*
Name Character Unicode code point (decimal) Standard Description
quot " U+0022 (34) XML 1.0 (double) quotation mark
amp & U+0026 (38) XML 1.0 ampersand
apos ' U+0027 (39) XML 1.0 apostrophe (= apostrophe-quote)
lt < U+003C (60) XML 1.0 less-than sign
gt > U+003E (62) XML 1.0 greater-than sign

Monday, 19 July 2010

Usare le Connessioni permanenti


Nel connettersi ad un database, oltre alla classica modalità di temporary connection, spesso si ha necessità di utilizzare le connessioni permanenti, che l'Application server riunisce in un pool di persistent connections.

Le connessioni permanenti hanno la particolarità di non chiudersi quando termina l'esecuzione dello script. PHP verifica se c'è un'identica connessione (stesso host, username e password) che non sia stata chiusa: se c'è la utilizza, altrimenti la crea.

L'utilità delle connessioni permanenti risalta maggiormente quando ci sono molti utenti che utilizzano brevi connessioni. In questo caso, infatti, il server utilizza il pool invece di aprire e chiudere una connessione per ogni query/dataset (considerando che ogni apertura comporta un costo operativo).

Un server Web multiprocesso (tipicamente, Apache) ha un processo padre che coordina un set di processi figli: quando viene richiesta una pagina dal client, il server alloca la risorsa scegliendo il primo processo figlio libero. Il problema delle connessioni temporanee, è che uno stesso client che effettua una nuova richiesta al server può essere servito da un nuovo processo, andando a creare due (o più) connessioni per una stessa pagina. Invece, se la connessione è permanente ogni pagina che effettua richieste SQL può riutilizzare la stessa connessione.
La controindicazione è nel numero massimo di connessioni che il database supporta. Bisogna verificare la documentazione per parametrizzare correttamente le connessioni (comprese abandoned e idle connections)

Ecco un esempio di codice di connessione in MySQL:

$connect=mysql_pconnect($dbhost, $dbuser, $dbpass);
if (!$connect)
    die("Errore durante la connessione a MySQL ".mysql_error());
mysql_select_db($dbname ,$connect);
mysql_query('set names utf8');

Naturalmente questo frammento di codice va posto in un file separato chiamato a livello globale, e non inserito in ogni pagina (altrimenti verrebbe aperta una connessione permanente per ogni richiesta!). Questo consente anche di avere codice scalabile e modificabile sostituendo connessioni permanenti e non permanenti.

Tuesday, 13 July 2010

Impostazione veloce Variabili di Sessione e utente

Molto spesso si ha necessità di verificare se una variabile è impostata, e se lo è correttamente. Ecco uno snippet di codice utile a tal scopo, che include anche il controllo di sessione sull'utente:

// Controllo che l'utente abbia profilo 3
@session_start();
if ($_SESSION['id_profile'] != 3) {
$_SESSION['errore'] = 2;
}
$id_requested = $_SESSION['id_profile']; 

$date_from = isset($_REQUEST['datefrom']) ? $_REQUEST['datefrom'] : "";

Per comodità riporto anche questo codice utile per distinguere i diversi casi di variabili

PHP Superglobals

Prendi il parametro
$_GET["id"]

quello che viene passato in Get, Post e Cookie da una form
$_REQUEST["variabile"]

Per sapere se una pagina arriva in POST:
$_SERVER["REQUEST_METHOD"]
Per salvare un dato in sessione:
$_SESSION["datodasalvare"] = $miavar;
NOTE
Con gli apici singoli il "\n" non viene espanso. 

L'attenzione ai parametri

Quando si accettano dati da un utente dovrebbero essere sempre disinfettati prima di mandarli in esecuzione al database.
Una vignetta spiega più di mille parole.


Xkcd (Exploit of a mom). Qualche esempio qui.
Per il Bravo Programmatore MySQL, la  funzione da utilizzare è ad esempio mysql_real_escape_string

Monday, 12 July 2010

Selezione di un range di date

Nel caso in cui serva estrarre da una relazione delle tuple che contengano esattamente un range di date di nascita, può essere più efficiente utilizzare funzioni native SQL/MySQL invece di usare un codice ogni volta personalizzato (ovvero: scriverlo da zero).

Si suppone che si abbia bisogno di distinguere range di 5 anni. Il codice risulterà questo:

(SELECT
        SUM(CASE WHEN  data_nascita < NOW() THEN 1 END) AS tutti,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '5' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '10' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 5_9,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '10' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '15' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 10_14,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '15' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '20' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 15_19,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '20' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '25' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 20_24,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '25' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '30' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 25_29,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '30' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '35' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 30_34,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '35' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '40' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 35_39,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '40' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '45' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 40_44,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '45' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '50' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 45_49,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '50' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '55' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 50_54,
        SUM(CASE WHEN DATE_ADD(data_nascita, INTERVAL '55' YEAR) < NOW() AND DATE_ADD(data_nascita, INTERVAL '60' YEAR) >= NOW() THEN 1 ELSE 0 END) AS 55_59,
        SUM(CASE WHEN YEAR(data_nascita) <= YEAR(CURDATE())-60 THEN 1 ELSE 0 END) AS over_60
        FROM tab_utenti
        WHERE attivo='1')

Thursday, 8 July 2010

Tunnel SSH

Per aprire una connessione sicura verso un Server, il tunnel SSH è sicuramente la soluzione migliore.

Diversi software possono servire allo scopo. Sicuramente ad esempio PuTTY, con Pageant, per le parole chiave, e Plink per creare collegamenti. Questo ultimo è il comando da utilizzare con la seguente sintassi:
plink -ssh -l <<nomeutente>> -L <<porta>>:<<indirizzo_porta>> -T -X -C -N <<server_destinazione>> [opzioni]
Esempio per un sistema linux con vm Windows:
plink -L 15901:10.11.12.13:5900 username@210.211.112.113
In cui_> porta locale:IP remoto:porta remota  username@IP locale.


Un'altra possibilità è OpenSSH. Ne parla Andrea Beggi qui. Brevemente:
Installare OpenSSH per Windows da qui (lasciare tutto default)
Aprire prompt comandi sulla dir di OpenSSH
cd bin
mkgroup -l >> ..\etc\group
mkpasswd -l -u <username_Windows> >> ..\etc\passwd   
net start opensshd

Apri PuTTY
Ip del server: Salva
Nella sezione SSH metti:
    Source Port: 3389
    Destination: 127.0.0.1:3389
Add.
Open: Yes

Vediamo come utilizzare SQLYog. La versione da utilizzare per questo scopo non è quella gratuita (Community Edition) ma l'Enterprise a pagamento. Dopo averla scaricata possiamo partire a configurare la connessione SSH e quella al database.

New -> Connection

Linguetta SSH
Use SSH Tunneling
SSH Host: va scritto il server a cui si vuole accedere (porta 22)
Username e password: quelle che usate per accedere in remoto (comunicate dall'admin)
Local Port: 4407 (Tcp/Udp)

Linguetta MySQL
MySQL host address: localhost o 127.0.0.1 (percorso locale al server)
Username e password: quelle usate per accedere al database (comunicate dall'admin)
Port: 3306 (porta Tcp usata da MySQL)
Database: il nome del vostro db

Save.

Verificate che ci sia l'utente. Andate su "Tools"->"User Manager"->"Edit User" e aggiungete l'utente.

A questo punto "Test connection.." e poi "Connect".


VNC su Tunnel SSH

Il tunnel SSH può essere anche usato per la modalità VNC (Virtual Network Computer), molto comoda per amministrare o gestire remotamente computer (su cui gira un VNC Server). La connessione VNC, infatti di norma è criptata solo in fase di login, ma utilizzandola tramite un tunnel SSH, si cripta tutto il traffico tra i due computer. Tra l'altro non vengono aperte porte VNC su Internet (quindi un eventuale scanning non troverà nulla), tranne la porta 222 di SSH. Devono essere abilitate (LISTEN) la porta remota 5900 (se Windows), o 5901 (se linux), e la porta  locale (si verifica con netstat -ln sui sistemi unix/linux, e netstat -an sotto Windows).

Ci si collega alla macchina remota indicando localhost:<porta locale> VNC forwardata su SSH e la porta remota. Il server, se raggiungibile ed attivo, richiederà username e password per abilitare il controllo remoto.

Friday, 2 July 2010

Il campo dedicato all'email

Secondo la specifica contenuta nell'RFC 2821, la parte dedicata al nome (local name) non deve superare 64 caratteri mentre la restante parte (domain name) 255 caratteri. La lunghezza massima dell'email si deduce sia quindi al massimo di 320 caratteri, compreso il simbolo `@'.

ESEMPIO (MySQL)
CREATE TABLE  `dbname`.`tb_utenti` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(20) NOT NULL,
  `password` varchar(20) NOT NULL,
  `nome` varchar(50) default NULL,
  `cognome` varchar(50) default NULL,
  `email` varchar(320) default NULL, 
  `indirizzo` text NOT NULL,
  `citta` varchar(255) NOT NULL,
  `data` datetime NOT NULL, 
  `telefono` varchar(50) NOT NULL,
  `note` text,
  PRIMARY KEY  (`id`,`username`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


Altre utili informazioni in questa pagina e alla RFC 2821 (che rende obsoleta la vetusta 821)

Thursday, 1 July 2010

Vincoli di integrità referenziali (foreign key)

Avendo ad es. queste due Relazioni:

tb_utenti
id_profilo: 1
tb_profili
id: 1
descrizione: normale

Codice (MySQL):

tb_utenti
KEY `fk_p` (`id_profilo`),
CONSTRAINT  `fk_p` FOREIGN KEY (`id_profilo`) REFERENCES `tb_profili` (`id`)
    ON DELETE CASCADE ON UPDATE CASCADE
(ovvero: costringi fk_p, chiave referenziante di id_profilo a referenziare il campo id di tb_profili)


ESEMPIO DI IMPLEMENTAZIONE
DROP TABLE IF EXISTS `dbname`.`tb_profili`;
CREATE TABLE `dbname`.`tb_profili` (
`id` int(11) NOT NULL auto_increment,
`descrizione` varchar(40) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `dbname`.`tb_profili` (`id`,`descrizione`) VALUES
(1,'Amministratore'),
(2,'Utente'),
(3,'Ospite');

DROP TABLE IF EXISTS `dbname`.`tb_utenti`;
CREATE TABLE `dbname`.`tb_utenti` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL,
`password` varchar(50) NOT NULL,
`nome` varchar(30) default NULL,
`cognome` varchar(50) default NULL,
`email` varchar(50) default NULL,
`data` datetime NOT NULL,
`attivo` int(11) NOT NULL default '0',
`id_profilo` int(11) NOT NULL default '0',
`note` text,
PRIMARY KEY (`id`,`username`),
UNIQUE KEY `id` (`id`),
KEY `fk_profili` (`id_profilo`),
CONSTRAINT `fk_profili` FOREIGN KEY (`id_profilo`) REFERENCES `tb_profili` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;

(vedere manuale MySQL per il significato del valore AUTO_INCREMENT)

Tuesday, 22 June 2010

MySql Workbench

MySQL Workbench consente di avere la visualizzazione del diagramma ER, Relazioni, Trigger, etc.

Download: http://dev.mysql.com/downloads/workbench/

Tuesday, 25 May 2010

Work essentials

Un notebook configurato per il Web development:

Essentials
Browser
  • Estensioni e plugin di Firefox
    Noscript (blocca qualsiasi script, da attivare sito per sito)
    Firebug
        + Codeburner for Firebug
        + firecookie
        + firequery
        + firephp
    Webdeveloper
    Xdebug (incollare su C:\wamp\bin\php\php5.2.11\ext le dll php_xdebug-2.1.0RC1-5.2-vc6.dll etc)
        http://xdebug.org/docs/install

SVN


Eclipse
  • Subclipse (plug-in providing support for Subversion within the Eclipse IDE)
    Incollare "http://subclipse.tigris.org/update_1.6.x" in Eclipse (Help -> Install new Software)
    ev. togliere Mylyn e JavaHL

Note
Ev. file di configurazione di Subversion 'config' va messo nella cartella svn che sta nel proprio profilo:
C:\Documents and Settings\Application Data\Subversion

Friday, 1 January 2010

IBM Alphaworks

Un'altra creazione molto interessante di quelli di Alphaworks, vecchia conoscenza:


 World Map of Social Networks (dec 2009) (Version 3)


Word Tree See a branching view of how a word or phrase is used in a text. Navigate the text by zooming and clicking.
Learn more
Phrase Net Display networks of related words and ideas.
Learn more
Wordle Wordle is a toy for generating “word clouds” from text that you provide. The clouds give greater prominence to words that appear more frequently in the source text.
Learn more
Tag Cloud How are you using your words? This enhanced tag cloud will show you the words popularity in the given set of text.
Learn more

Compare a set of values

Bar Chart How do the items in your data set stack up? A bar chart is a simple and recognizable way to compare values. You can display several sets of bars for multivariate comparisons.
Learn more
Block Histogram This versatile chart lets you get a quick sense of how a single set of data is distributed. Each item in the data is an individually identifiable block.
Learn more
Bubble Chart Have so many items that your bar chart is baffling? Do the values vary so much that one bar pushes to the top of the screen while another virtually disappears? Try our bubble chart, which displays values as circles of different sizes.
Learn more

See relationships among data points

Network Diagram Is your data all about relationships? Take a set of links -- say flight departure and arrival points or romantic pairings -- and see the connections laid out as a network.
Learn more
Scatterplot Point one variable across the x-axis, the other up the y-axis. The size of a dot can represent a third variable. The classic scatterplot gives you a bird's eye view of how your factors relate to each other.
Learn more
Matrix Chart A grid-based view of multidimensional data.
Learn more

See the parts of a whole

Treemap for Comparisons Want to map a comparison of now vs. then? City vs. highway? Decaf vs. regular? This version of the treemap lets you directly compare two different takes on a set of categorized items.
Learn more
Treemap The pie chart's big brother. Treemaps divide up a rectangle into hierarchical categories, letting you see relationships among large numbers of components. This lets you get an overview of a complex whole -- and drill down.
Learn more
Pie Chart Each component is a slice of the big pie. A simple and popular classic.
Learn more

See the world

Country_map Country Map... Shade the states, regions, or territories of an individual country based on data values. We currently support the following 14 countries:
Australia Brazil Canada China
France Germany Iraq Ireland
Italy Japan Netherlands Russia
UK USA
Learn more
US County Map This is a map of all counties in the United States
Learn more
World Map This is a world map.
Learn more