cancel
Showing results for 
Search instead for 
Did you mean: 
intapiuser
Community Team Member
Community Team Member
Here is an alternate visualization of a funnel chart - instead of using bars, it depicts the different steps as concentric circles.

How to use: define an array in the extract() function of the values you'd like to use. If you are pulling data from a data frame, you will need to use something like the pandas iloc function to extract the desired values.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection

# extract important variables from the data frame
def extract():
#   GET DATA FROM DATA FRAME
#   if df.size == 0:
#     return [0, 0, 0 , 0, 0]
#   else:
#     opps_created = df.iloc[0]['opps_created']
#     opps_accepted = df.iloc[0]['opps_accepted']
#     opps_trialed = df.iloc[0]['opps_trialed']
#     opps_won = df.iloc[0]['opps_won']

# EXAMPLE DATA
    opps_created = 150
    opps_accepted = 80
    opps_trialed = 50
    opps_won = 20
    return [opps_created, opps_accepted, opps_trialed, opps_won]


####################
# create text chart
####################
def kpi_text(ax, text = '', text_color = 'black', x_position = 0, y_position = 0.5, font_size = 13):
    return ax.text(x = x_position,
                   y = y_position,
                   s = text,
                   color = text_color,
                   family = 'sans-serif',
                   fontsize = font_size,
                   horizontalalignment = 'center',
                   verticalalignment = 'center')


# create the plot
def kpi_chart(df):

  # set up the figure
  fig, ax = plt.subplots(figsize = (5.5,5.5))

  fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
  ax.axis('off')

  # styling (colors and font sizes)
  mediumgray = '#999292'
  lightgray = '#c4c4c4'
  purples = plt.get_cmap('Purples_r')

  fontsize_text = 30
  offset_x = 0.1
  offset_y = 0.13

  # parse the data
  funnel_df = extract()
#     use the following if you are using the extract_df function to parse the desired values
#   funnel_df = extract(df)
  [opps_created, opps_accepted, opps_trialed, opps_won] = funnel_df

  # map the data
  def get_data_domain(data):
    return {'min': min(data), 'max': max(data)}

  def data_mapper(data = [None], outputsize = 0.5):
    #assumes zero-max domain normalization
    # 0.48 is the max radius with a bit of padding
    domain = get_data_domain(data)
    mapped_area =  [1.0 * d/domain['max'] * outputsize  for d in data]
    mapped_radius = [np.sqrt(d/np.pi) for d in mapped_area]
    return mapped_radius

  # mapping the data
  mapped_df = data_mapper(funnel_df)
  colors = ['aliceblue', 'paleturquoise', 'darkturquoise', 'lightseagreen']

  # the circles
  for i in range(len(mapped_df)):
      ax.add_patch(
        mpatches.Circle( (0.5 + offset_x, mapped_df[i] + offset_y),
                        mapped_df[i],
                        color = colors[i]))

  kpi_text(ax,
       text = funnel_df[-1],
       text_color = 'white',
       font_size = fontsize_text,
       x_position = 0.5 + offset_x,
       y_position = mapped_df[-1] + 0.01 + offset_y)


  for i in range(len(mapped_df) - 2, -1, -1):
      kpi_text(ax,
               text = funnel_df[i],
               text_color = 'teal',
               font_size = fontsize_text,
               x_position = 0.5 + offset_x,
               y_position = mapped_df[i + 1] + mapped_df[i] + 0.01 + + offset_y)

  cols = ['Created', 'Accepted', 'Trialed', 'Won']

  for i in range(len(cols) - 2, -1, -1):
      kpi_text(ax,
               text = cols[i],
               text_color = 'steelblue',
               font_size = fontsize_text/1.7,
               x_position = 0.5 + offset_x,
               y_position =  mapped_df[i] + mapped_df[i+1] - 0.05 + 0.01 + offset_y)
  kpi_text(ax,
       text = cols[-1],
       text_color = 'white',
       font_size = fontsize_text/1.7,
       x_position = 0.5 + offset_x,
       y_position = mapped_df[-1] - 0.05 + 0.01 + offset_y)


  return plt

periscope.image(kpi_chart())
Rate this article:
Comments
echaveze
7 - Data Storage
7 - Data Storage

Hi! I absolutely love this visual and would love to implement it! I am not sure however how to use this. I am using a regular live model and I tried adding that code to the widget script but I don't think that was the right way to do it... can you help me please?

Dami
Sisense Team Member
Sisense Team Member

@echaveze 

