Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7018 Articles
article-image-microsoft-dynamics-nav-diagnosing-code-problems
Packt
13 May 2011
7 min read
Save for later

Microsoft Dynamics NAV: Diagnosing Code Problems

Packt
13 May 2011
7 min read
No one writes perfect code on their first attempt. When running hundreds or even thousands of lines of code at a time, it can be extremely difficult to determine exactly where an error occurred and what caused it. That's why we have tools like the Debugger, Code Coverage, and Client Monitor in Microsoft Dynamics NAV. For the most part the recipes in this article will not deal with writing your own code or writing better code. Instead, we will focus more on how you can determine what is happening with the code you have already written. Using the debugger This recipe will show you how to use the debugger to examine the code that is currently executing. We will demonstrate how to go through the code line-by-line and watch how values and objects change. How to do it... Create a new codeunit from Object Designer. Add the following global variable: Add the following global text constant: Add a global function called ChangeCustomerName. The function should take in the following parameter: Add the following code to the function: Customer.Name := NewName; Add the following code to the OnRun trigger: Customer.FINDFIRST; ChangeCustomerName(Text001); Customer.VALIDATE("Post Code"); Save and close the codeunit. From the Tools menu in the NAV client select Debugger | Active (Shift + Ctrl + F11). From the Tools menu in the NAV client select Debugger | Breakpoint on Triggers (Shift + Ctrl + F12). Run the codeunit. How it works... When you run the codeunit, the Microsoft Dynamics NAV Debugger window will appear just like the one shown in the following screenshot: (Move the mouse over the image to enlarge it.) Before we get into the details of this window, we need to understand what caused it to appear. Setting the debugger to Active from the Tools | Debugger menu means that the debugger window will open every time the system encounters an error. In this case, though, we know our code doesn't produce any errors. We want to look at it anyway so we turn on the Breakpoint on Triggers option as well. There are five components to the debugger window. The first is the menu and toolbar at the very top. They function just like any other toolbars you've seen. You can mouse over each button to get a tool tip of what it does. The second component sits right below and contains the actual code from the current object. Here you can see a small yellow arrow pointing to the first line of our codeunit in the OnRun trigger. This is the line that is about to execute. Note that it has NOT executed yet. We'll explore each of the other three components as we move through our code. Use the F8 key or click on the Step Into button on the toolbar. The window will now look like the one shown in the following screenshot: (Move the mouse over the image to enlarge it.) The yellow arrow has moved to the second line of code and the first line has executed. Notice the red text in the bottom left-hand corner. This is the Variables window (bottom left window). It lists all the variables and their values from the current object. At first, our customer variable was uninitialized because we had not executed the Customer.FINDFIRST line. That line retrieved a record from the database causing the value of the variable to change. This text will only remain red until you take another step into the program. The next line of code that will execute is: ChangeCustomerName(Text001); What is this Text001 variable? If you're unsure of the value of a text constant, or you don't want to scroll through a possibly long list of variables in the Context window, you can add a shortcut to the Watch List (bottom right window). Right-click on Text001 and go to Add Watch. The variable will be added to the Watch List along with its current value. Go ahead and hit F8 to step into the next line. (Move the mouse over the image to enlarge it.) The yellow arrow jumps to the function that we just called. That brings us to our last window, the Call Stack (bottom middle window). It is important to know how you got to the code you are currently viewing. By looking at the Call Stack you can see that we were in the OnRun trigger of the codeunit and then jumped to the ChangeCustomerName function. You can click on each level of the stack to see the code for that object. (Move the mouse over the image to enlarge it.) You may not always want to go through your code line-by-line, though. Try hitting the F5 key or the Go command from the Debug menu. This will cause you to jump to the next function which is called instead of the next line. You will find yourself in a complete new object, the Customer table. Notice how the Context menu completely changes because the old variables are no longer in scope. They do not belong to the current object being examined. There's more... One common annoyance is trying to stop the debugger. You will find yourself in the middle of debugging your code and have that "Aha! I know what's wrong!" moment. You will click on the "X" to close the window only to have the debugger pop right back up at you. From the Debug menu click on Stop Debugging (Shift + F5). This will stop the debugger until you turn it on again and, more importantly, allow you to continue with your development. Stop Debugging also performs a rollback of the changes that have happened to the database since you started the debugger. Setting breakpoints Stepping through code line-by-line or function-by-function can take forever. Luckily there is an easy way to tell the debugger to stop right where we want it to. How to do it... Create and save the same codeunit discussed in the Using the debugger recipe in this article. Design the codeunit. Go to the following line of code in the OnRun trigger: ChangeCustomerName(Text001); Press F9 twice. Go to the following line of code in the OnRun trigger: VALIDATE("Post Code"); Press F9 once. Your window should look like the following screenshot: Save and close the codeunit. From the Tools menu in the NAV client select Debugger | Active (Shift + Ctrl + F11). Run the codeunit. How it works... When running the debugger on this codeunit, it should stop on Customer.VALIDATE("Post Code") line of code. This is because we have set a breakpoint here, which was the filledin red circle at the left of that line. The debugger stops right where we tell it to, that is right before that line of code executes. You will notice another mark. It is a red circle that is not filled. This is used to mark old breakpoints that you are not currently using. This is useful when you are trying to debug large amounts of code and want to temporarily remove a breakpoint or remember where you had one. There's more... The debugger is not perfect by any means. Some might even say it has a mind of its own sometimes. It doesn't always stop exactly where you want it to. It is common practice to set a breakpoint on a few successive lines of code in order to ensure that you stop in the general area.
Read more
  • 0
  • 0
  • 2016

article-image-pfsense-faqs
Packt
13 May 2011
4 min read
Save for later

pfSense FAQs

Packt
13 May 2011
4 min read
  pfSense 2 Cookbook A practical, example-driven guide to configuring even the most advanced features of pfSense 2.0       Read more about this book       (For more resources related to this subject, see here.) Q: What are the minimum hardware requirements for pfSense? A: The minimum requirements for a pfSense installation are 500Mhz, 128MB RAM, and 1GB hard disk space. Q: How does pfSense identify and assign interfaces? A: pfSense, like any other computer operating system, references each NIC by some unique value (fxp0, em0, em1, and so on). These unique identifiers are often associated with the driver being used and make it easier for us humans to use than the associated MAC address (00:80:0c:12:01:52). Taking that concept a step further, an interface is simply a named placeholder for each port: fxp0=WAN, em0=LAN, em1=DMZ, and so on. Q: How to enable the Secure Shell (SSH) service in pfSense? A: SSH is a networking protocol that allows encrypted communication between two devices. Enabling SSH allows secure access to the pfSense console remotely, just as if you were sitting in front of the physical console. Browse to System | Advanced | Secure Shell. Check Enable Secure Shell. You will be prompted for credentials when you connect (use the same username and password as the webGUI), but checking Disable password login for Secure Shell will allow you to use RSA keys instead. Leave the SSH port blank to use the default port: (Move the mouse over the image to enlarge it.) Save the changes and the SSH service will be started. Enabling the Secure Shell turns on pfSense's built-in SSH server to listen to requests on the port you've specified (port 22 by default). Like all pfSense services (unless otherwise noted), the SSH service will listen on every available interface. Like other services, firewall's rules are used to grant or deny access to these services.   Q: How does pfSense assign DNS servers to the DHCP clients? A: Specify any DNS server to be automatically assigned to our DHCP clients. If left blank, pfSense will automatically assign DNS servers to our clients in one of the following two ways: If DNS Forwarder is enabled, then the IP address of the interface is used. This is because the DNS Forwarder turns the pfSense machine itself into a DNS server, so the IP of the pfSense machine (that is, the gateway, which varies by interface) is assigned to each client. If DNS Forwarder isn’t enabled, then the DNS Servers configured on the General Setup page are used. And of course if, Allow DNS server list to be overridden by DHCP/PPP on WAN is enabled in General Setup, then the DNS servers obtained through the WAN will be used instead.   Q: What happens if the Register DHCP Leases in DNS Forwarder is enabled? A: If the Register DHCP Leases in DNS Forwarder option is enabled, pfSense will automatically register any devices that specify a hostname when submitting a DNS request. The downside, of course, is that not all devices submit a hostname and even when they do, it is sometimes cryptic. I prefer to only register important devices using DHCP static mappings, and all other (unimportant/unknown) devices can be referenced using their IP addresses. Q: What is an alias? What are the different types of aliases in pfSense? A: An alias is a place-holder (that is a variable) for information that may change. Aliases provide a degree of separation between our rules and values that may change in the future (for example, IP addresses, ports, and so on). It's best to use aliases whenever possible. The different types of aliases are as follows: Host alias: Selecting Host(s) as an alias Type allows you to create an alias that holds one or more IP addresses. Network alias: Selecting Network(s) as an alias Type allows you to create an alias that holds one or more networks (that is ranges of IP addresses). Port alias: Selecting Port(s) as an alias Type allows you to create an alias that holds one or more ports. OpenVPN Users alias: Selecting OpenVPN Users as an alias Type allows you to create an alias that holds one or more OpenVPN usernames. URL alias: Selecting URL as an alias Type allows you to create an alias that holds one or more URLs. URL Table alias: Selecting URL Table as an alias Type allows you to create an alias that holds a single URL pointing to a large list of addresses. This can be especially helpful when you need to import a large list of IPs and/or subnets. Using an alias: Aliases can be used anywhere you see a red textbox. Simply begin typing and pfSense will display any available aliases that match the text you've entered.
Read more
  • 0
  • 0
  • 4802

article-image-testing-python-using-doctest
Packt
13 May 2011
8 min read
Save for later

Testing in Python using doctest

