Hi all,
Is there a way to push the Default Pie Charts from Dynamo 3.2.1 onto a Drafting View?
Something like Data-Shapes does for older versions of Revit?
I’m not aware of a Data-Shapes node that creates charts in Revit, but you can always draw the chart yourself (via Dynamo of course) based on the chart data. A pie chart is just a circle split into representative sections based on percentage of the total. Those are all things you can calculate and draw in Dynamo/Revit.
EDIT: Here’s a starting point.
I actually used to have a Revit family for this… yes I am a nerd.
The number of weird dynamic families I’ve created over the years for stuff like this is crazy. Unfortunately I almost never use them more than a few times.
I used mine every work day for like a year… then joined Autodesk never thought about it again…
A example using WPF and LiveCharts (Core) library (Accessible from the Dynamo environment )
code Python
code
import clr
import sys
import System
from System.IO import StringReader, FileStream, FileMode, MemoryStream, File, Path
from System.Collections.Generic import List
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
clr.AddReference("LiveChartsCore")
clr.AddReference("LiveChartsCore.SkiaSharpView")
clr.AddReference("LiveChartsCore.SkiaSharpView.WPF")
clr.AddReference('SkiaSharp')
import LiveChartsCore
from LiveChartsCore import *
from LiveChartsCore.SkiaSharpView import *
from LiveChartsCore.SkiaSharpView import PieSeries
from LiveChartsCore.SkiaSharpView.WPF import *
from SkiaSharp import SKColors
from LiveChartsCore.SkiaSharpView.VisualElements import LabelVisual
from LiveChartsCore.SkiaSharpView.Painting import SolidColorPaint
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System.Windows.Controls
from System.Windows.Controls import *
import System.Windows.Controls.Primitives
from System.IO import StringReader
from System.Xml import XmlReader
from System.Windows import LogicalTreeHelper
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
from System.Windows.Media.Imaging import RenderTargetBitmap, PngBitmapEncoder, BitmapFrame
import traceback
import time
# https://v0.lvcharts.com/App/examples/v1/Wpf/Pie%20or%20Doughnut
class MainWindow(Window):
LAYOUT2 = '''
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
Title="LiveCharts"
Width="404"
Height="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<UserControl Grid.Row="0" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="500">
<Grid>
<lvc:PieChart Name="Chart" LegendPosition="Bottom" />
</Grid>
</UserControl>
<!-- Add the Save Chart button at the bottom -->
<Button Grid.Row="1" Name="SaveButton" Content="Push on a draft view" Height="30" Margin="10"/>
</Grid>
</Window>'''
def __init__(self, title="MyTitle", keys=["A","B", "C"], values=[10,20,30]):
self.title = title
self._keys = keys
self._values = values
self.img_stream = None
xr = XmlReader.Create(StringReader(MainWindow.LAYOUT2))
self.winLoad = XamlReader.Load(xr)
# initialize a SeriesCollection and bind it to the PieChart
self.seriesCollection = List[ISeries]()
# populate the PieChart with data
for key, value in zip(keys, values):
pie_series = PieSeries[float]()
pie_series.Values = [value]
pie_series.Name = key
self.seriesCollection.Add(pie_series)
self.InitializeComponent()
def InitializeComponent(self):
#
try:
self.SaveButton = LogicalTreeHelper.FindLogicalNode(self.winLoad, "SaveButton")
self.SaveButton.Click += self.save_button_clicked
#
self.Chart = LogicalTreeHelper.FindLogicalNode(self.winLoad, "Chart")
self.Chart.Series = self.seriesCollection
# set the title using LabelVisual
lb_title = LabelVisual()
lb_title.Text=self.title
lb_title.TextSize=20
lb_title.Paint=SolidColorPaint(SKColors.Black)
self.Chart.Title = lb_title
except Exception as ex:
print(str(ex))
def save_button_clicked(self, sender, args):
"""Event handler for the Save Chart button click"""
try:
self.save_chart_to_memory()
self.winLoad.Close()
except Exception as e:
print(f"Error saving chart as image: {e}")
def save_chart_to_memory(self):
try:
# use RenderTargetBitmap to capture the visual content of the chart
dpi = 300
size = self.Chart.RenderSize
width = int(size.Width * dpi / 96)
height = int(size.Height * dpi / 96)
render_bitmap = RenderTargetBitmap(width, height, dpi, dpi, System.Windows.Media.PixelFormats.Pbgra32)
# Render the chart's visual tree to the RenderTargetBitmap
render_bitmap.Render(self.Chart)
# Prepare to save the rendered bitmap to a file
encoder = PngBitmapEncoder()
frames = List[BitmapFrame](encoder.Frames)
frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(render_bitmap))
encoder.Frames = frames
# save image to memoryStream
self.img_stream = MemoryStream()
encoder.Save(self.img_stream)
# reset the memory stream position to the beginning
self.img_stream.Seek(0, System.IO.SeekOrigin.Begin)
print(f"Chart successfully saved to memomry")
except Exception as e:
print(f"Error saving chart as image: {e}")
def create_draft_view(view_name):
filter_Name = System.Predicate[System.Object](lambda x : x.ViewFamily == ViewFamily.Drafting )
view_family_type = List[Element](FilteredElementCollector(doc).OfClass(ViewFamilyType).ToElements()).Find(filter_Name)
#
drafting_view = ViewDrafting.Create(doc, view_family_type.Id)
try:
drafting_view.Name = view_name
except:
drafting_view.Name = f"{view_name}_{int(time.time())}"
return drafting_view
def create_image_on_draft_view(img_stream, view_name):
TransactionManager.Instance.EnsureInTransaction(doc)
#
dft_view = create_draft_view(view_name)
#
temp_file_path = Path.GetTempFileName()
temp_file_path_png = Path.ChangeExtension(temp_file_path, ".png")
with File.OpenWrite(temp_file_path_png) as temp_file_stream:
img_stream.CopyTo(temp_file_stream)
#
image_options = ImageTypeOptions(temp_file_path_png, False, ImageTypeSource.Import)
placement_options = ImagePlacementOptions()
placement_options.PlacementPoint = BoxPlacement.Center
placement_options.Location = XYZ.Zero
#
image_type = ImageType.Create(doc, image_options)
image_instance = ImageInstance.Create(doc, dft_view, image_type.Id, placement_options)
#
TransactionManager.Instance.TransactionTaskDone()
TransactionManager.Instance.ForceCloseTransaction()
uidoc.RequestViewChange(dft_view)
return image_instance
my_window = MainWindow(IN[0], IN[1], IN[2])
my_window.winLoad.ShowDialog()
if my_window.img_stream is not None:
OUT = create_image_on_draft_view(my_window.img_stream, my_window.title)
(compatible Revit 2025+ with all python engines ‘except the last…
’)
EDIT 20/09/2024
It’s works now
Thank you for the options guys. I will test them when I have some free time
Thank you c.poupin. This is great.
Is there a way to input my own colours in it? I’ve been looking at the LiveCharts documentation but I can’t find anything about that
After some faffing around I’ve changed the code to this:
import clr
import sys
import System
from System.IO import StringReader, FileStream, FileMode, MemoryStream, File, Path
from System.Collections.Generic import List
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
clr.AddReference("LiveChartsCore")
clr.AddReference("LiveChartsCore.SkiaSharpView")
clr.AddReference("LiveChartsCore.SkiaSharpView.WPF")
clr.AddReference('SkiaSharp')
import LiveChartsCore
from LiveChartsCore import *
from LiveChartsCore.SkiaSharpView import *
from LiveChartsCore.SkiaSharpView import PieSeries
from LiveChartsCore.SkiaSharpView.WPF import *
from SkiaSharp import SKColors
from LiveChartsCore.SkiaSharpView.VisualElements import LabelVisual
from LiveChartsCore.SkiaSharpView.Painting import SolidColorPaint
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System.Windows.Controls
from System.Windows.Controls import *
import System.Windows.Controls.Primitives
from System.IO import StringReader
from System.Xml import XmlReader
from System.Windows import LogicalTreeHelper
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
from System.Windows.Media.Imaging import RenderTargetBitmap, PngBitmapEncoder, BitmapFrame
import traceback
import time
# https://v0.lvcharts.com/App/examples/v1/Wpf/Pie%20or%20Doughnut
class MainWindow(Window):
LAYOUT2 = '''
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
Title="LiveCharts"
Width="404"
Height="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<UserControl Grid.Row="0" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="500">
<Grid>
<lvc:PieChart Name="Chart" LegendPosition="Right" />
</Grid>
</UserControl>
<!-- Add the Save Chart button at the bottom -->
<Button Grid.Row="1" Name="SaveButton" Content="Push on a draft view" Height="30" Margin="10"/>
</Grid>
</Window>'''
def __init__(self, title="MyTitle", keys=["A","B", "C"], values=[10,20,30], colors=[SKColors.Red, SKColors.Green, SKColors.Blue]):
self.title = title
self._keys = keys
self._values = values
self.colors = colors
self.img_stream = None
xr = XmlReader.Create(StringReader(MainWindow.LAYOUT2))
self.winLoad = XamlReader.Load(xr)
# initialize a SeriesCollection and bind it to the PieChart
self.seriesCollection = List[ISeries]()
# populate the PieChart with data
for key, value, colors in zip(keys, values, colors):
pie_series = PieSeries[float]()
pie_series.Values = [value]
pie_series.Name = key
pie_series.Fill = SolidColorPaint(colors)
self.seriesCollection.Add(pie_series)
self.InitializeComponent()
def InitializeComponent(self):
#
try:
self.SaveButton = LogicalTreeHelper.FindLogicalNode(self.winLoad, "SaveButton")
self.SaveButton.Click += self.save_button_clicked
#
self.Chart = LogicalTreeHelper.FindLogicalNode(self.winLoad, "Chart")
self.Chart.Series = self.seriesCollection
# set the title using LabelVisual
lb_title = LabelVisual()
lb_title.Text=self.title
lb_title.TextSize=20
lb_title.Paint=SolidColorPaint(SKColors.Black)
self.Chart.Title = lb_title
except Exception as ex:
print(str(ex))
def save_button_clicked(self, sender, args):
"""Event handler for the Save Chart button click"""
try:
self.save_chart_to_memory()
self.winLoad.Close()
except Exception as e:
print(f"Error saving chart as image: {e}")
def save_chart_to_memory(self):
try:
# use RenderTargetBitmap to capture the visual content of the chart
dpi = 300
size = self.Chart.RenderSize
width = int(size.Width * dpi / 96)
height = int(size.Height * dpi / 96)
render_bitmap = RenderTargetBitmap(width, height, dpi, dpi, System.Windows.Media.PixelFormats.Pbgra32)
# Render the chart's visual tree to the RenderTargetBitmap
render_bitmap.Render(self.Chart)
# Prepare to save the rendered bitmap to a file
encoder = PngBitmapEncoder()
frames = List[BitmapFrame](encoder.Frames)
frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(render_bitmap))
encoder.Frames = frames
# save image to memoryStream
self.img_stream = MemoryStream()
encoder.Save(self.img_stream)
# reset the memory stream position to the beginning
self.img_stream.Seek(0, System.IO.SeekOrigin.Begin)
print(f"Chart successfully saved to memory")
except Exception as e:
print(f"Error saving chart as image: {e}")
def create_draft_view(view_name):
filter_Name = System.Predicate[System.Object](lambda x : x.ViewFamily == ViewFamily.Drafting )
view_family_type = List[Element](FilteredElementCollector(doc).OfClass(ViewFamilyType).ToElements()).Find(filter_Name)
#
drafting_view = ViewDrafting.Create(doc, view_family_type.Id)
try:
drafting_view.Name = view_name
except:
drafting_view.Name = f"{view_name}_{int(time.time())}"
return drafting_view
def create_image_on_draft_view(img_stream, view_name):
TransactionManager.Instance.EnsureInTransaction(doc)
#
dft_view = create_draft_view(view_name)
#
temp_file_path = Path.GetTempFileName()
temp_file_path_png = Path.ChangeExtension(temp_file_path, ".png")
with File.OpenWrite(temp_file_path_png) as temp_file_stream:
img_stream.CopyTo(temp_file_stream)
#
image_options = ImageTypeOptions(temp_file_path_png, False, ImageTypeSource.Import)
placement_options = ImagePlacementOptions()
placement_options.PlacementPoint = BoxPlacement.Center
placement_options.Location = XYZ.Zero
#
image_type = ImageType.Create(doc, image_options)
image_instance = ImageInstance.Create(doc, dft_view, image_type.Id, placement_options)
#
TransactionManager.Instance.TransactionTaskDone()
TransactionManager.Instance.ForceCloseTransaction()
uidoc.RequestViewChange(dft_view)
return image_instance
my_window = MainWindow(IN[0], IN[1], IN[2], IN[3])
my_window.winLoad.ShowDialog()
if my_window.img_stream is not None:
OUT = create_image_on_draft_view(my_window.img_stream, my_window.title)
But no colours are passing through
you need to use SkiaSharp.SKColor
import this
from SkiaSharp import SKColors, SKColor, SKColorF
then add this in your Initialization method
# convert dynamo color to hex color
hex_color = "#{:02X}{:02X}{:02X}".format(ds_color.Red, ds_color.Green, ds_color.Blue)
sk_color = SKColor.Parse(hex_color)
pie_series.Fill = SolidColorPaint(sk_color)
hmm, do I need to define what ds_color is? it gives me an error on that line. Where can I find the dynamo api docs if there is such a thing
Not much in the way of formal documentation, as the API is built for C# and most (all?) of the API calls are self documenting in your IDE. Doesn’t help for Python though.
The Dynamo Color class should be available after adding the following though:
clr.AddReference('DSCoreNodes')
import DSCore # enable design script in python
From there you can refer to the Dynamo color class via DSCore.Color
and proceeding with the rest of that line.
still crashing, although I just realised that the color range in dynamo has a 4th parameter an Alpha so maybe that’s why it does not like it?
Color range or color?
Color range has a few different constructors so knowing which you’re using is a must. Color has an Alpha, Red, Green, and Blue (hence the ARGB name). If you’re not providing all four inputs then the last parameter (blue) is likely omitted, but I don’t believe color ranges support alpha channels so it might be erroring out there. Best to run a smaller snippet to get that bit working.
That color range doesn’t indicate an alpha input. Just colors, indices and values as usual. Can you post your full graph for review and a .rvt file? I’ll try and have a look tonight.
It’s just a small test graph at the moment, it’s not using any data from a Revit model.
Pie Chart Test.dyn (39.8 KB)
Need to know which Revit build you’re in too.
Revit 2025.