Skip to main content
Announcements
Qlik Connect 2024! Seize endless possibilities! LEARN MORE
Ouadie
Employee
Employee

Picasso.js is a powerful charting library that plays really well within the Qlik Sense ecosystem to build simple or very complex visualization.

By leveraging its component-based nature, you can combine the building blocks to create virtually any type of chart.

To learn more about Picasso.js, I recommend the following resources:

 

The full documentation of the library can be found on qlik.dev at https://qlik.dev/libraries-and-tools/picassojs. Navigating the documentation is easy, you can dig deeper into the main concepts, learn more about the different types of supported scales, but more importantly discover the different components that you can mix and match to create unique visualizations.

A feature of Picasso that I really like but is not very clear from the docs is Theming.

Picasso.js is themeable meaning that you can easily control the look and feel across all visualizations by creating a theme and changing a few base variables.

To do that, you simply pass in a theme object when instantiating Picasso js as follows:

 

 

…
Import picassojs from ‘picasso.js’;
…
  const picasso = picassojs({
    style: {
      '$font-color': '#FF00FF',
      '$font-size': '10px',
      '$font-family': 'Arial',
      '$font-size--l': '16px',
      '$guide-color': '#00FF00',
      '$shape': { // for use with type point component
      fill: '#00FF00',
      strokeWidth: 1,
      stroke: 'rgba(255, 255, 255, 0.2)',
      shape: 'star',
     },
    },
    palettes: [{
      key: 'categorical',
      colors: [
        chroma.bezier(['#00FF00', '#0000FF']).scale().colors(5),
      ],
    }, {
      key: 'sequential',
      colors: [
        ['#00FF00', '#0000FF'],
      ],
    }],
  });

 

 

Notice that you can change the labels’ font styling, colors, and even shapes of points (star, triangle, etc..) on the style object, and also pass in a color palette for categorical and sequential color scales.

The result looks like this (the ugly colors are for demo purposes only!)

Capture-999.PNG

Below is the complete code of the settings file and attached is the full project to run and edit.

 

 

/* eslint-disable no-unused-vars */
import {
  useElement,
  useState,
  useStaleLayout,
  useRect,
  useEffect,
} from '@nebula.js/stardust';
import picassojs from 'picasso.js';
import picassoQ from 'picasso-plugin-q';

import chroma from 'chroma-js';

export default function supernova() {
  const picasso = picassojs({
    style: {
      '$font-color': '#FF00FF',
      '$font-size': '10px',
      '$font-family': 'Arial',
      '$font-size--l': '16px',
      '$guide-color': '#00FF00',
      // $shape: { // for use with type point component
      //   fill: '#00FF00',
      //   strokeWidth: 1,
      //   stroke: 'rgba(255, 255, 255, 0.2)',
      //   shape: 'box',
      // },
    },
    palettes: [{
      key: 'categorical',
      colors: [
        chroma.bezier(['#00FF00', '#0000FF']).scale().colors(5),
      ],
    }, {
      key: 'sequential',
      colors: [
        ['#00FF00', '#0000FF'],
      ],
    }],
  });

  picasso.use(picassoQ);

  return {
    qae: {
      properties: {
        qHyperCubeDef: {
          qDimensions: [],
          qMeasures: [],
          qInitialDataFetch: [{ qWidth: 2, qHeight: 5000 }],
          qSuppressZero: false,
          qSuppressMissing: true,
        },
        showTitles: true,
        title: '',
        subtitle: '',
        footnote: '',
      },
      data: {
        targets: [
          {
            path: '/qHyperCubeDef',
            dimensions: {
              min: 1,
              max: 1,
            },
            measures: {
              min: 1,
              max: 1,
            },
          },
        ],
      },
    },
    component() {
      const element = useElement();
      const layout = useStaleLayout();
      const rect = useRect();

      const [instance, setInstance] = useState();

      useEffect(() => {
        const p = picasso.chart({
          element,
          data: [],
          settings: {},
        });

        setInstance(p);

        return () => {
          p.destroy();
        };
      }, []);

      useEffect(() => {
        if (!instance) {
          return;
        }

        instance.update({
          data: [
            {
              type: 'q',
              key: 'qHyperCube',
              data: layout.qHyperCube,
            },
          ],
          settings: {
            scales: {
              x: {
                data: {
                  extract: {
                    field: 'qDimensionInfo/0',
                  },
                },
              },
              y: {
                data: { field: 'qMeasureInfo/0' },
                invert: true,
                expand: 0.1,
              },
              c: {
                data: { field: 'qMeasureInfo/0' },
                type: 'color',
              },
            },
            components: [
              {
                type: 'axis',
                dock: 'left',
                scale: 'y',
              },
              {
                type: 'axis',
                dock: 'bottom',
                scale: 'x',
                settings: {
                  line: {
                    show: true,
                  },
                },
              },
              {
                type: 'grid-line',
                x: 'x',
                y: 'y',
              },
              {
                key: 'bars',
                type: 'box',
                data: {
                  extract: {
                    field: 'qDimensionInfo/0',
                    props: {
                      start: 0,
                      end: { field: 'qMeasureInfo/0' },
                    },
                  },
                },
                settings: {
                  major: { scale: 'x' },
                  minor: { scale: 'y' },
                  box: {
                    fill: { scale: 'c', ref: 'end' },
                  },
                },
              },
            ],
          },
        });
      }, [layout, instance]);

      useEffect(() => {
        if (!instance) {
          return;
        }
        instance.update();
      }, [rect.width, rect.height, instance]);
    },
  };
}