Dendogram












data
L0 L1 L2 L3 L4
x a a1
x a a2 a2a
x a a3
x b b1 b1a b1a1
x c c1
x c c2 c2a
x c c3

x d


script
#dataTable and ta (text area) are script parameters

#settings
delim = ","
cr = "\n"

#get list of filtered rows
rows = Document.ActiveFilteringSelectionReference.GetSelection(dataTable).AsIndexSet()

#generate tree
html = "<div class='tree'>"+cr # rendering text
r=0 # row #
l=0 # level
ll=0 # previous level
D=-1 # delta level change 
cc=[""]*(dataTable.Columns.Count+1) # previous level value


for row in rows:
c=0
for column in dataTable.Columns:
#get a cell value
v =  column.RowValues.GetFormattedValue(row) 
v = v if v!="(Empty)"  else ""

#is a node
isNode=v<>""

# record previous level and previous level value
if(isNode):
l=c+1

#calculate delta between levels
isBranch =v<>cc[l]
D=l-ll

if isBranch:

#construct text
if D>0 : html +=  "<ul>" * D + "<li><a>"+v+"</a>"+cr
if D<0 : html += "</ul>" * abs(D) + "<li><a>"+v+"</a>"+cr
if D==0 : html += "       <li><a>"+v+"</a></li</ul>"+cr


#record previous level and previous column value
ll=l
cc[l]=v

#increment col index
c+=1

#new row
#increment row index
r=0
#print cr + html + "</ul></div>"


#render results to a target textArea
from Spotfire.Dxp.Application.Visuals import HtmlTextArea
vis = ta.As[HtmlTextArea]()
vis.HtmlContent = html 

javascript (optional to make nodes collapsible)
//place this in the target textarea

$(function () {
    $('.tree li').hide();
    $('.tree li:first').show();
    $('.tree li').on('click', function (e) {
        var children = $(this).find('> ul > li');
        if (children.is(":visible")) children.hide('fast');
        else children.show('fast');
        e.stopPropagation();
    });

});


css (horizontal) 
/*Place this style in a different text area other than the target text area*/

<style>
* {margin: 0; padding: 0;}

.tree ul {
padding-top: 20px; position: relative;

transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li {
float: left; text-align: center;
list-style-type: none;
position: relative;
padding: 20px 5px 0 5px;

transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li::before, .tree li::after{
content: '';
position: absolute; top: 0; right: 50%;
border-top: 1px solid #ccc;
width: 50%; height: 20px;
}
.tree li::after{
right: auto; left: 50%;
border-left: 1px solid #ccc;
}

.tree li:only-child::after, .tree li:only-child::before {
display: none;
}

.tree li:only-child{ padding-top: 0;}

right connector from last child*/
.tree li:first-child::before, .tree li:last-child::after{
border: 0 none;
}

.tree li:last-child::before{ border-right: 1px solid #ccc;
border-radius: 0 5px 0 0;
-webkit-border-radius: 0 5px 0 0;
-moz-border-radius: 0 5px 0 0;
}
.tree li:first-child::after{
border-radius: 5px 0 0 0;
-webkit-border-radius: 5px 0 0 0;
-moz-border-radius: 5px 0 0 0;
}


.down-connector {
  position: absolute; top: -100; left: 50%;
border-left: 1px solid #ccc;
width: 0; 
  height: 20px;
}

.connector{
  position: absolute; 
  left: 50%;
border-left: 1px solid #ccc;
width: 0; 
  height: 20px;
}

.tree li a{
border: 1px solid #ccc;
padding: 5px 10px;
text-decoration: none;
color: #666;
font-family: arial, verdana, tahoma;
font-size: 11px;
display: inline-block;

border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;

transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li a:hover, .tree li a:hover + ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}

.tree li a:hover+ul li::after, 
.tree li a:hover+ul li::before, 
.tree li a:hover+ul::before, 
.tree li a:hover+ul ul::before{
border-color:  #94a0b4;
}

/*Time for some hover effects*/
/*We will apply the hover the the lineage of the element also*/
.tree li a:hover, .tree li a:hover + ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}

.tree li a:hover, .tree li a:hover + ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}