Packt
13 May 2011
8 min read
Python Testing Cookbook Coding a test harness for doctest The doctest module supports creating objects, invoking methods, and checking results. With this recipe, we will explore this in more detail. An important aspect of doctest is that it finds individual instances of docstrings, and runs them in a local context. Variables declared in one docstring cannot be used in another docstring. The reader can benefit from the previous article on Python: Using doctest for Documentation. How to do it... Create a new file called recipe19.py to contain the code from this recipe. Write a simple shopping cart application. class ShoppingCart(object): def __init__(self): self.items = [] def add(self, item, price): self.items.append(Item(item, price)) return self def item(self, index): return self.items[index-1].item def price(self, index): return self.items[index-1].price def total(self, sales_tax): sum_price = sum([item.price for item in self.items]) return sum_price*(1.0 + sales_tax/100.0) def __len__(self): return len(self.items) class Item(object): def __init__(self, item, price): self.item = item self.price = price Insert a docstring at the top of the module, before the ShoppingCart class declaration. """ This is documentation for the this entire recipe. With it, we can demonstrate usage of the code. >>> cart = ShoppingCart().add("tuna sandwich", 15.0) >>> len(cart) 1 >>> cart.item(1) 'tuna sandwich' >>> cart.price(1) 15.0 >>> print round(cart.total(9.25), 2) 16.39 """ class ShoppingCart(object): ... Run the recipe using -m doctest and -v for verbosity. Copy all the code we just wrote from recipe19.py into a new file called recipe19b.py. Inside recipe19b.py add another docstring to item, which attempts to re-use the cart variable defined at the top of the module. def item(self, index): """ >>> cart.item(1) 'tuna sandwich' """ return self.items[index-1].item Run this variant of the recipe. Why does it fail? Wasn't cart declared in the earlier docstring? How it works... The doctest module looks for every docstring. For each docstring it finds, it creates a shallow copy of the module's global variables and then runs the code and checks results. Apart from that, every variable created is locally scoped and then cleaned up when the test is complete. This means that our second docstring that was added later cannot see the cart that was created in our first docstring. That is why the second run failed. There is no equivalent to a setUp method as we used with some of the unittest recipes. If there is no setUp option with doctest, then what value is this recipe? It highlights a key limitation of doctest that all developers must understand before using it. There's more... The doctest module provides an incredibly convenient way to add testability to our documentation. But this is not a substitute for a full-fledged testing framework, like unittest. As noted earlier, there is no equivalent to a setUp. There is also no syntax checking of the Python code embedded in the docstrings. Mixing the right level of doctests with unittest (or other testing framework we pick) is a matter of judgment. Filtering out test noise Various options help doctest ignore noise, such as whitespace, in test cases. This can be useful, because it allows us to structure the expected outcome in a better way, to ease reading for the users. We can also flag some tests that can be skipped. This can be used where we want to document known issues, but haven't yet patched the system. Both of these situations can easily be construed as noise, when we are trying to run comprehensive testing, but are focused on other parts of the system. In this recipe, we will dig in to ease the strict checking done by doctest. We will also look at how to ignore entire tests, whether it's on a temporary or permanent basis. How to do it... With the following steps, we will experiment with filtering out test results and easing certain restrictions of doctest. Create a new file called recipe20.py to contain the code from this recipe. Create a recursive function that converts base10 numbers into other bases. def convert_to_basen(value, base): import math def _convert(remaining_value, base, exp): def stringify(value): if value > 9: return chr(value + ord('a')-10) else: return str(value) if remaining_value >= 0 and exp >= 0: factor = int(math.pow(base, exp)) if factor <= remaining_value: multiple = remaining_value / factor return stringify(multiple) + _convert(remaining_value-multiple*factor, base, exp-1) else: return "0" + _convert(remaining_value, base, exp-1) else: return "" return "%s/%s" % (_convert(value, base, int(math.log(value, base))), base) Add a docstring that includes a test to exercise a range of values as well as documenting a future feature that is not yet implemented. def convert_to_basen(value, base): """Convert a base10 number to basen. >>> [convert_to_basen(i, 16) for i in range(1,16)] #doctest: +NORMALIZE_WHITESPACE ['1/16', '2/16', '3/16', '4/16', '5/16', '6/16', '7/16', '8/16', '9/16', 'a/16', 'b/16', 'c/16', 'd/16', 'e/16', 'f/16'] FUTURE: Binary may support 2's complement in the future, but not now. >>> convert_to_basen(-10, 2) #doctest: +SKIP '0110/2' """ import math Add a test runner. if __name__ == "__main__": import doctest doctest.testmod() Run the test case in verbose mode. Copy the code from recipe20.py into a new file called recipe20b.py. Edit recipe20b.py by updating the docstring to include another test exposing that our function doesn't convert 0. def convert_to_basen(value, base): """Convert a base10 number to basen. >>> [convert_to_basen(i, 16) for i in range(1,16)] #doctest: +NORMALIZE_WHITESPACE ['1/16', '2/16', '3/16', '4/16', '5/16', '6/16', '7/16', '8/16', '9/16', 'a/16', 'b/16', 'c/16', 'd/16', 'e/16', 'f/16'] FUTURE: Binary may support 2's complement in the future, but not now. >>> convert_to_basen(-10, 2) #doctest: +SKIP '0110/2' BUG: Discovered that this algorithm doesn't handle 0. Need to patch it. TODO: Renable this when patched. >>> convert_to_basen(0, 2) '0/2' """ import math Run the test case. Notice what is different about this version of the recipe; and why does it fail? Copy the code from recipe20b.py into a new file called recipe20c.py. Edit recipe20c.py and update the docstring indicating that we will skip the test for now. def convert_to_basen(value, base): """Convert a base10 number to basen. >>> [convert_to_basen(i, 16) for i in range(1,16)] #doctest: +NORMALIZE_WHITESPACE ['1/16', '2/16', '3/16', '4/16', '5/16', '6/16', '7/16', '8/16', '9/16', 'a/16', 'b/16', 'c/16', 'd/16', 'e/16', 'f/16'] FUTURE: Binary may support 2's complement in the future, but not now. >>> convert_to_basen(-10, 2) #doctest: +SKIP '0110/2' BUG: Discovered that this algorithm doesn't handle 0. Need to patch it. TODO: Renable this when patched. >>> convert_to_basen(0, 2) #doctest: +SKIP '0/2' """ import math Run the test case. How it works... In this recipe, we revisit the function for converting from base-10 to any base numbers. The first test shows it being run over a range. Normally, Python would fit this array of results on one line. To make it more readable, we spread the output across two lines. We also put some arbitrary spaces between the values to make the columns line up better. This is something that doctest definitely would not support, due to its strict pattern matching nature. By using #doctest: +NORMALIZE_WHITESPACE, we are able to ask doctest to ease this restriction. There are still constraints. For example, the first value in the expected array cannot have any whitespace in front of it. But wrapping the array to the next line no longer breaks the test. We also have a test case that is really meant as documentation only. It indicates a future requirement that shows how our function would handle negative binary values. By adding #doctest: +SKIP, we are able to command doctest to skip this particular instance. Finally, we see the scenario where we discover that our code doesn't handle 0. As the algorithm gets the highest exponent by taking a logarithm, there is a math problem. We capture this edge case with a test. We then confirm that the code fails in classic test driven design (TDD) fashion. The final step would be to fix the code to handle this edge case. But we decide, in a somewhat contrived fashion, that we don't have enough time in the current sprint to fix the code. To avoid breaking our continuous integration (CI) server, we mark the test with a TO-DO statement and add #doctest: +SKIP. There's more... Both the situations that we have marked up with #doctest: +SKIP, are cases where eventually we will want to remove the SKIP tag and have them run. There may be other situations where we will never remove SKIP. Demonstrations of code that have big fluctuations may not be readily testable without making them unreadable. For example, functions that return dictionaries are harder to test, because the order of results varies. We can bend it to pass a test, but we may lose the value of documentation to make it presentable to the reader.  
Read more
  • 0
  • 0
  • 6651

article-image-silverstripe-24-creating-our-own-theme
Packt
12 May 2011
8 min read
Save for later

SilverStripe 2.4: Creating our Own Theme

Packt
12 May 2011
8 min read
Time for action - files and folders for a new theme We could start off from scratch, but let's not make it more complicated than necessary: Simply copy the BlackCandy theme to a new folder in the same directory. We'll just call it bar as the page should be for a bar business. Now reload the CMS backend and you should be able to switch to the new bar theme. As we won't use any of the available images we can delete all image files, but leave the folder intact—we'll add our own pictures later on. Basic layout Next, we'll create our page's general layout. Time to put our template skills into action! Here's the basic layout we want to create: So far it's a pretty basic page. We'll take a good look at the templates and basic structure but won't spend much time on the HTML and CSS specifics. Do, however pay attention on how to set up the different CSS files to make the most out of them. We won't list every line of code involved. If you'd prefer, you can simply copy the missing parts from the code provided here (Ch:2) File themes/bar/templates/Page.ss This page is pretty empty. We'll later add an intro page with a different structure, so the code these templates will share is rather limited. Time for action - the base page Add the following code to the file themes/bar/templates/Page.ss: <!doctype html> <html lang="$ContentLocale"> <head> <meta charset="utf-8"/> <% base_tag %> <title> <% if MetaTitle %> $MetaTitle <% else %> $Title <% end_if %> </title> $MetaTags(false) <link rel="shortcut icon" href="favicon.ico"/> <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"> </script> <![endif]--> </head> <body> $Layout <noscript> <br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp; <div><p> <b>Please activate JavaScript.</b><br/> Otherwise you won't be able to use all available functions properly... </p></div> </noscript> </body> </html> What just happened? The highlighted parts are SilverStripe specific: First, we set the language of our content. Depending on what you've selected during the installation process this can vary. By default, it will be: <html lang="en-US"> Setting the page's base; this can be useful when referencing images and external files. Depending on how you set up your system this will vary. Setting the title just like in the BlackCandy theme. Next, adding meta tags without the title element. These are only set if you actually enter them in the CMS on the Metadata tab on the desired page's Content tab. Empty fields are simply left out in the output. Only the SilverStripe note is set in any case. Finally, including the page's specific layout. The JavaScript we include for Internet Explorer versions before 9 fixes their inability to correctly render HTML5 tags. To learn more about the specific code, head over to https://code.google.com/p/html5shim/. Why HTML5? The motivation behind it isn't to stay buzz-word compliant. While HTML5 is not a finished standard yet, it already adds new features and makes the development a little easier. Take a look at the doctype declaration for example: that's much shorter than XHTML. Now there's a real chance of actually remembering it and not needing to copy it every time you start from scratch. New features include some very handy tags, but we'll come to those in the next code sample. The output on the final HTML page for the second and third elements (we've already taken a look at the first) in the header looks like the following listing. Which part in the template is responsible for which line or lines? <title>home</title> <meta name="generator" content="SilverStripe - http://silverstripe.org" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="keywords" content="some keyword" /> <meta name="description" content="the description of this page" /> Did you notice that there is no reference to a CSS file and the styling is still applied? Remember that CSS files are automagically included if you stick to the naming convention we've already discussed. File themes/bar/templates/Layout/Page.ss Now let's move beyond the basics and do something a bit more interesting. Time for action - the layout page Add the following code to the file themes/bar/templates/Layout/Page.ss: <div> <img src="$ThemeDir/images/background.jpg" alt="Background" id="background"/> </div> <section id="content" class="transparent rounded shadow"> <aside id="top"> <% include BasicInfo %> </aside> <% include Menu %> <section class="typography"> $Content $Form </section> </section> <% include Footer %> We rely on just three includes which are very easy to reuse on different pages. We then reference the page's content and possible forms (no comments will be required). The only template part we've not yet covered is the $ThemeDir. This is replaced by the path to our theme, in our case themes/bar/. So you don't need to worry about hard-coded paths when copying template files between different themes. You only need to take care of paths in the CSS files as they are not processed by the template engine. The includes: BasicInfo.ss, Menu.ss, and Footer.ss In the previous code segment, we've referenced three includes. Let's not forget to create them. Time for action - the includes The includes we're yet to explore are Menu.ss, BasicInfo.ss, and Footer.ss. The menu is very simple, we only include the first level, highlighting the currently active item, as we won't have more subpages: <nav id="menu"> <ul> <% control Menu(1) %> <li class="$Linkingmode"> <a href="$Link">$MenuTitle</a> </li> <% end_control %> </ul> </nav> BasicInfo.ss only contains the $ThemeDir placeholder besides good old HTML: <a href="home"> <img src="$ThemeDir/images/logo.png" alt="Logo" id="logo"/> </a> <ul id="details-first"> <li>Phone: <b>01 23456789</b></li> <li>Contact: <a href="contact">contact@bar.com</a></li> <li>Address: <a href="location">Bar Street 123</a></li> </ul> <div id="details-second"> <div class="left">Opening hours:</div> <div class="right"><p> <b>Mon - Thu 2pm to 2am</b><br/> <b>Fri - Sat 2pm to 4am</b> </p></div> </div> <a href="http://www.facebook.com/pages/"> <img src="$ThemeDir/images/facebook.png" alt="Facebook" id="facebook"/> </a> Be sure to replace bar.com with your own domain. However, using it here is quite fitting because we're making a page for a bar and http://www.bar.com is only a placeholder itself. It's derived from foobar or foo bar, a placeholder name often used in computer programming. But take a look at the site yourself for more information. Finally, the footer makes use of the $Now placeholder and the date formatter .Year to retrieve the current year: <footer> <span><a href="imprint">Imprint</a></span> <span>&copy; Bar $Now.Year</span> </footer> Have a go hero - create the layout and pages Now that we've gone over all of the content, it's time to build the page. Feel free to copy some code as we're not a typing class, but take careful note of every SilverStripe specific part, so you understand what you're doing. We use three includes, so create these files and remove the rest still available from BlackCandy as well as the unused templates/Layout/Page_results.ss. And don't forget to flush the cache by appending ?flush=all to the page's URL! When working with includes it will save you a lot of trouble. We've hardcoded some links to different pages in the template files. Make sure you add all necessary pages including the imprint, but don't add it to the menu.
Read more
  • 0
  • 0
  • 2646

article-image-ibm-lotus-domino-exploring-view-options-web
Packt
11 May 2011
8 min read
Save for later

IBM Lotus Domino: exploring view options for the web

