Hello everyone! I would like to know if there is a node in Dynamo that can act like UI.Messenger, a UI window pops up in the Revit interface to display information, except for the UI.Messenger displays text information, but this node can integrate the information into a pie chart.
The Pie chart node displays a pie chart in the Dynamo interface, but I need to display it in the Revit interface
Maybe Datashapes will do what you need?
1 Like
Thank you for your reply. But what I need is a node for outputting results, not an input node
all right…I found that Datashape can complete my task. Thank you for your reminder!
The pie chart created using Datashape is not very aesthetically pleasing. Can UI nodes achieve the same effect as above?
The python code in datashapes can be unwrapped and edited, if you want to dive into how they work you could use it as a platform to work from to get exactly what you want, just make sure you credit the original author in your code
Others may know of some other methods to achive this as well
I got it. thank you
Hi,
2 examples with Python (LiveCharts and Matplotlib)
- WPF + LiveCharts (IronPython) (LiveCharts library is included in Dynamo 2.19+)
be careful, there are some changes with dynamo 3 (the LiveCharts library has changed a little)
code IronPython wpf+LiveCharts
import clr
import sys
import System
#import net library
from System.Collections.Generic import List
clr.AddReference('System')
try:
clr.AddReference('System.Diagnostics')
except:pass
from System.Diagnostics import Process
net_clr_runtime_name = str(System.Environment.Version)
targetFrameworkAttribute = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(System.Runtime.Versioning.TargetFrameworkAttribute, False)[0].FrameworkName #.SingleOrDefault()
pocessName = Process.GetCurrentProcess().ProcessName
clr.AddReference("LiveCharts")
from LiveCharts import *
clr.AddReference("LiveCharts.Wpf")
from LiveCharts.Wpf import *
from LiveCharts.Defaults import *
try:
clr.AddReference("IronPython.Wpf")
clr.AddReference('System.Core')
clr.AddReference('System.Xml')
clr.AddReference('PresentationCore')
clr.AddReference('PresentationFramework')
except IOError:
raise
from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
from System.Windows.Controls import *
try:
import wpf
except ImportError:
raise
class MyForm(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:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
Title="Wpf + LiveCharts"
Width="404"
Height="419">
<Grid>
<UserControl
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500">
<Grid>
<lvc:PieChart Name="Chart" LegendLocation="Bottom" Series="{Binding tableValues}" Hoverable="False" DataTooltip="{x:Null}">
<lvc:PieChart.ChartLegend>
<lvc:DefaultLegend BulletSize="20"></lvc:DefaultLegend>
</lvc:PieChart.ChartLegend>
</lvc:PieChart>
</Grid>
</UserControl>
</Grid>
</Window>"""
def __init__(self, keys=["A","B", "C"], values=[10,20,30]):
self.ui = wpf.LoadComponent(self, StringReader(MyForm.LAYOUT2))
seriesCollection = SeriesCollection()
#
for i, j in zip(keys, values):
values = ChartValues[System.Double]()
values.Add(float(j))
seriesCollection.Add(PieSeries(Title=i,Values=values,DataLabels=True))
self.Chart.Series = seriesCollection
def appThread():
my_window = MyForm(IN[0], IN[1])
my_window.Show()
print(pocessName)
if pocessName == "Revit":
thread = appThread()
else:
thread = Application.Current.Dispatcher.Invoke(appThread)
- Winform + matplotlib (CPython3)
code python3 Winfom + matplotlib
import clr
import sys
import System
from System.Threading import Thread, ThreadStart, ApartmentState
#import net library
from System.Collections.Generic import List
clr.AddReference('System')
try:
clr.AddReference('System.Diagnostics')
except:pass
from System.Diagnostics import Process
net_clr_runtime_name = str(System.Environment.Version)
targetFrameworkAttribute = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(System.Runtime.Versioning.TargetFrameworkAttribute, False)[0].FrameworkName #.SingleOrDefault()
pocessName = Process.GetCurrentProcess().ProcessName
clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms
from System.Drawing import *
from System.Windows.Forms import *
from System.Drawing.Imaging import *
clr.AddReference('Python.Included')
import Python.Included as pyInc
path_py3_lib = pyInc.Installer.EmbeddedPythonHome
sys.path.append(path_py3_lib + r'\Lib\site-packages')
import io
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import base64
def decoThread(func):
def wrapper():
globals()['objForm'] = None
if pocessName == "Revit":
objForm = func()
else:
thread = Thread(ThreadStart(func))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()
return globals()['objForm']
return wrapper
class PieForm(Form):
def __init__(self, fig):
image_from_plot = PieForm.plt2arr(fig)
self.base64String = PieForm.ConvertToBitmap2(image_from_plot)
self.InitializeComponent()
def InitializeComponent(self):
self._pictureBox1 = System.Windows.Forms.PictureBox()
((System.ComponentModel.ISupportInitialize)(self._pictureBox1)).BeginInit()
self.SuspendLayout()
#
# pictureBox1
#
self._pictureBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
pic = System.Convert.FromBase64String(self.base64String)
self._pictureBox1.Image = System.Drawing.Image.FromStream(System.IO.MemoryStream(pic))
self._pictureBox1.Location = System.Drawing.Point(2, 2)
self._pictureBox1.Name = "pictureBox1"
self._pictureBox1.Size = self._pictureBox1.Image.Size # System.Drawing.Size(414, 413)
self._pictureBox1.TabIndex = 0
self._pictureBox1.TabStop = False
#
# Form40
#
self.ClientSize = self._pictureBox1.Size
self.Controls.Add(self._pictureBox1)
self.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent
self.Name = "PieForm"
self.Text = "Winform + matplotlib"
((System.ComponentModel.ISupportInitialize)(self._pictureBox1)).EndInit()
self.ResumeLayout(False)
@staticmethod
def plt2arr(fig):
"""
need to draw if figure is not drawn yet
"""
fig.canvas.draw()
rgba_buf = fig.canvas.buffer_rgba()
(w,h) = fig.canvas.get_width_height()
rgba_arr = np.frombuffer(rgba_buf, dtype=np.uint8).reshape((h,w,4))
return rgba_arr
@staticmethod
def ConvertToBitmap2(npImgArray):
bitmap_ = None
# remove alpha
if npImgArray.ndim == 3 and npImgArray.shape[-1] == 4:
npImgArray = npImgArray[:, :, :-1]
# convert to PIL Image
if npImgArray.ndim == 3:
image = Image.fromarray(npImgArray, "RGB")
else:
image = Image.fromarray(npImgArray, "L")
# convert to Python ByteArray
s = io.BytesIO()
plt.savefig(s, format='png', bbox_inches="tight")
plt.close()
s = base64.b64encode(s.getvalue()).decode("utf-8").replace("\n", "")
return s
@decoThread
def main():
total = sum(IN[1])
fig, ax = plt.subplots()
ax.pie(IN[1], labels=IN[0], autopct=lambda p: '{:.2f}'.format(p * total / 100), shadow=True)
objForm = PieForm(fig)
objForm.ShowDialog()
objForm = None
main()
3 Likes
thank you very much!!
1 Like