.tree li a:hover+div+ul li::after, 
.tree li a:hover+div+ul li::before, 
.tree li a:hover+div+ul::before, 
.tree li a:hover+div+ul ul::before{
border-color:  #94a0b4;
}


.tree li a:hover, .tree li a:hover + div+ ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
</style>


css vertical (one or the other)
<style>
.tree li {
    margin: 0px 0;
    list-style-type: none;
    position: relative;
    padding: 20px 5px 0px 5px;
}
.tree li::before {
    content:'';
    position: absolute;
    top: 0;
    width: 1px;
    height: 100%;
    right: auto;
    left: -20px;
    border-left: 1px solid #ccc;
    bottom: 50px;
}
.tree li::after {
    content:'';
    position: absolute;
    top: 30px;
    width: 25px;
    height: 20px;
    right: auto;
    left: -20px;
    border-top: 1px solid #ccc;
}
.tree li a {
    display: inline-block;
    border: 1px solid #ccc;
    padding: 5px 10px;
    text-decoration: none;
    color: #666;
    font-family: arial, verdana, tahoma;
    font-size: 11px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
}
 .tree > ul > li::before, .tree > ul > li::after {
    border: 0;
}
 .tree li:last-child::before {
    height: 30px;
}

 .tree li a:hover, .tree li a:hover+ul li a {
    background: #c8e4f8;
    color: #000;
    border: 1px solid #94a0b4;
}
 .tree li a:hover+ul li::after, .tree li a:hover+ul li::before, .tree li a:hover+ul::before, .tree li a:hover+ul ul::before {
    border-color: #94a0b4;
}

</style>

Popup filters (no js, no bs)






html

<style>
body {
  color: #333333;
  font-family: 'Helvetica', arial;
}
.wrap {
  padding: 40px;
  text-align: center;
}
hr {
  clear: both;
  margin-top: 40px;
  margin-bottom: 40px;
  border: 0;
}
h1 {
  font-size: 30px;
  margin-bottom: 40px;
}
p {
  margin-bottom: 20px;
}
.btn {
  background: #e06666;
  border: #e06666 solid 1px;
  border-radius: 3px;
  color: #fff;
  display: inline-block;
  font-size: 14px;
  padding: 8px 15px;
  text-decoration: none;
  text-align: center;
  min-width: 60px;
  position: relative;
  transition: color .1s ease;
}
.btn:hover {
  background: #555;
  border: #555 solid 1px;
}
.btn.btn-big {
  font-size: 18px;
  padding: 15px 20px;
  min-width: 100px;
}
.btn-close {
  color: #aaaaaa;
  font-size: 30px;
  text-decoration: none;
  position: absolute;
  right: 5px;
  top: 0;
}
.btn-close:hover {
  color: #919191;
}
.modal:before {
  content: "";
  display: none;
  background: rgba(0, 0, 0, 0.6);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
}
.modal:target:before {
  display: block;
}
.modal:target .modal-dialog {
  -webkit-transform: translate(0, 0);
  -ms-transform: translate(0, 0);
  transform: translate(0, 0);
  top: 20%;
}
.modal-dialog {
  background: #fefefe;
  border: #333333 solid 1px;
  border-radius: 5px;
  margin-left: -200px;
  position: fixed;
  left: 50%;
  top: -100%;
  z-index: 11;
  width: 360px;
  -webkit-transform: translate(0, -500%);
  -ms-transform: translate(0, -500%);
  transform: translate(0, -500%);
  -webkit-transition: -webkit-transform 0.3s ease-out;
  -moz-transition: -moz-transform 0.3s ease-out;
  -o-transition: -o-transform 0.3s ease-out;
  transition: transform 0.3s ease-out;
}
.modal-body {
  padding: 20px;
}
.modal-header,
.modal-footer {
  padding: 10px 20px;
}
.modal-header {
}
.modal-header h2 {
  font-size: 20px;
}
.modal-footer {
  text-align: right;
}
</style>


