Pie Chart to Drafting View

Hi,

here is the full version with input colors (Dynamo Colors)

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, SKColor, SKColorF 
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, keys, values, ds_colors):
        super().__init__()
        self.title = title
        self._keys = keys
        self._values = values
        self._ds_colors = ds_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, ds_color in zip(keys, values, ds_colors):
            pie_series = PieSeries[float]()
            pie_series.Values = [value]
            pie_series.Name = key
            # 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)
            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], 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)
3 Likes

Thank you for that c.poupin. Now to compare and see what I was doing wrong. :slight_smile:

1 Like