Packt
11 May 2011
8 min read
Views are important to most Domino applications. They provide the primary means by which documents are located and retrieved. But working with views on the Web is often more complicated or less satisfactory than using views with the Notes client. Several classic view options are available for web applications, all of which have draw-backs and implementation issues. A specific view can be displayed on the Web in several different ways. So it is helpful to consider view attributes that influence design choices, in particular: View content View structure How a view is translated for the Web How a view looks in a browser Whether or not a view template is used View performance Document hierarchy In terms of content, a view contains: Data only Data and HTML tags In terms of structure, views are: Uncategorized Categorized In terms of the techniques used by Domino to translate views for the Web, there are four basic methods: Domino-generated HTML (the default) Developer-generated HTML (the view contains data and HTML tags) View Applet (used with data only views) XML (the view is transmitted to the browser as an XML document) The first three of these methods are easier to implement. Two options on the Advanced tab of View Properties control which of these three methods is used: Treat view contents as HTML Use applet in the browser If neither option is checked, then Domino translates the view into an HTML table and then sends the page to the browser. If Treat view contents as HTML is checked, then Domino sends the view to the browser as is, assuming that the developer has encoded HTML table tags in the view. If Use applet in the browser is checked, then Domino uses the Java View Applet to display the view. (As mentioned previously, the Java Applets can be slow to load, and they do require a locally installed JVM (Java Virtual Machine)). Using XML to display views in a browser is a more complicated proposition, and we will not deal with it here. Pursue this and other XML-related topics in Designer Help or on the Web. Here is a starting point: http://www.ibm.com/developerworks/xml/ In terms of how a view looks when displayed in a browser, two alternatives can be used: Native styling with Designer Styling with Cascading Style Sheets In terms of whether or not a view template is used, there are three choices: A view template is not used The default view template is used A view template created for a specific view is used Finally, view performance can be an issue for views with many: Documents Columns Column formulas Column sorting options Each view is indexed and refreshed according to a setting on the Advanced tab of View Properties. By default, view indices are set to refresh automatically when documents are added or deleted. If the re-indexing process takes longer, then application response time can suffer. In general, smaller and simpler views with fewer column formulas perform better than long, complicated and computationally intensive views. The topics in this section deal with designing views for the Web. The first few topics review the standard options for displaying views. Later topics offer suggestions about improving view look and feel. Understand view Action buttons As you work with views on the Web, keep in mind that Action buttons are always placed at the top of the page regardless of how the view is displayed on the Web (standard view, view contents as HTML) and regardless of whether or not a view template is used. Unless the Action Bar is displayed with the Java applet, Action buttons are rendered in a basic HTML table; a horizontal rule separates the Action buttons from the rest of the form. Bear in mind that the Action buttons are functionally connected to but stylistically independent of the view and view template design elements that display lower on the form. Use Domino-generated default views When you look at a view on the Web, the view consists only of column headings and data rows. Everything else on the page (below any Action buttons) is contained on a view template form. You can create view templates in your design, or you can let Domino provide a default form. If Domino supplies the view template, the rendered page is fairly basic. Below the Action buttons and the horizontal rule, standard navigational hotspots are displayed; these navigational hotspots are repeated below the view. Expand and Collapse hotspots are included to support categorized views and views that include documents in response hierarchies. The view title displays below the top set of navigational hotspots, and then the view itself appears. If you supply a view template for a view, you must design the navigational hotspots, view title, and other design elements that may be required. View contents are rendered as an HTML table with columns that expand or contract depending upon the width of cell contents. If view columns enable sorting, then sorting arrows appear to the right of column headings. Here is an example of how Domino displays a view by default on the Web: In this example, clicking the blue underscored values in the left-most Last Name column opens the corresponding documents. By default, values in the left-most column are rendered as URL links, but any other column—or several columns—can serve this purpose. To change which column values are clickable, enable or disable the Show values in this column as links option on the Advanced tab of Column Properties: Typically a title, subject, or another unique document attribute is enabled as the link. Out of the box default views are a good choice for rapid prototyping or for one-time needs where look-and-feel are less important. Beyond designing the views, nothing else is required. Domino merges the views with HTML tags and a little JavaScript to produce fully functional pages. On the down side, what you see is what you get. Default views are stylistically uninspiring, and there is not a lot that can be done with them beyond some modest Designer-applied styling. Many Designer-applied styles, such as column width, are not translated to the Web. Still, some visual improvements can be made. In this example, the font characteristics are modified, and an alternate row background color is added: Include HTML tags to enhance views Some additional styling and behavior can be coded into standard views using HTML tags and CSS rules. Here is how this is done: In this example, <font> tags surround the column Title. Note the square brackets that identify the tags as HTML: Tags can also be inserted into column value formulas: "[<font color='darkblue'>]" + ContactLast + "[</font>]" When viewed with a browser, the new colors are displayed as expected. But when the view is opened in Notes, it looks like this: (Move the mouse over the image to enlarge it.) The example illustrates how to code the additional tags, but frankly the same effects can be achieved using Designer-applied formatting, so there is no real gain here. The view takes longer to code and the final result is not very reader-friendly when viewed with the Notes client. That being said, there still may be occasions when you want to add HTML tags to achieve a particular result. Here is a somewhat more complicated application of the same technique. This next line of code is added to the Title of a column. Note the use of <sup> and <font> tags. These tags apply only to the message See footnote 1: Last Name[<sup><font color='red'>]See footnote 1[</font></sup>] The result achieves the desired effect: More challenging is styling values in view columns. You do not have access to the <td> or <font> tags that Domino inserts into the page to define table cell contents. But you can add <span> tags around a column value, and then use CSS rules to style the span. Here is what the column formula might look like: "[<span class='column1'>]" + ContactLast + "[</span>]" Here is the CSS rule for the column1 class: .column1 { background-color: #EEE; cursor: default; display: block; font-weight: bold; text-decoration: none; width: 100%; } These declarations change the background color of the cell to a light gray and the pointer to the browser default. The display and width declarations force the span to occupy the width of the table cell. The text underscoring (for the link) is removed and the text is made bold. Without the CSS rule, the view displays as expected: With the CSS rule applied, a different look for the first column is achieved:
Read more
  • 0
  • 0
  • 9010

article-image-ibm-lotus-domino-creating-action-buttons-and-adding-style-views
Packt
11 May 2011
7 min read
Save for later

IBM Lotus Domino: Creating Action Buttons and Adding Style to Views

Packt
11 May 2011
7 min read
IBM Lotus Domino: Classic Web Application Development Techniques A step-by-step guide for web application development and quick tips to enhance applications using Lotus Domino Provide view navigation buttons Simple views intended to provide information (for example, a table of values) or links to a limited number of documents can stand alone quite nicely, embedded on a page or a view template. But if more than a handful of documents display in the view, you should provide users a way to move forward and backward through the view. If you use the View Applet, enable the scroll bars; otherwise add some navigational buttons to the view templates to enable users to move around in it. Code next and previous navigation buttons If you set the line count for a view, only that number of rows is sent to the browser. You need to add Action buttons or hotspots on the view template to enable users to advance the view to the next set of documents or to return to the previous set of documents—essentially paging backward and forward through the view. Code a Next button with this formula: @DbCommand("Domino"; "ViewNextPage") Code a Previous button with this formula: @DbCommand("Domino"; "ViewPreviousPage") Code first and last buttons Buttons can be included on the view template to page to the first and last documents in the view. Code an @Formula in a First button's Click event to compute and open a relative URL. The link reopens the current view and positions it at the first document: @URLOpen("/"+@WebDbName+"/"+@Subset(@ViewTitle;-1) + "?OpenView&Start=1") For a Last button, add a Computed for Display field to the view template with this @Formula: @Elements(@DbColumn("":"NoCache"; "" ; @ViewTitle; 1)) The value for the field (vwRows in this example) is the current number of documents in the view. This information is used in the @Formula for the Last button's Click event: url := "/" + @WebDbName + "/" + @Subset(@ViewTitle;-1) ; @URLOpen(url + "?OpenView&Start=" + @Text(vwRows)) When Last is clicked, the view reopens, positioned at the last document. Please note that for very large views, the @Formula for field vwRows may fail because of limitations in the amount of data that can be returned by @DbColumn. Let users specify a line count As computer monitors today come in a wide range of sizes and resolutions, it may be difficult to determine the right number of documents to display in a view to accommodate all users. On some monitors the view may seem too short, on others too long. Here is a strategy you might adapt to your application, that enables users to specify how many lines to display. The solution relies on several components working together: Several Computed for display fields on the view template A button that sets the number of lines with JavaScript Previous and Next buttons that run JavaScript to page through the view The technique uses the Start and Count parameters, which can be used when you open a view with a URL. The Start parameter, used in a previous example, specifies the row or document within a view that should display at the top of the view window on a page. The Count parameter specifies how many rows or documents should display on the page. The Count parameter overrides the line count setting that you may have set on an embedded view element. Here are the Computed for display fields to be created on the view template. The Query_String_Decoded field (a CGI variable) must be named as such, but all the other field names in this list are arbitrary. Following each field name is the @Formula that computes its value: Query_String_Decoded: Query_String_Decoded vwParms: @Right(@LowerCase(Query_String_Decoded); "&") vwStart: @If(@Contains(vwParms; "start="); @Middle(vwParms; "start="; "&"); "1") vwCount: @If(@Contains(vwParms; "count="); @Middle(vwParms; "count="; "&"); "10") vwURL: "/" + @WebDbName + "/"+ @Subset(@ViewTitle;1) + "?OpenView" vwRows: @Elements(@DbColumn("":"NoCache"; ""; @ViewTitle; 1)) countFlag "n" newCount: "1" Add several buttons to the view template. Code JavaScript in each button's onClick event. You may want to code these scripts inline for testing, and then move them to a JavaScript library when you know they are working the way you want them to. The Set Rows button's onClick event is coded with JavaScript that receives a line count from the user. If the user-entered line count is not good, then the current line count is retained. A flag is set indicating that the line count may have been changed: var f = document.forms[0] ; var rows = parseInt(f.vwRows.value) ; var count = prompt("Number of Rows?","10") ; if ( isNaN(count) | count < 1 | count >= rows ) { count = f.vwCount.value ; } f.newCount.value = count ; f.countFlag.value = "y" ; The Previous button's onClick event is coded to page backward through the view using the user-entered line count: var f = document.forms[0] ; var URL = f.vwURL.value ; var ctFlag = f.countFlag.value ; var oCT = parseInt(f.vwCount.value) ; var nCT = parseInt(f.newCount.value) ; var oST = parseInt(f.vwStart.value) ; var count ; var start ; if ( ctFlag == "n" ) { count = oCT ; start = oST - oCT ; } else { count = nCT ; start = oST - nCT ; } if (start < 1 ) { start = 1 ; } location.href = URL + "&Start=" + start + "&Count=" + count ; The Next button pages forward through the view using the user-entered line count: var f = document.forms[0] ; var URL = f.vwURL.value ; var ctFlag = f.countFlag.value ; var oCT = parseInt(f.vwCount.value) ; var nCT = parseInt(f.newCount.value) ; var start = parseInt(f.vwStart.value) + oCT ; if ( ctFlag == "n" ) { location.href = URL + "&Start=" + start + "&Count=" + oCT ; } else { location.href = URL + "&Start=" + start + "&Count=" + nCT ; } Finally, if First and Last buttons are included with this scheme, they need to be recoded as well to work with a user-specified line count. The @formula in the First button's Click event now looks like this: count := @If(@IsAvailable(vwCount); vwCount; "10") ; parms := "?OpenView&Start=1&Count=" + count ; @URLOpen("/" + @WebDbName + "/" + @Subset(@ViewTitle;-1) + parms) ;7 The @formula in the Last button's Click event is also a little more complicated. Note that if the field vwRows is not available, then the Start value is set to 1,000. This is really more for debugging since the Start parameter should always be set to the value of vwRows: start := @If(@IsAvailable(vwRows); @Text(vwRows); "1000") ; count := @If(@IsAvailable(vwCount); vwCount; "10") ; parms := "?OpenView&Start=" + start + "&Count=" + count ; url := "/" + @WebDbName + "/" + @Subset(@ViewTitle;-1) ; @URLOpen(url + parms) ; Code expand and collapse buttons for categorized views Two other navigational buttons should be included on the view template for categorized views or views that include document hierarchies. These buttons expand all categories and collapse all categories respectively: The Expand All button's Click event contains this @Command: @Command([ViewExpandAll]) The Collapse All button's Click event contains this @Command: @Command([ViewCollapseAll]) Co-locate and define all Action buttons Action Bar buttons can be added to a view template as well as to a view. If Action buttons appear on both design elements, then Domino places all the buttons together on the same top row. In the following image, the first button is from the view template, and the last three are from the view itself: If it makes more sense for the buttons to be arranged in a different order, then take control of their placement by co-locating them all either on the view template or on the view. Create your own Action buttons As mentioned previously, Action Bar buttons are rendered in a table placed at the top of a form. But on typical Web pages, buttons and hotspots are located below a banner, or in a menu at the left or the right. Buttons along the top of a form look dated and may not comply with your organization's web development standards. You can replace the view template and view Action buttons with hotspot buttons placed elsewhere on the view template: Create a series of hotspots or hotspot buttons on the view template, perhaps below a banner. Code @formulas for the hotspots that are equivalent to the Action Bar button formulas. Define a CSS class for those hotspots, and code appropriate CSS rules. Delete or hide from the Web all standard Action Bar buttons on the view template and on the view.
Read more
  • 0
  • 0
  • 5684
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-zenoss-core-3-tips-and-tricks
Packt
10 May 2011
4 min read
Save for later

Zenoss Core 3: Tips and Tricks