<!-- Button -->
<h1><center><a href="#modal-one" ><SpotfireControl id="6b028e3cabee4567b4e4081cd2459d63" /></a><center></h1>

<!-- Modal -->
<div class="modal" id="modal-one" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-header">
      <h2>Select Date</h2>
      <a href="#" class="btn-close" aria-hidden="true">x</a>
    </div>
    <div class="modal-body">
      <p><SpotfireControl id="369d6997db7249718618a82baa23023b" /></p>
    </div>
    <div class="modal-footer">
      <a href="#" class="btn">OK</a>
    </div>
  </div>
</div>


js
no javascrip required!

Send email with PDF

# This script sends a pdf via email
from System import IO, Net, DateTime
from System.Net import Mail, Mime
from System.Text import Encoding

#1. Configure email
#gmail settings    : smtp.gmail.com,  port:587 encription=True credentials=True)
#corporate settings: smtp.contoso.com,port:25  encription=False credentials=False)
SMTPClient = "smtp.gmail.com"
SMTPPort = 587
useEncription = True
useCredentials = True

fromEmail = "your@gmail.com"
toEmail ="someone@acompany.com"
fromEmailUsr = fromEmail
fromEmailPwd = "y0urP4$$w0rd!"
filename = "test.pdf"
myMailSubject = "PDF email from a spotfire geek"
myMailBody = "Attached find pdf"
PDFattachment= "C://temp//test.pdf"

#2. Prepare email
MyMailMessage = Mail.MailMessage()
MyMailMessage.From = Mail.MailAddress(fromEmail)
MyMailMessage.To.Add(toEmail)
MyMailMessage.Subject = myMailSubject
MyMailMessage.Body = myMailBody
ct = Mime.ContentType(Mime.MediaTypeNames.Application.Pdf)

#3. Attach PDF file
attach = Mail.Attachment(PDFattachment, ct) 
attach.ContentDisposition.FileName = filename 
MyMailMessage.Attachments.Add(attach)
Mail.Attachment(PDFattachment, ct)

#4. Send email
emailSender = Mail.SmtpClient(SMTPClient)
emailSender.Port = SMTPPort
if useCredentials: emailSender.Credentials = Net.NetworkCredential(fromEmailUsr, fromEmailPwd)
emailSender.EnableSsl = useEncription
emailSender.Send(MyMailMessage)

print "Email sent!"

Render HTML from Data Table

html
<span id='dropDownDocProp' style='display:none'>
<SpotfireControl id="calculatedValueGoesHere123" />
calculated value expression: first([myHTMLColumn])
</span>

<div id="here">html renders here</div>

js
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

//this is the target element to monitor changes
//just put the span id here. You can remove next line and add a script param called targetDomId
var targetDomId = "dropDownDocProp"

//function when dropdown value changes
var myFunction = function(oldValue,newValue){
$("#here").html(newValue)
}


//no need to change after this line.
var target = document.getElementById(targetDomId)

//callback is the function to trigger when target changes
var oldVal = target.innerText.trim()
var callback = function(mutations) {
 newVal=$('#'+targetDomId+' ').text()
 if(newVal!=oldVal) myFunction(oldVal,newVal)
 oldVal = newVal;
}

//this is to glue these two together
var observer = new MutationObserver(callback);

var opts = {
    childList: true, 
    attributes: true, 
    characterData: true, 
    subtree: true
}


observer.observe(target,opts);




Sample Data
copy the text below and add a data table from clipboard in spotfire