This post was originally written for periscope. You can similarly use this code using the Notebooks functionality built in to newer versions of Sisense (https://docs.sisense.com/main/SisenseLinux/working-with-notebooks-1.htm?TocPath=Notebooks%7C_____3), however you will need to make some changes.

Please first load data via sql from your live model in Query_1 in a notebook:

Dami_3-1701891461854.png

Next please use this updated code and click the + Code button below the SQL request window. Paste the code below in there:

 

#Use SisenseHelper.load_dataframe(string) with the name of a SQL cell to load the output as a dataframe.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection
colors = ['aliceblue', 'paleturquoise', 'darkturquoise', 'lightseagreen'] # You can change the colors here
cols = ['outer_circle', '2nd_circle', '3rd_circle', 'innermost_circle'] # You can change the names that will appear in the circles in the final image here
columnname = 'PATIENT_ID' # You can change the name of the column to reference here

# extract important variables from the data frame
def extract(df):
#   GET DATA FROM DATA FRAME
  if df.size == 0:
    return [0, 0, 0 , 0, 0]
  else:
    firstcircle = df.iloc[0][columnname]
    secondcircle = df.iloc[1][columnname]
    thirdcircle = df.iloc[2][columnname]
    fourthcircle = df.iloc[3][columnname]

# EXAMPLE DATA
#    firstcircle = 
#    secondcircle = 80
#    thirdcircle = 50
#    fourthcircle = 20
    return [firstcircle, secondcircle, thirdcircle, fourthcircle]


####################
# create text chart
####################
def kpi_text(ax, text = '', text_color = 'black', x_position = 0, y_position = 0.5, font_size = 13):
    return ax.text(x = x_position,
                   y = y_position,
                   s = text,
                   color = text_color,
                   family = 'sans-serif',
                   fontsize = font_size,
                   horizontalalignment = 'center',
                   verticalalignment = 'center')


# create the plot
def kpi_chart(df):

  # set up the figure
  fig, ax = plt.subplots(figsize = (5.5,5.5))

  fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
  ax.axis('off')

  # styling (colors and font sizes)
  mediumgray = '#999292'
  lightgray = '#c4c4c4'
  purples = plt.get_cmap('Purples_r')

  fontsize_text = 30
  offset_x = 0.1
  offset_y = 0.13

  # parse the data
#  funnel_df = extract()
#     use the following if you are using the extract_df function to parse the desired values
  funnel_df = extract(df)
  [firstcircle, secondcircle, thirdcircle, fourthcircle] = funnel_df

  # map the data
  def get_data_domain(data):
    return {'min': min(data), 'max': max(data)}

  def data_mapper(data = [None], outputsize = 0.5):
    #assumes zero-max domain normalization
    # 0.48 is the max radius with a bit of padding
    domain = get_data_domain(data)
    mapped_area =  [1.0 * d/domain['max'] * outputsize  for d in sorted(data, reverse=True)]
    mapped_radius = [np.sqrt(d/np.pi) for d in mapped_area]
    return mapped_radius

  # mapping the data
  mapped_df = data_mapper(funnel_df)
  

  # the circles
  for i in range(len(mapped_df)):
      ax.add_patch(
        mpatches.Circle( (0.5 + offset_x, mapped_df[i] + offset_y),
                        mapped_df[i],
                        color = colors[i]))

  kpi_text(ax,
       text = sorted(funnel_df, reverse=True)[-1],
       text_color = 'white',
       font_size = fontsize_text,
       x_position = 0.5 + offset_x,
       y_position = mapped_df[-1] + 0.01 + offset_y)


  for i in range(len(mapped_df) - 2, -1, -1):
      kpi_text(ax,
               text = sorted(funnel_df, reverse=True)[i],
               text_color = 'teal',
               font_size = fontsize_text,
               x_position = 0.5 + offset_x,
               y_position = mapped_df[i + 1] + mapped_df[i] + 0.01 + + offset_y)


  for i in range(len(cols) - 2, -1, -1):
      kpi_text(ax,
               text = cols[i],
               text_color = 'steelblue',
               font_size = fontsize_text/1.7,
               x_position = 0.5 + offset_x,
               y_position =  mapped_df[i] + mapped_df[i+1] - 0.05 + 0.01 + offset_y)
  kpi_text(ax,
       text = cols[-1],
       text_color = 'white',
       font_size = fontsize_text/1.7,
       x_position = 0.5 + offset_x,
       y_position = mapped_df[-1] - 0.05 + 0.01 + offset_y)


  return plt
df = SisenseHelper.load_dataframe('Query_1')
kpi_chart(df)
SisenseHelper.save_image(plt)

 


This code references a column name and will take the 1st, 2rd, 3rd and 4th rows of that column to retrieve the values: 

 

Dami_4-1701891554469.png

You can change the circle colors, circle names and which column is referenced to retrieve the data by changing the values entered on lines 7, 8 and 9:

 

Dami_5-1701891579780.png

Click the 'Run Python' button. You can click the chart button next to the 'Run Python' at the bottom of the code block however at this time, Code Block charts cannot be added to a dashboard. You can share notebooks with multiple charts like this for users to access and view, similarly to a dashboard.

Version history
Last update:
‎03-02-2023 09:32 AM
Updated by:
Contributors