Packt
10 May 2011
4 min read
Zenoss Core 3.x Network and System Monitoring Importing devices and attributes Tip: If you already have a list of the SNMP capable devices by hostname or IP address, Zenoss Core can import them via the zenbatchload command. In its simplest form, zebatchload will process a text file that lists one device per line. Here's a sample list of devices that I will call deviceList.txt: device01 router02 web03 Since zenbatchload is a Zenoss Core daemon, we need to run it as the zenoss user. Here are the commands: su - zenoss <enter zenoss user's password> zenbatchload deviceList.txt The zenbatchload import utility will not update devices that are already in the device inventory. Editing and moving organizers Tip: Editing organizers: You can change the name or description of an organizer by selecting the organizer and then clicking on Edit. You can find the Edit option by clicking on the Actions menu button (which looks like a sprocket) at the bottom of the Infrastructure sidebar. See the following screenshot: Moving organizers: You can nest organizers by dragging and dropping one organizer into another one to create a hierarchy. You can only nest similar organizers, which means that you cannot move a system into a group or a group into a location. Zeneventlog—unable to connect to Windows Tip: If you see an event that indicates zeneventlog is unable to connect to Windows, that's an indication Zenoss Core is not able to authenticate to the Windows server. Check the Configuration Properties (zProperties) of the device to ensure you have the correct username and password set. The following screenshot shows the WMI specific zProperties: Remember, the zWinUser and zWinPassword properties must be an administrator on the Windows server you're monitoring. It's possible that each of your Windows servers could require a different username and password. The zWinUser property can be either a local or a domain account. If you use a domain account, specify the domain for the zWinuser value (for example, mojoactiveadministrator). Zenoss Core does not collect WMI data Tip: It's possible that Zenoss Core isn't collecting any data from the Windows Servers via WMI, but there are no events reported. You can check the following zProperties at the device or class level: Make sure the device is using the zenoss.wmi.WinServiceMap collector plugin Set the zWmiMonitorIgnore property to False in the Configuration Properties for the device or device class If you want to collect event logs, set the zWinEventlog property to True in the Configuration Properties for the device or device class Acknowledging an event Tip: Acknowledging an event signals to other team members and to Zenoss Core that you are aware of the event and, presumably, taking action. Acknowledging the event is good communication among your team, but Zenoss Core can also escalate event severities or alerts based on an event status. A common way to escalate an event or an alert is by the event count. For example, we can instruct Zenoss Core to escalate the event severity from Error to Critical if the event hasn't been acknowledged after a specified number of monitoring cycles. Or if we're dealing with alerts, Zenoss Core can be configured to alert the next person on call, in the event you fall asleep on the roof at 3 in the morning and don't realize the database server has been down for 15 minutes. To acknowledge an event: Select the event from the Event Console by clicking on it. Click on the on Acknowledge Events button (the icon that looks like a check mark). A check mark will appear next to the event. See the following screenshot: In the screenshot all the events are acknowledged, except the first one.
Read more
  • 0
  • 0
  • 13125

article-image-cms-made-simple-application-user-defined-tags
Packt
10 May 2011
9 min read
Save for later

CMS Made Simple: Application of User-Defined Tags

Packt
10 May 2011
9 min read
CMS Made Simple Development Cookbook Over 70 simple but incredibly effective recipes for extending CMS Made Simple with detailed explanations – useful for beginners and experts alike! These recipes have been specially selected to demonstrate capabilities. While they may be useful as provided, they are designed to show the range of what can be done with tags, and to provide examples of useful operations such as setting Smarty variables, interfacing with the database, interacting with modules, and consuming data from remote web services. You are encouraged to use these recipes as starting points for your own projects. Introduction One of the most popular uses of CMS Made Simple involves an administrator who creates a basic site structure and template, and one or more editors who maintain page content without having to worry about the site layout. In this configuration, you can think of the CMS essentially as a big template engine with some utilities to add content. Each page of the site comprises a page template with areas that get populated with various kinds of content. These areas are either tags or variables, where the distinction is that a tag involves the execution of code, while a variable is a simple substitution of values. The CMS comes with a large assortment of built-in tags, including the fundamental "content" tag and a variety of useful supporting tags for building navigation, links, including images, and so forth. Because CMS Made Simple can be seen as being built around tags, it is not surprising that there are facilities for creating your own tags. You can create tags directly through the Admin panel—these are called User-Defined Tags or UDTs. If you want even more extensive capabilities in your tag, you can have those capabilities by creating a file that follows a few basic conventions. The template engine used by CMS Made Simple comes from the Smarty project. Pages are Smarty templates, and the built-in CMS tag types are all Smarty tags. Behind the scenes, both UDTs and file-based tags also become Smarty tags. For additional information on Smarty, the documentation provided by the Smarty project is invaluable. You can read more at http://www.smarty.net/docsv2/en/ Displaying the User's IP address from a User-Defined Tag This recipe demonstrates creating a very simple User-Defined Tag, and using it to display information, that it gets from PHP globally-defined variables. Getting ready For this recipe, you will need to have CMS Made Simple installed and working. You will need login access to the site's Administration area as a member of the "admin" group, or as a member of a group with permissions to "Modify User-Defined Tags" and "Manage All Content". How to do it... Log in to your CMS Administration area. Using the top menu, go to "Extensions" and click on "User Defined Tags". Click on the "Add User Defined Tag" button. In the "Name" field type "user_ip". In the "Code" text area, type the following code: echo 'Welcome user from '.$_SERVER['REMOTE_ADDR'].' -- enjoy your visit!'; Click on the "Submit" button. Using the top menu, go to "Content" and click on "Pages". Click on the "Add New Content" button. In the "Title" and "Menu Text" fields, type "Tag Test". In the "Content" text area, type the following code: {user_ip} Click on the "Submit" button. View your site from the user side. Click on the new "Tag Test" page. How it works... User-Defined Tags work by linking a piece of PHP code to a tag which is recognized by Smarty. When Smarty parses a template and encounters that tag, it executes the code in question, and substitutes the tag markup with any output from that PHP code. When we create a UDT in the CMS Made Simple admin area, the name we enter into the text field becomes the tag which Smarty will look for, and the code we enter into the text area is the PHP associated with the tag. This recipe is an example of outputting text directly from a User-Defined Tag. It works by echoing a string, that then replaces the {user_ip} tag in the content. This substitution of the tag can take place either in a page template or in the page content, which might seem a little confusing since it's stated earlier that Smarty processes tags that it finds in templates. The confusion, though, is mostly due to terminology; CMS Made Simple processes both layout templates and page content through Smarty, so while it is being processed, page content serves as a template from Smarty's perspective. The User-Defined Tag we create accesses one of the PHP "superglobals"—the $_SERVER variable . This variable contains information about the HTTP request and some environmental information about the PHP server. In this case, we're getting the user's IP address information to display. Using the CmsObject and the current content object in a User-Defined Tag This recipe shows you how to access the Page Content object via the CmsObject in a User-Defined Tag. The primary technique that it demonstrates—getting a reference to the CmsObject and using the CmsObject to get a reference to other important CMS runtime objects—is one that you will use to solve many different kinds of problems. In this recipe, we use the CmsObject to get a reference to the Page Content object. Once we have a reference to this object, we can call upon its methods to report all kinds of interesting information about the current page content. Getting ready For this recipe, you will need login access to your site's Administration area with permission to "Modify User-Defined Tags" and "Manage All Content". How to do it... Log in to your CMS Administration area. Using the top menu, go to "Extensions" and click on "User Defined Tags". Click on the "Add User Defined Tag" icon. In the "Name" field, type "content_description". In the "Code" field, type the following code: $gCms = cmsms(); $contentops = $gCms->GetContentOperations(); $content_obj = $contentops->getContentObject(); echo 'Current content object is "'.$content_obj->Name().'"<br />'; echo 'which was created on '.$content_obj->GetCreationDate().'<br />'; echo 'its alias is "'.$content_obj->Alias().'"<br />'; echo 'and its URL is "'.$content_obj->GetURL().'"<br />'; Click on the "Submit" button. Using the top menu, select "Content" and click on "Pages". Click on the "Add New Content" button. Enter "New Content Page" into the "Title" and "Menu Text" fields. In the "Content" field, enter: {content_description} Click on the "Submit" button. View your site from the user side. Click on the new "Content Page" page. How it works... CMS Made Simple uses an internal object called "CmsObject" to keep track of a great deal of what it needs to serve content. This information includes the site hierarchy, the installed and active modules, references to the database, and more. The CmsObject is available to Modules, Tags, and User-Defined Tags via the cmsms() function. In this recipe, we want to display information from the current Content object. However, this object is not directly accessible. To get access to this object, we need to make a static call to the ContentOperations object, but this object is also not directly accessible from our code. To get access to these objects, we need to get references to them. We start by gaining access to the CmsObject by calling the global cmsms() function. From our reference to the CmsObject, we request a reference to the ContentOperations object, that we then use to request a reference to the current content object. Once we have the current content object, we can call assorted methods on it to retrieve information about the current content. In this recipe, we get the content's name, when it was last modified, its alias, and its URL. Since this recipe is an example, we don't format these various pieces of information or use a template, but simply echo them. In a production UDT or one in which there's any complexity to what is being displayed, it would be more advisable to use the values to populate Smarty variables for later display, or use a template for formatting them. There's more... There are a number of interesting objects, that CmsObject manages. References can be requested to: BookmarkOperations— used in the Admin area ContentOperations—which has methods to handle Content and content metadata Db— which wraps the ADODB database API GlobalContentOperations— which has methods to handle Global Content Blocks GroupOperations— which has methods to handle Admin Groups HierarchyManager— which has methods for handling site content hierarchies ModuleOperations— which has methods for managing Modules Smarty— which wraps the Smarty template engine StylesheetOperations—which has methods for handling TemplateOperations— which has methods for handling Smarty templates UserOperations— which has methods for handling Admin Users UserTagOperations— which has methods for handling User-Defined Tags Getting attributes using page_attr If you're looking to display information about the current content object, CMS Made Simple has a custom Smarty tag that provides some attributes: {page_attr}. You can use this tag to display page attribute information—simply by specifying a key to the information you're requesting. For example, to get the page's "image" attribute, you could use the tag {page_attr key="image"}. Other keys that are supported include: target image thumbnail extra1 extra2 extra3 searchable pagedata disable_wysiwyg content_en As you can see, this is not as rich a collection of information as you can get from the content object directly using your own UDT. Old code and the use of globals If you look at old modules or User-Defined Tags that have been posted in the CMS Made Simple forum, you may see the following code: global $gCms; instead of the $gCms = cmsms() used here. For a long time, the use of the global declaration was the preferred way to access the CmsObject. This approach is now deprecated for a number of reasons, most important of which is a security issue and also including portability of code between CMS Made Simple 1.x and the upcoming 2.x versions. While use of the global declaration to access the CmsObject will likely still work, it is strongly discouraged.  
Read more
  • 0
  • 0
  • 4733

article-image-sage-3d-data-plotting
Packt
09 May 2011
6 min read
Save for later

Sage: 3D Data Plotting