ID Detail
2 "<div style=""position:relative;""> <div style=""opacity:0.5;position:absolute;left:50px;top:-30px;width:300px;height:150px;background-color:#40B3DF""></div> <div style=""opacity:0.3;position:absolute;left:120px;top:20px;width:100px;height:170px;background-color:#73AD21""></div> <div style=""margin-top:30px;width:360px;height:130px;padding:20px;border-radius:10px;border:10px solid #EE872A;font-size:120%;""> <h1>CSS = Styles and Colors</h1> <div style=""letter-spacing:12px;font-size:15px;position:relative;left:25px;top:25px;"">Manipulate Text</div> <div style=""color:#40B3DF;letter-spacing:12px;font-size:15px;position:relative;left:25px;top:30px;"">Colors, <span style=""background-color:#B4009E;color:#ffffff;""> Boxes</span></div> </div> </div>"
3 "<style> table { width:100%; } table, th, td { border: 1px solid black; border-collapse: collapse; } th, td { padding: 5px; text-align: left; } table.names tr:nth-child(even) { background-color: #eee; } table.names tr:nth-child(odd) { background-color:#fff; } table.names th { background-color: black; color: white } </style> </head> <body><table> <tr> <th>Firstname</th> <th>Lastname</th> <th>Age</th> </tr> <tr> <td>Jill</td> <td>Smith</td> <td>50</td> </tr> <tr> <td>Eve</td> <td>Jackson</td> <td>94</td> </tr> <tr> <td>John</td> <td>Doe</td> <td>80</td> </tr> </table><br><table class=""names""> <tr> <th>Firstname</th> <th>Lastname</th> <th>Age</th> </tr> <tr> <td>Jill</td> <td>Smith</td> <td>50</td> </tr> <tr> <td>Eve</td> <td>Jackson</td> <td>94</td> </tr> <tr> <td>John</td> <td>Doe</td> <td>80</td> </tr> </table>"
7 "<style> .flex-container { display: -webkit-flex; display: flex; -webkit-flex-flow: row wrap; flex-flow: row wrap; text-align: center; } .flex-container > * { padding: 15px; -webkit-flex: 1 100%; flex: 1 100%; } .article { text-align: left; } header {background: black;color:white;} footer {background: #aaa;color:white;} .nav {background:#eee;}.nav ul { list-style-type: none; padding: 0; } .nav ul a { text-decoration: none; }@media all and (min-width: 768px) { .nav {text-align:left;-webkit-flex: 1 auto;flex:1 auto;-webkit-order:1;order:1;} .article {-webkit-flex:5 0px;flex:5 0px;-webkit-order:2;order:2;} footer {-webkit-order:3;order:3;} } </style><div class=""flex-container""> <header> <h1>City Gallery</h1> </header><nav class=""nav""> <ul> <li><a href=""#"">London</a></li> <li><a href=""#"">Paris</a></li> <li><a href=""#"">Tokyo</a></li> </ul> </nav><article class=""article""> <h1>London</h1> <p>London is the capital city of England. It is the most populous city in the United Kingdom, with a metropolitan area of over 13 million inhabitants.</p> <p>Standing on the River Thames, London has been a major settlement for two millennia, its history going back to its founding by the Romans, who named it Londinium.</p> <p><strong>Resize this page to see what happens!</strong></p> </article></div>"
10 "<style> body {background-color: powderblue;} h1 {color: red;} p {color: blue;} </style> <h1>This is a Heading</h1> <p>This is a paragraph.</p> <script> function myFunction() { document.getElementById(""demo"").innerHTML = ""Hello JavaScript!""; } </script> </head> <body> <h1>My Web Page</h1> <p id=""demo"">A Paragraph</p> <button type=""button"" onclick=""myFunction()"">Try it</button><img src=""https://www.w3schools.com/images/html5.gif""> "

Change sparkline color on Graphical Table

from Spotfire.Dxp.Application. Visuals import VisualTypeIdentifiers
from Spotfire.Dxp.Application. Visuals.Miniatures import GraphicalTable, SparklineMiniatureVisualization 
from System.Drawing import Color 

#graphPlot is a GraphicalTable visualization script parameter
#color is a string document property holding values like "red", "blue" or "papayawhip" 

for column in graphPlot.As[GraphicalTable]() .Columns: 
    if column.Visualization.TypeId == VisualTypeIdentifiers. SparklineMiniatureVisualization: 
print column.Title
if column.Title == "Trend": 
#column.Visualization.LineColor = Color.FromArgb(R,G,B)
column.Visualization.LineColor = Color.FromName(color)



Thanks to Mike Akister and Adam W!

nice little round button



html
<span id="btn"><SpotfireControl id="fe2511f37ad94401ae64dc4f59d1cf24" /></span>