Packt
09 May 2011
6 min read
  Sage Beginner's Guide Unlock the full potential of Sage for simplifying and automating mathematical computing        Time for action – make an interactive 3D plot Let's make an interactive 3D plot. var('x, y') p3d = plot3d(y^2 + 1 - x^3 - x, (x, -pi, pi), (y, -pi, pi)) p3d.show() If you run this example in the notebook interface, a Java applet called Jmol will run in the cell below the code. If you run it from the interactive shell, Jmol will launch as a stand-alone application. Clicking and dragging on the figure with the left mouse button will rotate the plot in 3D space. Clicking and dragging with the centre button, or moving the scroll wheel, zooms in and out. Right-clicking brings up a menu that allows you to set various options for Jmol. Since Jmol is also used to visualize the 3D structures of molecules, some of the options are not relevant for plotting functions. Here is a screenshot of the function, plotted with Jmol: What just happened? We made a cool 3D plot that allowed us to explore a function of two variables. When running Jmol as an applet in a worksheet, you can click on the "Get Image" link below the plot to save an image of the plot in its current state. However, the image quality is not particularly high because it is saved in JPEG format. When Jmol is called from the command line, it runs as a stand-alone application, and more options are available. You can save files in JPEG, GIF, PPM, PNG, or PDF format. Note that the PDF format is a bitmap embedded in a PDF file, rather than a true vector representation of the surface. The syntax for using plot3d is very simple: plot3d(f(x,y), (x, x_min, x_max), (y, y_min, y_max)) There are a few optional arguments to the show method that you can use to alter the appearance of the plot. Setting mesh=True plots a mesh on the surface, and setting dots=True plots a small sphere at each point. You can also use the transformation keyword argument to apply a transformation to the data—see the plot3d documentation for more information. Higher quality output We can improve the quality of saved images using ray tracing, which is an algorithm for generating images that is based on optical principles. Sage comes with ray tracing software called Tachyon, which can be used to view 3D plots. To activate Tachyon, use the show method with the viewer keyword as shown below: p3d.show(viewer='tachyon', frame=False, axes=True) Depending on the speed of your computer, the ray tracing may require a few seconds to a few minutes. The frame keyword selects whether or not to draw a box around the outer limits of the plot, while the axes keyword determines whether or not the axes are drawn. Parametric 3D plotting Sage can also plot functions of two variables that are defined in terms of a parameter. You can make very complex surfaces in this way. Time for action – parametric plots in 3D We will plot two interlocking rings to demonstrate how complex surfaces are easily plotted using three functions of two parameters: var('u, v') f1 = (4 + (3 + cos(v)) * sin(u), 4 + (3 + cos(v)) * cos(u), 4 + sin(v)) f2 = (8 + (3 + cos(v)) * cos(u), 3 + sin(v), 4 + (3 + cos(v)) * sin(u)) p1 = parametric_plot3d(f1, (u, 0, 2 * pi), (v, 0, 2 * pi), texture="red") p2 = parametric_plot3d(f2, (u, 0, 2 * pi), (v, 0, 2 * pi), texture="blue") combination = p1 + p2 combination.show() The result should look like this: What just happened? We made a very complex 3D shape using the parametric_plot3d function. The optional arguments for this function are the same as the options for the plot3d function. Contour plots Sage can also make contour plots, which are 2-D representations of 3-D surfaces. While 3D plots are eye-catching, a 2D plot can be a more practical way to convey information about the function or data set. Time for action – making some contour plots The following code will demonstrate four different ways to make a 2D plot of a 3D surface with Sage: var('x, y') text_coords = (2, -3.5) cp = contour_plot(y^2 + 1 - x^3 - x, (x, -3, 3), (y, -3, 3), contours=8, linewidths=srange(0.5, 4.0, 0.5), fill=False, labels=True, label_colors='black', cmap='gray', colorbar=False) cp += text("Contour", text_coords) ip = implicit_plot(y^2 + 1 - x^3 - x, (x, -3, 3), (y, -3, 3)) ip += text("Implicit", text_coords) rp = region_plot(y^2 + 1 - x^3 - x < 0, (x, -3, 3), (y, -3, 3), incol=(0.8, 0.8, 0.8)) # color is an (R,G,B) tuple rp += text("Region", text_coords) dp = density_plot(y^2 + 1 - x^3 - x, (x, -3, 3), (y, -3, 3)) dp += text("Density", text_coords) show(graphics_array([cp, ip, rp, dp], 2, 2), aspect_ratio=1, figsize=(6, 6)) The output should be as follows: What just happened? The plots we made demonstrate four different ways of visualizing the function we plotted in the previous example. All four functions follow the same syntax as plot3d: contour_plot(f(x,y), (x, x_min, x_max), (y, y_min, y_max)) contour_plot plots level curves on the surface. In other words, z is constant on each curve. implicit_plot does the same thing, but only plots the curve where z=0. region_plot determines the curve for which z=0, and then fills in the region where z<0. Finally, density_plot converts the z value of the function to a color value and plots a color map of the z values over the x-y plane. We used the contour plot to demonstrate some of the keyword arguments that can be used to control the appearance of the plot. Here is a summary of the options we used: KeywordDescriptioncontoursThe number of contours to drawlinewidthsA list of line widths, corresponding to the number of contoursfillTrue to fill in between the contourslabelsTrue to label each contourlabel_colorsColor to use for labelscmapColor map to use for contour linescolorbarTrue to display the a scale bar showing the color map Summary In this article we learned about making three-dimensional plots and contour plots. Further resources on this subject: Plotting Data with Sage [Article] Creating Line Graphs in R [Article] Graphical Capabilities of R [Article] What Can You Do with Sage Math? [Article] Python Multimedia: Enhancing Images [Article] Python Multimedia: Fun with Animations using Pyglet [Article]
Read more
  • 0
  • 0
  • 10616

article-image-microsoft-dynamics-gp-understanding-reporting-tools
Packt
09 May 2011
11 min read
Save for later

Microsoft Dynamics GP: Understanding Reporting Tools

Packt
09 May 2011
11 min read
Microsoft Dynamics GP 2010 Reporting Create and manage business reports with Dynamics GP Our goal is to select the reporting tool that has the best capability to meet our required condition. Of course we will consider all of our reporting tools against each individual challenge. In reality, however, we will have to consider the varying conditions we need to meet with each challenge, and accept some trade-offs in our reporting tool's ability to meet all of our conditions. Intended audience A report almost always turns out useless when it hasn't been designed and created with the eventual end user in mind. Not only is it likely that the report will not provide the critical data our end user requires, but in many cases, the reporting tool we've selected to design the report may not even contain the functionality we require to meet the requirements of the end user. This can lead to ballooning investments in time and money and is often has the feel of trying to fit a square peg in a round hole! For the most part, our reporting audiences can be classified as either external or internal consumers of our organization's data. External consumers include auditors who require insight into the financial health of our organization, potential investors, and current stakeholders. On the other hand, internal consumers can range from operations personnel such as a warehouse manager, members of the accounting team, as well as members of the executive team. For external auditors who require insight into our organization's transaction journals, the default reports that come with tools such as Report Writer and SmartList Builder can easily be modified to provide auditors with the exact information they need. Although these reports are internal to GP, we can convert them to printouts or, in the case of SmartLists, export them to Excel and send the finished document over to the auditor. Other external consumers, such as potential investors and current stakeholders are primarily interested in seeing a summary of our organization's financial statement. This can be provided via numerous types of financial statements, and fortunately, Management Reporter can be used to create a wide variety of professional-looking financial statements that can then be distributed externally. One thing to keep in mind about most of our internal users is that they are more likely to operate within GP on a daily basis. We can assume that most of these users already have a GP login and are familiar with navigating through the GP environment. By creating reports with a reporting tool that is built-in to GP, we can add a new dimension to the user's GP experience without having to introduce the user to another application and another environment. Tools such as SmartList Builder and Report Writer allow us to develop such reports, and users will more than likely appreciate the ease of access that comes with their new reports. But, this is not to say that all internal users want to see their new reports in GP. It's entirely likely that members of our executive team will not have access to GP, much less the time or desire to navigate through the raw output that comes from SmartLists or posting journals designed in Report Writer. Instead, our executive team members want to see summarized information in a single, easy-to-reach location. Reporting tools such as the pre-defined SSRS Reports Library, Analysis Cubes for Excel, and Management Reporter are all alike in that they can provide these team members with a central repository of summary reports that do not require a GP user login to view. For a better, more visual understanding of the relationship between internal and external report consumers and the tools that they would most likely benefit from, take a look at the following image: Data sources Since the end result of the kind of reports is to present our end user with data from our ERP solution, we should be concerned with the source of that data. At first glance, the answer seems obvious: if we're trying to provide data from our ERP environment, shouldn't we pull it straight from the underlying company database itself? Unfortunately, the answer is not always that simple. We must be aware of potential performance impacts against our company databases that might result from our reporting processes. Additionally, even though our focus is primarily on GP 2010, we must keep in mind that data can reside in other, non-GP related data marts, as well. These separate data sources may exist due to other proprietary applications. If our end user wants to include information from separate data sources in his or her report, we need to be sure that we have a reporting tool that can access this data and use it in conjunction with what we are pulling from our GP database. By their very nature, some of the reporting tools can easily be used to combine data from multiple data sources. One tool that lends itself to this kind of reporting is the Analysis Cubes for Excel product. Because this product is built on a data warehouse, we have a ready-made location in which data extracted from multiple data sources can be transformed for consistency purposes and then loaded into the data warehouse. The transformation piece of this is critical, as one of the biggest challenges of using disparate data sources is finding a way to join the data together through some common key value(s). For example, one data source may refer to customers via a unique eight digit numeric customer code, whereas the other data source may refer to the same customer with a ten digit alpha-numeric code. In order to combine these two sets of data, we need to find a way to relate the eight digit codes to their corresponding ten digit codes from the other data source! Although Analysis Cubes for Excel offers a unique environment in which data from multiple data sources can be staged, other reporting tools we've discussed can also pull data from multiple data sources. This is largely due to the flexibility they offer in the form of using SQL queries to extract data for reports. For example, in SSRS, we can use SQL queries to create the data set from which our report is built. These SQL queries offer us flexibility to pull data from multiple tables, multiple databases, and even multiple servers. Unlike Analysis Cubes, however, the transformation required to create commonality between these different data sources must be done entirely within the SQL query. While this can be achieved, it is usually the domain of those with more advanced technical skills, and it can also cause an unnecessary drain on system resources each time the report is generated. SQL queries can also be used to generate data for SmartList Builder and Excel Report Builder reports, although this does create some limitations that may or may not be an issue for our end users. The image below shows where each reporting tool falls in the spectrum of reporting against a single data source or multiple data sources: Latency Latency deals with the idea that, depending on the reporting tool we select, the data in our report may lag a bit behind the actual data that exists in our ERP environment. Although it is likely that our users will profess a need for real-time data in all of our reports, in reality, this is not always easy to achieve. While it may be relatively easy to display up-to-the minute transactional data with certain reporting tools, this is usually only half the battle in reporting. To provide reports capable of analyzing large data sets and offering insight into trends in our data, we cannot rely on simple reporting tools that spit nothing but raw transactional data back at us. Instead, we must use reporting tools that can analyse large amounts of data and return to us a summarized look at the trends and movements within our organization. To do this requires a blend of time, money, and resources. So, while ERP applications like GP 2010 have long since been able to provide us with reporting tools that can spit raw data back at us, the effort to provide reporting tools that can truly help us aggregate and make sense of our large data sets are increasingly gaining in importance. For example, reporting tools like Management Reporter allow us to create a structure in which bits of data can be summarized into meaningful financial statements that provide both inside and outside stakeholders a look at the health of our organization. With such an analytical tool, we can see the big picture, or the trends, in our organization's data, even though this data originally came to us in the form of individual journal entries. The process of creating a financial statement in Management Reporter is two-fold: Creating the structure, or the building blocks of our report Generating the content of our report Although this is usually a fairly quick process, made even faster by the fact that we are using only standardized information from our general ledger, it still requires some time and resources to ensure that our reports are up to date. Here, then, we see an example of a great reporting tool that provides up-to-date data without too much of a drain on resources; however, we are limited to viewing this data in the rigid structure of a financial statement. But what happens when our users tell us that they want the same analytical capabilities provided by Management Reporter, but for other modules in GP, and with the flexibility to quickly and easily modify their reports? This sounds like a job for Analysis Cubes for Excel! The trade-off, however, comes in the form of extraordinarily large time delay (or latency) between the data found in the cubes and what actually exists in our production databases. Because Analysis Cubes stages data in a data warehouse and then processes the data into cubes for faster querying by the end user. The end-result means users will spend less time sorting through copious amounts of transactional data and more time analysing organizational trends that can be used to provide organizational advantage. While this data may not be up-to the minute (more than likely, it won't even be up-to-the hour), this should not scare our report-users away from this tool. Instead, we need to remind them that trends found in our data are often the result of a length of time far greater than the latency of our data; in fact, the cost and impact of reacting to every minute shift in a trend analysis caused by the addition of last minute data to our data set can often have far reaching and devastating consequences on our overall business plan! And finally, let's not overstate the importance of tools such as SmartList and Excel Reports Builder in the face of far more sophisticated reporting tools like Management Reporter and Analysis Cubes. Tools such as SmartList and Excel Reports Builder do a great job of providing transactional data quickly and accurately. Because these tools don't offer much in the way of analysis, they do the best job of any reporting tool of providing up-to-the minute data without a major drain on costs or performance. These tools also provide search mechanisms that make it easier to navigate to a specific transaction among hundreds and thousands of others. Tools such as these, while probably not much use to an executive team member, can be incredibly valuable to day-to-day operations personnel such as the Customer Service representative who must quickly navigate to a customer's transactions within GP. Using SmartList, for example, our representative can quickly find the right transaction and use the drilldown functionality to actually open the transaction directly in GP. So, while presenting real-time data can be achieved, we must determine from our end user whether the goal is to see purely transactional data that can be retrieved quickly and easily, or if there is a larger goal of using a report for trend analysis or to provide a summary of a large set of data. As we've seen, the opposing concepts of this reporting challenge consist of real time reporting versus potential data lag. While most of the tools we've discussed tend to lean towards real-time reporting, we can see from the following image that some tools do a better job of providing real-time data. Even though some tools do provide real-time data, some of these tools, like Management Reporter, require the user to go through a more defined report-generation process that can take some extra time to access the data.  
Read more
  • 0
  • 0
  • 1575
article-image-wordpress-3-building-widget
Packt
06 May 2011
10 min read
Save for later

WordPress 3: Building a Widget

Packt
06 May 2011
10 min read
  WordPress 3 Plugin Development Essentials Create your own powerful, interactive plugins to extend and add features to your WordPress site         Read more about this book       (For more resources on WordPress, see here.) The plan What exactly do we want this plugin to do? Our widget will display a random bit of text from the database. This type of plugin is frequently used for advertisement rotations or in situations where you want to spruce up a page by rotating content on a periodic basis. Each instance of our plugin will also have a "shelf life" that will determine how frequently its content should be randomized. Let's take a moment to come up with some specifications for this plugin. We want it to do the following: Store multiple chunks of content, such as bits of Google Adsense code Be able to randomly return one of the chunks Set a time limit that defines the "shelf life" of each chunk, after which the "random" chunk will be updated Widget overview Even if you are already familiar with widgets, take a moment to look at how they work in the WordPress manager under Appearance | Widgets. You know that they display content on the frontend of your site, usually in a sidebar, and they also have text and control forms that are displayed only when you view them inside the manager. If you put on your thinking cap, this should suggest to you at least two actions: an action that displays the content on the frontend, and an action that displays the form used to update the widget settings inside the manager. There are actually a total of four actions that determine the behavior of a standard widget, and you can think of these functions as a unit because they all live together in a single widget object. In layman's terms, there are four things that any widget can do. In programmatic terms, the WP_Widget object class has four functions that you may implement: The constructor: The constructor is the only function that you must implement. When you "construct" your widget, you give it a name, a description, and you define what options it has. Its name is often __ construct(), but PHP still accepts the PHP 4 method of naming your constructor function using the name of the class. widget(): It displays content to users on the frontend. form(): It displays content to manager users on the backend, usually to allow them to update the widget settings. update(): It prepares the updated widget settings for database storage. Override this function if you require special form validation. In order to make your widget actually work, you will need to tell WordPress about it by registering it using the WordPress register_widget() function. If you want to get a bit more information about the process, have a look at WordPress' documentation here. Let's outline this in code so you can see how it works. Preparation As always, we're going to go through the same setup steps to get our plugin outlined so we can get it activated and tested as soon as possible. Create a folder inside the wp-content/plugins/ directory. We are naming this plugin "Content Rotator", so create a new folder inside wp-content/ plugins/ named content-rotator. Create the index.php file. Add the Information Head to the index.php file. If you forgot the format, just copy and modify it from the Hello Dolly plugin like we did in the previous article, Anatomy of a WordPress Plugin. We're giving you bigger sections of code than before because hopefully by now you're more comfortable adding and testing them. Here is what our index.php looks like: <?php/*------------------------------------------------------------------------------Plugin Name: Content RotatorPlugin URI: http://www.tipsfor.us/Description: Sample plugin for rotating chunks of custom content.Author: Everett GriffithsVersion: 0.1Author URI: http://www.tipsfor.us/------------------------------------------------------------------------------*/// include() or require() any necessary files here...include_once('includes/ContentRotatorWidget.php');// Tie into WordPress Hooks and any functions that should run onload.add_action('widgets_init', 'ContentRotatorWidget::register_this_widget');/* EOF */ Add the folders for includes and tpls to help keep our files organized. Add a new class file to the includes directory. The file should be named ContentRotatorWidget.php so it matches the include statement in the index.php file. This is a subclass which extends the parent WP_Widget class. We will name this class ContentRotatorWidget, and it should be declared using the extends keyword. <?php /*** ContentRotatorWidget extends WP_Widget** This implements a WordPress widget designed to randomize chunksof content.*/class ContentRotatorWidget extends WP_Widget { public $name = 'Content Rotator'; public $description = 'Rotates chunks of content on a periodic basis'; /* List all controllable options here along with a default value. The values can be distinct for each instance of the widget. */ public $control_options = array(); //!!! Magic Functions // The constructor. function __construct() { $widget_options = array( 'classname' => __CLASS__, 'description' => $this->widget_desc, ); parent::__construct( __CLASS__, $this->name,$widget_ options,$this->control_options); } //!!! Static Functions static function register_this_widget() { register_widget(__CLASS__); } } /* EOF */ This is the simplest possible widget—we constructed it using only the __ construct() function. We haven't implemented any other functions, but we are supplying enough information here for it to work. Specifically, we are supplying a name and a description, and that's enough to get started. Let's take a moment to explain everything that just happened, especially since the official documentation here is a bit lacking. When we declared the ContentRotatorWidget class, we used the extends keyword. That's what makes this PHP class a widget, and that's what makes object-oriented code so useful. The __construct() function is called when an object is first created using the new command, so you might expect to see something like the following in our index. php file: <?php $my_widget = new ContentRotatorWidget();?> However, WordPress has obscured that from us—we just have to tell WordPress the classname of the widget we want to register via the register_widget() function, and it takes care of rest by creating a new instance of this ContentRotatorWidget. There is a new instance being created, we just don't see it directly. Some of the official documentation still uses PHP 4 style examples of the constructor function— that is to say that the function whose name shares the name of the class. We feel that naming the constructor function __construct is clearer. You may have wondered why we didn't simply put the following into our index.php file: register_widget('ContentRotatorWidget'); // may throw errors if called too soon! If you do that, WordPress will try to register the widget before it's ready, and you'll get a fatal error: "Call to a member function register() on a non-object". That's why we delay the execution of that function by hooking it to the widgets_ init action. We are also tying into the construct of the parent class via the parent::__ construct() function call. We'll explain the hierarchy in more detail later, but "parent" is a special keyword that can be used by a child class in order to call functions in the parent class. In this case, we want to tie into the WP_Widget __ construct() function in order to properly instantiate our widget. Note our use of the PHP __CLASS__ constant—its value is the class name, so in this case, we could replace it with ContentRotatorWidget, but we wanted to provide you with more reusable code. You're welcome. Lastly, have a look at the class variables we have declared at the top of the class: $name, $description, and $control_options. We have put them at the top of the class for easy access, then we have referenced them in the __construct() function using the $this variable. Note the syntax here for using class variables. We are declaring these variables as class variables for purposes of scope: we want their values to be available throughout the class. Please save your work before continuing. Activating your plugin Before we can actually use our widget and see what it looks like, we first have to activate our plugin in the manager. Your widget will never show up in the widget administration area if the plugin is not active! Just to be clear, you will have to activate two things: your plugin, and then your widget. The code is simple enough at this point for you to be able to quickly track down any errors. Activating the widget Now that the plugin code is active, we should see our widget show up in the widget administration area: Appearance | Widgets. Take a moment to notice the correlation between the widget's name and description and how we used the corresponding variables in our constructor function. Drag your widget into the primary widget area to make it active. Once it has been activated, refresh your homepage. Your active widget should print some text in the sidebar. (Move the mouse over the image to enlarge it.) Congratulations! You have created your first WordPress widget! It is printing a default message: function WP_Widget::widget() must be over-ridden in a sub-class, which is not very exciting, but technically speaking you have a functional widget. We still need to enable our widget to store some custom options, but first we should ensure that everything is working correctly. Having problems? No widget? If you have activated your plugin, but you do not see your widget showing up in the widget administration area, make sure you have tied into a valid WordPress action! If you misspell the action, it will not get called! The action we are using in our index.php is widgets_init—don't forget the "s"! White screen? Even if you have PHP error-reporting enabled, sometimes you suddenly end up with a completely white screen in both the frontend and in the manager. If there is a legitimate syntax error, that displays just fine, but if your PHP code is syntactically correct, you end up with nothing but a blank page. What's going on? A heavy-handed solution for when plugins go bad is to temporarily remove your plugin's folder from /wp-content/plugins, then refresh the manager. WordPress is smart enough to deactivate any plugin that it cannot find, so it can recover from this type of surgery. If you are experiencing the "White Screen of Death", it usually means that something is tragically wrong with your code, and it can take a while to track it down because each time you deactivate the plugin by removing the folder, you have to reactivate it by moving the folder back and reactivating the plugin in the WordPress manager. This unenviable situation can occur if you accidentally chose a function name that was already in use (for example, register()—don't use that as a function name). You have to be especially careful of this when you are extending a class because you may inadvertently override a vital function when you meant to create a new one. If you think you may have done this, drop and do 20 push-ups and then have a look at the original parent WP_Widget class and its functions in wp-includes/widgets.php. Remember that whenever you extend a class, it behooves you to look at the parent class' functions and their inputs and outputs. If this sounds like Greek to you, then the next section is for you.
Read more
  • 0
  • 0
  • 2990

article-image-silverstripe-24-customizing-layout
Packt
06 May 2011
10 min read
Save for later

SilverStripe 2.4: Customizing the Layout

Packt
06 May 2011
10 min read
Templates and themes All pages within SilverStripe are rendered using a template, which is basically an HTML/XHTML file with added control code. A template allows you to make conditional statements, create menus, access data stored in the database, and much more. Instead of using PHP for these enhancements, templates rely on a dedicated template engine. When the user accesses a page the engine replaces the control code with PHP. This transformation is then evaluated by the web server to regular markup code, which every browser can display. A theme consists of a collection of template, CSS, and image files. Design-specific JavaScript is also stored here. Together they form the layout of a page. Switching between themes You can have multiple themes and switch between them whenever you like. You're definitely encouraged to give everything described here a try. It helps you in becoming an active developer instead of a passive user. So let's get things started! Time for action - change the default theme Simply perform the following steps in the CMS and you're all set: Log into the CMS by appending /admin to your page's base URL. Provide the credentials you defined during the installation and you should be logged-in. Go to the general configuration page by clicking on the globe within the Page Tree section. The default text of this element is Your Site Name. The Theme is set to (Use default theme) by default; change this to tutorial. Click on the Save button. Go to the base URL / and reload the page. What just happened? We've successfully changed the theme of our website. It's as easy as that. Note that you need to package your theme into a subfolder of themes/ to be able to switch between them. While you can also put the contents of a theme directly into the mysite/ folder, keeping your system modularized is a good practice. Therefore we won't integrate the layout into the site specific folder and will instead always create a dedicated, switchable theme. Getting more themes After unpacking a theme, copy it to the themes/ folder, change the theme in the CMS, and you're good to go. Using a prebuilt theme really is that simple. Next, we'll take a look at the facilities for building our own themes—specifically, the template engine that powers all themes in SilverStripe. By the end of this article and next, you'll even be ready to upload and share your own themes with the rest of the community at the address above. New contributions are always welcome. Template engine As described earlier, the SilverStripe architecture consists of three layers, each serving a specific purpose. The one responsible for the layout is called View, which we'll cover in detail in this article. Another template engine? One might wonder why it is necessary to learn another template language, while there are already so many others available and PHP can do all of it as well. The main reasons behind this are: The template engine and the rest of the system fit perfectly together. After getting the hang of it, it makes the creation of templates and communication with the other layers faster and easier. The available control code is very simple. Designers without a lot of programming knowledge can create feature-rich layouts. It enforces good coding practice. Without the ability to use raw PHP, one cannot by-pass the other layers and undermine the architecture. Only layout and rendering information should be used within templates. Taking a look at BlackCandy First of all, switch back to the BlackCandy theme as we want to take a better look at it. Within your installation, navigate to the folder themes/blackcandy/ and you'll see three folders: css/, images/, and templates/. The images/ folder contains any image used in your theme; if you like, you can create subfolders to keep things organized. The remaining folders are a bit more complicated, so let's break them down. CSS At first this looks a bit messy—five files for the CSS; couldn't we use just a single one? We could, but many developers consider it a good practise splitting the functionality into different parts, making it easier to navigate later on. Sticking to this convention adds functionality as well. This is a common principle, called convention over configuration. If you do things the way they are expected by the system, you don't need to configure them specifically. Once you know the "way" of the system, you'll work much quicker than if you had to configure the same things over and over again. editor.css This file is automagically loaded by SilverStripe's what you see is what you get (WYSIWYG) editor. So if you apply the correct styling via this file, the content in the CMS' backend will look like the final output in the frontend. Additionally you'll have all custom elements available under the Styles dropdown, so the content editors don't need to mess around with pure HTML. As this file is not automatically linked to the frontend, it's common practice to put all frontend styling information into typography.css and reference that file in editor.css: @import "typography.css"; If you want to provide any styling information just for the CMS, you can put it below the @import. layout.css, form.css, and typography.css These files are automagically included in the frontend if they are available in your theme. While layout.css is used for setting the page's basic sections and layout, form.css deals with the form related styling. typography.css covers the layout of content entered into the CMS, generally being imported by editor.css as we've just discussed. Elements you will include here are headers (<h1>, <h2>, and so on), text (for example <p>), lists, tables, and others you want to use in the CMS (aligning elements, <hr>, and so on). ie6.css This file isn't part of the SilverStripe convention, but is a useful idea you might want to adopt. You must include it manually but it will still be a good idea to stick to this naming schema: ie.css for styling elements in any version of Internet Explorer, ie6.css for Internet Explorer 6 specifics, and so on. What about performance? Cutting down on the number of files being loaded is an effective optimization technique for websites. We'll take a look at how to do that. Templates Now that we've discussed the styling, let's take a look at how to put the content together with the help of templates. Learning the very basics Before we continue, some basic facts and features of templates: Templates must use the file extension .ss instead of .html or .php. Templates can be organized alongside their PHP Controllers, so you can use the same powerful mechanism as in the other layers. We'll take a better look at what this means a little later. Page controls consist of placeholders and control structures, which are both placed within the regular markup language. Placeholders start with a $ and are processed and replaced by the template engine. Control structures are written between opening <% and closing %>. They look a bit like HTML tags and they are used the same way. Some consist of a single element, like HTML's <br>, whereas others consist of two or more. Starting to use templates Now that we've covered the basics, let's put them into practice. Time for action - using site title and slogan We shall use placeholders, taking a look at the code level and how to use them in the CMS: Open the file themes/blackcandy/templates/Page.ss in your preferred editor. If the syntax highlighting is disabled due to the unknown file extension, set it to HTML. Find the two placeholders $SiteConfig.Title and $SiteConfig.Tagline in the code. Go to the general configuration page in the CMS, the one where we've changed the theme. Edit the Site title and Site Tagline/Slogan to something more meaningful. Save the page. Go to the base URL and hit refresh. If you view the page's source, you can see that the two placeholders have been replaced by the text we have just entered in the CMS. If you are wondering about the short doctype declaration: there is nothing missing, this is HTML5, which SilverStripe is already using in its default theme. If you prefer XHTML or an older HTML standard, you can freely change it. The CMS happily works with all of them. What just happened? The file we've just edited is the base template. It's used for every page (unless specifically overwritten). You can define your general layout once and don't have to repeat it again. You should always try to avoid repeating code or content. This is generally called don't repeat yourself (DRY) or duplication is evil (DIE). SilverStripe supports you very well in doing this. The site title and slogan are globally available. You can use them on every page and they share the same content across the whole website. These placeholders are prefixed with SiteConfig. as well as a $ sign. In the CMS they are all available on the site's root element, the one with the globe. By default, there are just two, but we'll later see how to add more. Other placeholders are available on specific pages or can be different on each page. We'll come to those next. Layout Looking again at the Page.ss we've just opened, you'll also see a $Layout placeholder. This is replaced by a file from the themes/blackcandy/templates/Layout folder. There are only two files available by default and for every standard page Page.ss is used. When a page is loaded, the template engine first finds the base templates/Page.ss (excluding the theme specific part of the path as this can vary). It's evaluated and the $Layout is replaced by templates/Layout/Page.ss, which is also evaluated for further SilverStripe controls. Ignore Page_results.ss for the moment. It's only used for search queries which we'll cover later. We'll also add more page types so the layout's Page.ss can then be replaced by a more specific template, while the base templates/Page.ss is always used. Includes Both Page.ss files include statements like <% include BreadCrumbs %>. These controls are replaced by files from the themes/blackcandy/templates/Includes/ folder. For example, the above include grabs the themes/blackcandy/templates/Includes/BreadCrumbs.ss file. Note that filenames are case sensitive. Otherwise you're free to select a meaningful name. Try sticking to one naming convention to make your own life easier later on, and also note that you mustn't include the <code>.ss</code> extension. If you're seeing a Filename cannot be empty error, make sure the included file really exists. Have a go hero - using page name, navigation label, and metadata title Now that we've explored all available files and how they are used, let's take a better look at the system. In the CMS backend, go to the Home page. Change the text currently entered into Page name, Navigation label (both in the Main tab), and Title (Metadata tab). Take a look at: Where on the page they are used In which file they are located (take a look at all three possible locations) What template placeholders represent them You might notice $MetaTitle, $Title, and $MenuTitle in your template files (for the moment ignore the appended .XML). We will explore these later on.
Read more
  • 0
  • 0
  • 2456

article-image-installing-microsoft-dynamics-nav
Packt
06 May 2011
4 min read
Save for later

Installing Microsoft Dynamics NAV

Packt
06 May 2011
4 min read
The installation of Dynamics NAV Classic components remains more or less similar to the Dynamics NAV 5.0 version. Thus, in this article, we have used the NAV 5.0 version for installation of Dynamics NAV Classic components and the Dynamics NAV 2009 SP1 version for installation of RTC and the other new components introduced after the release of NAV 2009. Installing a Classic client Classic client installation, also called a C/SIDE client, is more or less the same for all the versions of Navision Financials, Navision, Microsoft Business Solutions—Navision, or Dynamics NAV. We have illustrated an example of 5.0 SP1 Dynamics NAV C/SIDE client installations as follows: Starting with the startup screen of the installation disk, the process is fairly easy and well defined through the various installation stages. Click on C/SIDE Client for Microsoft Dynamics NAV under the Install section of the screen to run the installation wizard. If we want to install multiple versions of NAV on the same machine, there is a work around to do that. Install the latest version and copy the client (C:program filesMicrosoft Dynamics NAV...) folder(s) for the rest of the versions that we want to use. Once we have copied the client files, use fin.exe or finsql.exe to run the appropriate version of Dynamics NAV; this is not supported by the standard product and must not be used in a client production environment. The installation process takes us through the setup wizard. In a network installation, we would typically select Minimum as the Install option. This needs the least amount of disk space. We can also select this option if we need just the client executables.   If we select Custom, we will get a few options to select from the following: Help: This is the option for installing Dynamics NAV Online Help. It is recommended to have this option always on. Demo Database: This is the option to install a demonstration database with the CRONUS company. This is not needed typically in a network installation. We may need to install this option in a single user installation. Backup of Demo Database: If selected, this option will copy a backup (.fbk file) of the demo database to the program folder. Commerce Integration, Employee Portal: These options need to be selected if we are installing Employee Portal, Commerce Gateway, or Commerce portal (discontinued now) components. Business Notification Manager: This is the option to send automatic business event notifications from NAV. Outlook Integration: This feature installs components for Dynamics NAV and Microsoft Outlook Integration. This also installs a toolbar in Microsoft Outlook. Gantt Server: The OLAP component that facilitates management of shop floor production using visual status updates and plans. There is also the option to change the installation path, by clicking on the Change... button at the bottom. The following are some of the key program files and what they do: Fin.exe: This is a client executable for the Microsoft Dynamics NAV C/SIDE client. Finsql.exe: This is a client executable for the Microsoft Dynamics NAV C/SIDE client for SQL Server option. CRONUS.flf: This file and the files with extension .flf are the license files for Microsoft Dynamics NAV and are responsible for granting appropriate access to the application areas, based on what has been bought from Microsoft. Fin.stx: The local settings, system menu captions, and regional settings are kept as system text in the .stx file. Fin.etx: The error messages for the system errors and not the application errors generated by business logic are stored in this error text file. Database.fdb: This is the Microsoft Dynamics Classic database file. Database.fbk: This is the Microsoft Dynamics Classic database backup. The wonders of the ZUP file are as follows: In the versions prior to Microsoft Dynamics NAV 2009, all local client settings such as column widths, report filters, and displayed form columns, were stored in the .zup file for the users on their local application data folder. A parameter for client executables fin.exe, fin sql.exe—ID=<name> saves the ZUP file with this ID, thus providing the ability to group the ZUP files together and giving the ability to back up different ZUP files. In the Dynamics NAV 2009 RoleTailored client version, the .zup file is replaced by the following files and tables where the local settings are stored: ClientUserSettings.Config PersonalizationStore.xml CustomSettings.config Table 2000000075 User Metadata Table 2000000071 Object Metadata Upwards compatibility: It is recommended to upgrade the client executables to the latest version, if not the database. However, with NAV 2009 this may not be true.
Read more
  • 0
  • 0
  • 3909
article-image-microsoft-dynamics-gp-installing-analysis-cubes
Packt
05 May 2011
4 min read
Save for later

Microsoft Dynamics GP: Installing Analysis Cubes

Packt
05 May 2011
4 min read
  Microsoft Dynamics GP 2010 Reporting Create and manage business reports with Dynamics GP   Pre-installation checklist Before proceeding with our installation of the Analysis Cubes, we need to review our Pre-installation checklist. Review system requirements for server components – This includes determining which of the deployment configurations we will be using in our environment. Review security requirements for installing and configuring the server components: To install and configure the server components, the Windows user account must be in the Windows groups in the following chart, as described in the latest Analysis Cubes for Excel manual: Server ComputerWindows GroupsMicrosoft Dynamics GP Server ComputerAdministratorsSQL Server Computer for Microsoft Dynamics GP Company DatabasesAll versions of SQL Server: Administrators SQL Server 2005: SQLServer2005MSSQLUser SQL Server 2008: SQLServerMSSQLUserData Warehouse Database Server Computer (with Integration Services Installed)All versions of SQL Server: Administrators SQL Server 2005: SqlServer2005MSSQLUser; SQLServer2005DTSUser SQL Server 2008: SQLServerMSSQLUser; SQLServerDTSUserSQL Server Analysis Services ComputerAll versions of SQL Server: Administrators SQL Server 2005: SQLServer2005MSOLAPUser SQL Server 2008: SQLServerMSOLAPUser Dynamics GP server must be given access to read and write data on the data warehouse database server if it is a different physical machine. Gather information required for configuring the server components: The Dynamics GP company databases that will be used to populate the data warehouse database The name that will be used for the data warehouse database The SQL server name or instance name that the data warehouse database will reside on The locations of the data and log files for the SQL server instance The SQL Server Integration Services packages to install Whether to populate the warehouse database with detailed General Ledger transaction information for various modules or to use summary information Determine whether to populate each cube with all transactions or to enter an earliest date to import from the company databases Determine whether to include multicurrency information and if so, which reporting currency and exchange rate table to use for each company Define a password for the Dynamics User SQL Server login account that will be used by the company databases to access the data warehouse database using SQL Server Authentication Installing the Server Configuration Wizard Now that we have ensured we have met all system requirements and obtained the necessary security permissions to perform the installation, we can proceed with installing the Server Configuration Wizard. The installation can be started from the Dynamics GP 2010 Installation Media or by downloading the Analysis Cubes Installer package from either the PartnerSource or CustomerSource portals. Be sure that when downloading the package from these sites, you download the correct file whether you are on Dynamics GP 2010 RTM or Service Pack 1. To install the Server Configuration Wizard, follow these steps: Locate the Microsoft_DynamicsGP11_AnalysisCubesServer_x86.msi file you downloaded and double-click the file to open the Dynamics GP Server Setup Wizard. Click Next to proceed. On the License Agreement window, select the I Agree radio button and click Next. Enter the path for the destination folder to install the server configuration wizard program to. The default path is C:Program FilesMicrosoft DynamicsAnalysis Cubes for Microsoft Dynamics GP Server. Click Next. Click Next to complete the installation. Click Close to close the wizard. Using the Server Configuration Wizard to deploy the cubes Once we have installed the Server Configuration Wizard, we need to run the wizard to actually deploy the cubes. During the configuration wizard installation process, two files, named Microsoft.Dynamics.GP.AnalysisCubes.ConfigurationWizard2005.exe and Microsoft.Dynamics.GP.AnalysisCubes.ConfigurationWizard2008.exe are extracted to the destination folder. Shortcuts to these files, named Analysis Cubes Configuration Wizard for SQL Server 2005 and Analysis Cubes Configuration Wizard for SQL Server 2008 also are created on the desktop. To use the Server Configuration Wizard to Deploy the Cubes, follow these steps: Browse to the folder location where the Server Configuration Wizard was installed, or run the Analysis Cubes Configuration Wizard from the desktop. (Move the mouse over the image to enlarge.) On the Data Warehouse Setup window, enter the values for the fields based on the information you gathered in the Pre-Installation checklist section. On the Microsoft Dynamics GP database selection window, enter your Dynamics GP server name and select each company database(s) that will be included in the Data Warehouse and click Next. On the Analysis Cubes Integration Setup window, select the modules to include in the data warehouse and whether to import transactions in detail or in summary. A cutoff date can also be selected to limit transactions that are loaded. Click Next.  
Read more
  • 0
  • 0
  • 3723

article-image-plotting-data-sage
Packt
05 May 2011
14 min read
Save for later

Plotting Data with Sage

Packt
05 May 2011
14 min read
Sage Beginner's Guide Unlock the full potential of Sage for simplifying and automating mathematical computing Confusion alert: Sage plots and matplotlib The 2D plotting capabilities of Sage are built upon a Python plotting package called matplotlib. The most widely used features of matplotlib are accessible through Sage functions. You can also import the matplotlib package into Sage, and use all of its features directly. This is very powerful, but it's also confusing, because there's more than one way to do the same thing. To further add to the confusion, matplotlib has two interfaces: the command-oriented Pyplot interface and an object-oriented interface. The examples in this chapter will attempt to clarify which interface is being used. Plotting in two dimensions Two-dimensional plots are probably the most important tool for visually presenting information in math, science, and engineering. Sage has a wide variety of tools for making many types of 2D plots. Plotting symbolic expressions with Sage We will start by exploring the plotting functions that are built in to Sage. They are generally less flexible than using matplotlib directly, but also tend to be easier to use. Time for action – plotting symbolic expressions Let's plot some simple functions. Enter the following code: p1 = plot(sin, (-2*pi, 2*pi), thickness=2.0, rgbcolor=(0.5, 1, 0), legend_label='sin(x)') p2 = plot(cos, (-2*pi, 2*pi), thickness=3.0, color='purple', alpha=0.5, legend_label='cos(x)') plt = p1 + p2 plt.axes_labels(['x', 'f(x)']) show(plt) If you run the code from the interactive shell, the plot will open in a separate window. If you run it from the notebook interface, the plot will appear below the input cell. In either case, the result should look like this: What just happened? This example demonstrated the most basic type of plotting in Sage. The plot function requires the following arguments: graphics_object = plot(callable symbolic expression, (independent_var, ind_var_min, ind_var_max)) The first argument is a callable symbolic expression, and the second argument is a tuple consisting of the independent variable, the lower limit of the domain, and the upper limit. If there is no ambiguity, you do not need to specify the independent variable. Sage automatically selects the right number of points to make a nice curve in the specified domain. The plot function returns a graphics object. To combine two graphics objects in the same image, use the + operator: plt = p1 + p2. Graphics objects have additional methods for modifying the final image. In this case, we used the axes_labels method to label the x and y axes. Finally, the show function was used to finish the calculation and display the image. The plot function accepts optional arguments that can be used to customize the appearance and format of the plot. To see a list of all the options and their default values, type: sage: plot.options {'fillalpha': 0.5, 'detect_poles': False, 'plot_points': 200, 'thickness': 1, 'alpha': 1, 'adaptive_tolerance': 0.01, 'fillcolor': 'automatic', 'adaptive_recursion': 5, 'exclude': None, 'legend_label': None, 'rgbcolor': (0, 0, 1), 'fill': False} Here is a summary of the options for customizing the appearance of a plot: KeywordDescriptionalphaTransparency of the line (0=opaque, 1=transparent)fillTrue to fill area below the linefillalphaTransparency of the filled-in area (0=opaque, 1=transparent)fillcolorColor of the filled-in areargbcolorColor of the line Sage uses an algorithm to determine the best number of points to use for the plot, and how to distribute them on the x axis. The algorithm uses recursion to add more points to resolve regions where the function changes rapidly. Here are the options that control how the plot is generated: KeywordDescriptionadaptive_recursionMax depth of recursion when resolving areas of the plot where the function changes rapidlyadaptive_toleranceTolerance for stopping recursiondetect_polesDetect points where function value approaches infinity (see next example)excludeA list or tuple of points to exclude from the plotplot_pointsNumber of points to use in the plot Specifying colors in Sage There are several ways to specify a color in Sage. For basic colors, you can use a string containing the name of the color, such as red or blue. You can also use a tuple of three floating-point values between 0 and 1.0. The first value is the amount of red, the second is the amount of green, and the third is the amount of blue. For example, the tuple (0.5, 0.0, 0.5) represents a medium purple color. Some functions "blow up" to plus or minus infinity at a certain point. A simplistic plotting algorithm will have trouble plotting these points, but Sage adapts. Time for action – plotting a function with a pole Let's try to plot a simple function that takes on infinite values within the domain of the plot: pole_plot = plot(1 / (x - 1), (0.8, 1.2), detect_poles='show', marker='.') print("min y = {0} max y = {1}".format(pole_plot.ymax(), pole_plot.ymin())) pole_plot.ymax(100.0) pole_plot.ymin(-100.0) # Use TeX to make nicer labels pole_plot.axes_labels([r'$x$', r'$1/(x-1)$']) pole_plot.show() The output from this code is as follows: What just happened? We did a few things differently compared to the previous example. We defined a callable symbolic expression right in the plot function. We also used the option detect_poles='show' to plot a dashed vertical line at the x value where the function returns infinite values. The option marker='.' tells Sage to use a small dot to mark the individual (x,y) values on the graph. In this case, the dots are so close together that they look like a fat line. We also used the methods ymin and ymax to get and set the minimum and maximum values of the vertical axis. When called without arguments, these methods return the current values. When given an argument, they set the minimum and maximum values of the vertical axis. Finally, we labeled the axes with nicely typeset mathematical expressions. As in the previous example, we used the method axes_labels to set the labels on the x and y axes. However, we did two special things with the label strings: r'$frac{1}{(x-1)}$' The letter r is placed in front of the string, which tells Python that this is a raw string. When processing a raw string, Python does not interpret backslash characters as commands (such as interpreting n as a newline). Note that the first and last characters of the string are dollar signs, which tells Sage that the strings contain mark-up that needs to be processed before being displayed. The mark-up language is a subset of TeX, which is widely used for typesetting complicated mathematical expressions. Sage performs this processing with a built-in interpreter, so you don't need to have TeX installed to take advantage of typeset labels. It's a good idea to use raw strings to hold TeX markup because TeX uses a lot of backslashes. To learn about the typesetting language, see the matplotlib documentation at: http://matplotlib.sourceforge.net/users/mathtext.html Time for action – plotting a parametric function Some functions are defined in terms of a parameter. Sage can easily plot parametric functions: var('t') pp = parametric_plot((cos(t), sin(t)), (t, 0, 2*pi), fill=True, fillcolor='blue') pp.show(aspect_ratio=1, figsize=(3, 3), frame=True) The output from this code is as follows: What just happened? We used two parametric functions to plot a circle. This is a convenient place to demonstrate the fill option, which fills in the space between the function and the horizontal axis. The fillcolor option tells Sage which color to use for the fill, and the color can be specified in the usual ways. We also demonstrated some useful options for the show method (these options also work with the show function). The option aspect_ratio=1 forces the x and y axes to use the same scale. In other words, one unit on the x axis takes up the same number of pixels on the screen as one unit on the y axis. Try changing the aspect ratio to 0.5 and 2.0, and see how the circle looks. The option figsize=(x_size,y_size) specifies the aspect ratio and relative size of the figure. The units for the figure size are relative, and don't correspond to an absolute unit like inches or centimetres. The option frame=True places a frame with tick marks around the outside of the plot. Time for action – making a polar plot Some functions are more easily described in terms of angle and radius. The angle is the independent variable, and the radius at that angle is the dependent variable. Polar plots are widely used in electrical engineering to describe the radiation pattern of an antenna. Some antennas are designed to transmit (or receive) electromagnetic radiation in a very narrow beam. The beam shape is known as the radiation pattern. One way to achieve a narrow beam is to use an array of simple dipole antennas, and carefully control the phase of the signal fed to each antenna. In the following example, we will consider seven short dipole antennas set in a straight line: # A linear broadside array of short vertical dipoles # located along the z axis with 1/2 wavelength spacing var('r, theta') N = 7 normalized_element_pattern = sin(theta) array_factor = 1 / N * sin(N * pi / 2 * cos(theta)) / sin(pi / 2 * cos(theta)) array_plot = polar_plot(abs(array_factor), (theta, 0, pi), color='red', legend_label='Array') radiation_plot = polar_plot(abs(normalized_element_pattern * array_factor), (theta, 0, pi), color='blue', legend_label='Radiation') combined_plot = array_plot + radiation_plot combined_plot.xmin(-0.25) combined_plot.xmax(0.25) combined_plot.set_legend_options(loc=(0.5, 0.3)) show(combined_plot, figsize=(2, 5), aspect_ratio=1) Execute the code. You should get a plot like this: What just happened? We plotted a polar function, and used several of the plotting features that we've already discussed. There are two subtle points worth mentioning. The function array_factor is a function of two variables, N and theta. In this example, N is more like a parameter, while theta is the independent variable we want to use for plotting. We use the syntax (theta, 0, pi) in the plot function to indicate that theta is the independent variable. The second new aspect of this example is that we used the methods xmin and xmax to set the limits of the x axis for the graphics object called combined_plot. We also used the set_legend_options of the graphics object to adjust the position of the legend to avoid covering up important details of the plot. Time for action – plotting a vector field Vector fields are used to represent force fields such as electromagnetic fields, and are used to visualize the solutions of differential equations. Sage has a special plotting function to visualize vector fields. var('x, y') a = plot_vector_field((x, y), (x, -3, 3), (y, -3, 3), color='blue') b = plot_vector_field((y, -x), (x, -3, 3), (y, -3, 3), color='red') show(a + b, aspect_ratio=1, figsize=(4, 4)) You should get the following image: What just happened? The plot_vector_field function uses the following syntax: plot_vector_field((x_function,y_function), (x,x_min,x_max), (y,y_ min,y_max)) The keyword argument color specifies the color of the vectors. Plotting data in Sage So far, we've been making graphs of functions. We specify the function and the domain, and Sage automatically chooses the points to make a nice-looking curve. Sometimes, we need to plot discrete data points that represent experimental measurements or simulation results. The following functions are used for plotting defined sets of points. Time for action – making a scatter plot Scatter plots are used in science and engineering to look for correlation between two variables. A cloud of points that is roughly circular indicates that the two variables are independent, while a more elliptical arrangement indicates that there may be a relationship between them. In the following example, the x and y coordinates are contrived to make a nice plot. In real life, the x and y coordinates would typically be read in from data files. Enter the following code: def noisy_line(m, b, x): return m * x + b + 0.5 * (random() - 0.5) slope = 1.0 intercept = -0.5 x_coords = [random() for t in range(50)] y_coords = [noisy_line(slope, intercept, x) for x in x_coords] sp = scatter_plot(zip(x_coords, y_coords)) sp += line([(0.0, intercept), (1.0, slope+intercept)], color='red') sp.show() The result should look similar to this plot. Note that your results won't match exactly, since the point positions are determined randomly. What just happened? We created a list of randomized x coordinates using the built-in random function. This function returns a random number in the range 0 <= x < 1. We defined a function called noisy_line that we then used to create a list of randomized y coordinates with a linear relationship to the x coordinates. We now have a list of x coordinates and a list of y coordinates, but the scatter_plot function needs a list of (x,y) tuples. The zip function takes the two lists and combines them into a single list of tuples. The scatter_plot function returns a graphics object called sp. To add a line object to the plot, we use the following syntax: sp += line([(x1, y1), (x2,y2)], color='red') The += operator is a way to increment a variable; x+=1 is a shortcut for x = x + 1. Because the + operator also combines graphics objects, this syntax can be used to add a graphics object to an existing graphics object. Time for action – plotting a list Sometimes, you need to plot a list of discrete data points. The following example might be found in an introductory digital signal processing (DSP) course. We will use lists to represent digital signals. We sample the analogue function cosine(t) at two different sampling rates, and plot the resulting digital signals. # Use list_plot to visualize digital signals # Undersampling and oversampling a cosine signal sample_times_1 = srange(0, 6*pi, 4*pi/5) sample_times_2 = srange(0, 6*pi, pi/3) data1 = [cos(t) for t in sample_times_1] data2 = [cos(t) for t in sample_times_2] plot1 = list_plot(zip(sample_times_1, data1), color='blue') plot1.axes_range(0, 18, -1, 1) plot1 += text("Undersampled", (9, 1.1), color='blue', fontsize=12) plot2 = list_plot(zip(sample_times_2, data2), color='red') plot2.axes_range(0, 18, -1, 1) plot2 += text("Oversampled", (9, 1.1), color='red', fontsize=12) g = graphics_array([plot1, plot2], 2, 1) # 2 rows, 1 column g.show(gridlines=["minor", False]) The result is as follows: What just happened? The function list_plot works a lot like scatter_plot from the previous example, so I won't explain it again. We used the method axes_range(x_min, x_max, y_min, y_max) to set the limits of the x and y axes all at once. Once again, we used the += operator to add a graphics object to an existing object. This time, we added a text annotation instead of a line. The basic syntax for adding text at a given (x,y) position is text('a string', (x,y)). To see the options that text accepts, type the following: sage: text.options {'vertical_alignment': 'center', 'fontsize': 10, 'rgbcolor': (0, 0, 1), 'horizontal_alignment': 'center', 'axis_coords': False} To display the two plots, we introduced a new function called graphics_array, which uses the basic syntax: graphics_array([plot_1, plot_2, ..., plot_n], num_rows, num_columns) This function returns another graphics object, and we used the show method to display the plots. We used the keyword argument gridlines=["minor", False] to tell Sage to display vertical lines at each of the minor ticks on the x axis. The first item in the list specifies vertical grid lines, and the second specifies horizontal grid lines. The following options can be used for either element: "major"Grid lines at major ticks"minor"Grid lines at major and minor ticksFalseNo grid lines Try playing with these options in the previous example.  
Read more
  • 0
  • 0
  • 25149
Modal Close icon
Modal Close icon