js
$("#btn input").css({
    "color": "#26A2ED",
    "border-radius": "60%",
    "height": "30px",
    "width": "30px",
    "font-size": "8px",
    "padding": "0px",
    "position": "absolute"
})

slideshow

To loop through pages automatically we need a javascript timer on each page to trigger an iron python script that changes to the next page.




html
<FONT size=6><SPAN>the iron python script switches to the next page</SPAN></FONT> 

<DIV id=switchPageBtn><SpotfireControl id="ff8993c967e049f580fed8aa9b25ec45" /></DIV>


js
$(function(){
clearTimeout(document.body.timeout);
document.body.timeout=setTimeout(function(){$('#switchPageBtn input').click();}, 3000)
});

script 
#current page number
cp = Document.Pages.IndexOf(Document.ActivePageReference)

#total pages
tp = Document.Pages.Count

#calculate next page
np = cp+1 if cp+1<tp else 0

#go to next page
Document.ActivePageReference = Document.Pages[np]


Slide menu



html

<script src='//cdn.muicss.com/mui-0.4.6/js/mui.js'></script>

<style>

#sidedrawer {
  position: fixed;
  top: 0;
  bottom: 0;
  width: 300px;
  left: -300px;
  overflow: auto;
  z-index: 2;
  background-color: #fff;
  border:1px solid lightblue;
  top:27px;
  transition: transform 0.2s;
}

@media (min-width: 768px) {
  #sidedrawer {
    transform: translate(300px);
  }

  body.hide-sidedrawer #sidedrawer {
    transform: translate(0px);
  }
}

#sidedrawer ul {
  list-style: none;
}

#sidedrawer > ul {
  padding-left: 0px;
}

#sidedrawer > ul > li:first-child {
  padding-top: 15px;
}

#sidedrawer strong {
  display: block;
  padding: 15px 22px;
  cursor: pointer;
}

#sidedrawer strong:hover {
  background-color: #E0E0E0;
}

#sidedrawer strong + ul > li {
  padding: 6px 0px;
}

.closebtn{
  cursor: pointer;
}
</style>

<b  class="closebtn js-hide-sidedrawer"><font size=4>☰</font></b>  click the hamburger to to open the menu

<div id="sidedrawer" class="mui--no-user-select">
click the top right button to close the menu 
 <div style='float:right;cursor:hand;font-size:20px' class="closebtn js-hide-sidedrawer">☒</div>
<div class="mui-divider"></div> 
<ul>
  <li class="active">
    <strong>Options</strong> 
    <ul> 
      <li>This is a List Box filter </li>
      <li><SpotfireControl id="8e46dc29e17746e38b69ed088933e1fc" /></li>
    </ul>
  </li>
  <li>
    <strong>More Options</strong>
    <ul> 
      <li>This is a Check Box filter</li>
      <li><SpotfireControl id="a5d461b193084a338c6b4c4d0cfb0cea" /></li>
    </ul>
  </li>
</ul> 
</div>
</div>
</div>


js

jQuery(function($) {
  var $bodyEl = $('body'),
      $sidedrawerEl = $('#sidedrawer');
  
  
  function showSidedrawer() {
    // show overlay
    var options = {
      onclose: function() {
        $sidedrawerEl
          .removeClass('active')
          .appendTo(document.body);
      }
    };
    
    var $overlayEl = $(mui.overlay('on', options));
    
    // show element
    $sidedrawerEl.appendTo($overlayEl);
    setTimeout(function() {
      $sidedrawerEl.addClass('active');
    }, 20);
  }
  
  
  function hideSidedrawer() {
    $bodyEl.toggleClass('hide-sidedrawer');
  }
  
  
  $('.js-show-sidedrawer').on('click', showSidedrawer);
  $('.js-hide-sidedrawer').on('click', hideSidedrawer);
  
  
  var $titleEls = $('strong', $sidedrawerEl);
  
  $titleEls
    .next()
    .hide();
  
  $titleEls.on('click', function() {
    $(this).next().slideToggle(200);
  });
});