Skip to main content

#Output0 debatiendo

Warning: Forgive me if I don't use the right terms - I am very new to tableau.

 

I am working on a project to focusing on population of people living within a selected dynamic radius distance (in km). Second part of the project is to show which of provincial road networks pass through the selected circle.

 

What I have:

 

1. Shape file of 2016 population census of the province (Saskatchewan, Canada) - down to dissemination block area units IDs (DBAUIDs). This shape file also has areas (in square kms) of all the DBAUID's.

2. Shape Map of the provincial road networks - different classes of roads, town names, metro centers, etc.

 

My main focus is to draw circles (dynamic radius) around top 9 city centers by population. And show the population living within that radius AND amount spent on maintaining road networks passing through that circle - by increasing or decreasing the radius. I found a very good example here (Richard Leeke's Super-Charged ZIP Code Radius-Finder ) but can't reproduce it as I have limited knowledge on GIS.

 

What I have done:

1. I was able to build circles using the lat/long of 9 cities - chosen manually (But I wish this can be automated for all cities and be able to select by filters).

2. I was also able to change the circle radius using a parameter.

 

I am stuck with overlaying the population files and road network files and making them work with the circles. Like I said earlier, this (workbook found here >> Richard Leeke's Super-Charged ZIP Code Radius-Finder  is exactly what I have in mind to achieve. I need help on this. Thank you for being kind enough to help me advance in Tableau. All of the definition to understand the census data are here: Table 4.12 Dissemination area boundary files record layout.

 

Message was edited by: Jim Dehner

I removed the list of "Mentioned" - see

139 respuestas
  1. 22 dic 2018, 00:04

    OK, explanations for the last two views and the dashboard.

     

    Highway Spending per Capita for Selected Areas

     

    This builds on a lot of the things we did in the previous view, but has one extra twist which I'll explain first before the detailed instructions.

     

    The table calculation for the field [Amount Spent per Capita] uses the expression:

     

    [Selected Amount Spent] / [Selected Population]

     

    where both of those are themselves table calculation, but with different addressing: [Selected Amount Spent] is calculated over all roadnames whereas [Selected Population] is calculated over all dissemination blocks. This means we can't just use the 'Compute Using' menu option for [Amount Spent per Capita] to set the addressing, because that only allows us to pick one field, so only one of the two component calculations would be correct. Instead we need to use the 'Edit Table Calculation' option which gives the option to set the addressing individually for each component calculation:

    OK, explanations for the last two views and the dashboard.

    The dialog has a drop-down list allowing you to choose each component calculation in turn.

    pastedImage_5.png

     

    At first sight you would think that for 'Selected Population' you should just check [dbuid] (meaning the calculation would be performed over all [dbuid] values for each combination of [Highway Roadname] and [Population Center]) and for [Selected Amount Spent] you should check [Highway Roadname] (meaning the calculation would be performed over all [Highway Roadname] values for each combination of [dbuid] and [Population Center]). But that results in [Amount Spent per Capita] being null. This screenshot of the 'show data' window hopefully explain what is happening here: [Selected Population] is always null for highway rows and [Selected Amount Spent] is null for all dissemination block rows - so [Amount Spent per Capita] is always null (because one or other of the two fields used to calculate it is always null).

    pastedImage_2.png

     

    So actually what we need to do is perform both calculations over all values of both [Highway Roadname] and [dbuid] for each [Population Center], by setting both like this:

    pastedImage_6.png

     

    That means that both components calculations and hence the [Amount Spent per Capita] are evaluated correctly for every row, as shown here:

    pastedImage_1.png

    We will again want to filter the view down to a single row, using the [First Row?] field, as we did previously.

     

    Step by step instructions.

     

    1) Create a new sheet and call it 'Highway Spending per Capita for Selected Areas'.

    2) Drag [Population Center] from datasource 'Pop Centre Dissemination Block Highway' onto the Rows shelf.

    3) Switch to sheet 'Dissemination Blocks and Highways around Population Centers' and for both the population and population center filters select 'Apply to Worksheets' and select 'Highway Spending per Capita for Selected Areas' to apply those filters to our new sheet.

    4) Switch back to 'Highway Spending per Capita for Selected Areas' and drag [dbuid] and [Highway Roadname] onto the detail shelf.

    5) Drag [Amount Spent per Capita] onto the Columns shelf, and set the addressing using the 'Edit Table Calculation' option from the drop-down menu on the field. Select both [dbuid] and [Highway Roadname] for each of the two component calculated fields, as per the explanation above.

    6) Drag [Is First?] onto the filter shelf and select 'True' when prompted (the reason it only offers 'True' is because with the default addressing there is only one row per partition - so that row is always the first row in its partition). Now use 'Edit Table Calculation' to set the addressing to use both [dbuid] and [Highway Roadname] as above. Finally select 'True' when offered 'True' or 'False' to filter to just the first row.

    7) From the Label shelf select 'Show mark labels'.

    pastedImage_13.png

    8) Optionally format the [Amount Spent per Capita] field and axis to use currency format.

     

    Your view should now look like this for Saskatoon.

    pastedImage_14.png

     

    Highway Spending by Population Center and Route

     

    Last sheet. This one is very straightforward, no new techniques or concepts, so just brief step-by-step instructions should do.

     

    1) Create a new sheet and call it 'Highway Spending by Population Center and Route'.

    2) Drag [Population Center] from datasource 'Pop Centre Dissemination Block Highway' onto the Rows shelf.

    3) Switch to sheet 'Dissemination Blocks and Highways around Population Centers' and for both the population and population center filters select 'Apply to Worksheets' and select 'Highway Spending by Population Center and Route' to apply those filters to our new sheet.

    4) Switch back to 'Highway Spending by Population Center and Route', drag [Highway Roadname] onto the Detail shelf and [Highway Route Number1] onto the Rows shelf.

    5) Drag [Selected Amount Spent] onto the Columns shelf, and set the addressing using the 'Compute Using' option from the drop-down menu on the field. Select [Highway Roadname].

    6) Drag [Is First?] onto the filter shelf and select 'True' when prompted. Now use the 'Compute Using' menu option to set the addressing to use [Highway Roadname] as above. Finally select 'True' when offered 'True' or 'False'.

    7) From the Label shelf select 'Show mark labels'.

    8) Optionally format the [Selected Amount Spent] field and axis to use currency format.

     

    Your view should now look like this for Saskatoon.

    pastedImage_25.png

     

    One thing that is worth pointing out is that the calculated field [Selected Amount Spent] is the same field as we used on sheet 'Population and Highway Spending for Selected Areas', but gives a different answer this time because we have the route number dimension as well as population center on this sheet, so the result is broken down further.

     

    Finally create a dashboard, drag all the sheets on and arrange as you see fit.

     

    The filters should all just work on all sheets because of the way that we applied the filters from the first sheet to all of the other sheets.

     

    You will probably want to edit the titles and alias some of the entries in the legends and do various other bits of tidy up. Here's what mine looks like:

     

    pastedImage_27.png

    For extra bonus points you can do things like adding highlight actions to the dashboard so that you can click on route numbers in the bar chart and highlight the routes on the map:

     

    pastedImage_28.png

     

    I noticed that you had created extracts for both the census CSV file and the expenditure spreadsheet. That is definitely a good thing to do - after seeing that I've done it for mine and although I haven't timed it the workbook seems quicker - it is certainly really responsive. One thing you could do is recreate the census extract with a filter on province, so that you only include dissemination blocks for Saskatchewan. I don't think that will make a measurable difference to performance, but it saves a bit of space - and it's a good habit to get into, I think - no point in carrying around lots of excess data that is unrelated to what you are doing.

     

    So that's all there is to it.

     

    It has certainly turned into a much bigger exercise than I was expecting and we have covered an awful lot of ground and lots of different Tableau concepts and techniques. It's actually been really useful for me - I've been right out of the Tableau world for a long time so it's been a great chance to refresh my knowledge and get up to date on all the changes that have been happening since I was last using it regularly.

     

    As I say, I'm fully expecting some more questions (including working through the one you are stuck on at the moment). I'll get to those as and when I'm around.

     

    Good luck!

0/9000

 I can see the file under Box service account but not able to open the file, I have tried to download manually and open using windows built in apps, but still not opening. I am reading the png file using File read connector.

 

 Below is the Box connector code -

<box:create-files-content doc:name="Upload file" doc:id="b523395b-1655-461c-adfc-fa5200b21fb5" config-ref="Box_Connector_Config" filePartFilename='#"Image202405262133401png"'>

<box:create-files-attributes ><![CDATA[#output application/json --- { parent: { id: "0"}, name: "Image202405262133401.png" }]]></box:create-files-attributes><box:file-content ><![CDATA[#output application/java --- payload as String]]></box:file-content> </box:create-files-content>

0/9000
2 respuestas
0/9000
3 respuestas
  1. 24 abr 2023, 15:40

    @Joseph Crapanzano​ 

    Hi, I have modified your python script:

    import pandas as pd

    ⌗import tabpy

    ⌗from tableau_tools import prep_decimal, prep_int, prep_bool, prep_string, prep_date, prep_datetime

     

    # Define duration_columns as a global variable

    duration_columns = [

    'Step 1',

    'Step 2',

    'Step 3',

    'Step 4',

    'Step 5',

    'Step 6',

    'Step 7',

    ]

     

    def moving_average(data, window=10, max_visits=150):

    # Filter rows based on Appointment Status

    filtered_data = data[(data['appt_status'] == 'CHECKED_OUT') | (data['appt_status'] == 'CHECKING_OUT')]

    # Group by Appointment Type ID and sort by Appointment DateTime of Service

    grouped_data = filtered_data.groupby('type_id')

     

    # Initialize moving average columns with NaN

    for duration_column in duration_columns:

    data[f"Moving Average {duration_column}"] = float('nan')

     

    for name, group in grouped_data:

    sorted_group = group.sort_values(by='datetime')

    sorted_group = sorted_group.head(max_visits)

    if len(sorted_group) >= window:

    for duration_column in duration_columns:

    if duration_column in sorted_group.columns:

    sorted_group[f"Moving Average {duration_column}"] = sorted_group[duration_column].rolling(window=window).mean()

     

    # Update the moving average columns in the original dataset

    data.loc[sorted_group.index, [f"Moving Average {duration_column}" for duration_column in duration_columns]] = sorted_group[[f"Moving Average {duration_column}" for duration_column in duration_columns]]

     

    return data

     

    def get_output_schema():

    return pd.DataFrame({

    **{f'Moving Average {name}': prep_decimal() for i, name in enumerate(['Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5', 'Step 6', 'Step 7'], start=1)},

    })

     

    def prep_script(input):

    # Convert input data to pandas DataFrame

    input_data = input

     

    # Call the moving_average function

    output = moving_average(input_data)

    print(output)

     

    # Convert the result back to a list of dicts

    #output = [row.to_dict() for _, row in result.iterrows()]

     

    # Get the output schema using the get_output_schema function

    #output_schema = get_output_schema()

     

    # Return output and schema

    return output#, output_schema

    Now it is working, I think you can start from here.

     

    If this post resolves the question, would you be so kind to "Select as Best"?. This will help other users find the same answer/resolution and help community keep track of answered questions. Thank you.

     

    Regards,

     

    Diego Martinez

    Tableau Visionary and Forums Ambassador

0/9000

#Input

 

{

 

"street": "ABCS",

 

"code": "1234"

 

}

If sizeOf(code)>10 I need to append with street like "ABCD 1234" and remove the code key.

#Input

{

"street": "ABCS",

"code": "12345678910"

}

#Output

{

"street": "ABCS 12345678910"

}

 

Like that if sizeOf(code)<10 and street= null. I need to remove street key.

#Input

{

"street": null,

"code": "12345"

}

#Output

{

"code": "12345"

}

If sizeOf(code)>10 and street = null remove the code key and add the value to street.

#Input

{

"street": null,

"code": "12345678910"

}

#Output

{

"street": "12345678910"

}

I need to get all these scenarios in single response. Can anyone help me on this.

 

Regards

Niranjan K

3 respuestas
  1. 12 may 2022, 11:44

    @Mohammed Abdul Khader Sufi​ 

     

    Thanks for you response.

     

    But I need to verify both the fields. Last condition is not working. If code > 10 and street =null remove code and paste whatever the value coming from code to street.

     

    Is it possible to write down the condition in below similar way.

    {

    "street": condition,

    "code": condition

    }

     

    Regards

    Niranjan K

0/9000

Hi,

 

I am trying to list zip files in an FTP location and unzip it. It is working fine with File list and not with FTP list. Please help me on this.

 

Below is my code using zip extensions in FTP. I am listing all the zips files and it is working fine for File list but not for FTP list. in File pattern i have give as *.zip also . Below is my code. Please help me on this

 

<?xml version="1.0" encoding="UTF-8"?>

 

<mule xmlns:ftp="http://www.mulesoft.org/schema/mule/ftp"

xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" xmlns:compression="http://www.mulesoft.org/schema/mule/compression"

xmlns:file="http://www.mulesoft.org/schema/mule/file"

xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="

http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd

http://www.mulesoft.org/schema/mule/compression http://www.mulesoft.org/schema/mule/compression/current/mule-compression.xsd

http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd

http://www.mulesoft.org/schema/mule/ftp http://www.mulesoft.org/schema/mule/ftp/current/mule-ftp.xsd">

 

<file:config name="File_Config1" doc:name="File Config" doc:id="5370704c-51c3-4ec4-85ce-ef626e31432c" >

<file:connection workingDir="C:\Users\Srikanth.S\Documents\ProjectWork\Recordati\Unzips"/>

</file:config>

<file:config name="File_Config" doc:name="File Config" doc:id="1d1c6349-065a-47e2-9215-3f6f9c479b0e" >

<file:connection/>

</file:config>

<file:config name="File_Copy_Config" doc:name="File Config" doc:id="a6bb55e8-a14d-4c66-866f-c2db2ba8b6a7" />

<configuration-properties doc:name="Configuration properties" doc:id="5ffb2862-6f6b-45fd-ab24-18a444b8bd33" file="mule-app.properties" />

<ftp:config name="FTP_Config" doc:name="FTP Config" doc:id="7dc1248f-7b52-44f8-97ba-a29f43ba7402" >

<ftp:connection host="${ftp.host}" username="${ftp.user}" password="${ftp.pass}" />

</ftp:config>

<flow name="archive-extract-test" >

<file:list doc:name="List" doc:id="ab15b542-d086-49b9-83f6-5ae55b82aa00" config-ref="File_Copy_Config" directoryPath="C:\Users\Srikanth.S\Documents\ProjectWork\Recordati\Unzips\lists\">

<file:matcher filenamePattern="*.zip"/>

</file:list>

<foreach doc:name="For Each" doc:id="0abb4d26-5e74-4532-9713-9acbec2318aa" collection="payload">

<compression:extract doc:name="Extract" doc:id="90a2d174-ccaf-4264-bd81-49f1ab4a70a9">

<compression:extractor>

<compression:zip-extractor />

</compression:extractor>

</compression:extract>

<foreach doc:name="For Each" collection="payload">

 <file:write doc:name="Write" doc:id="0cfc3cd7-c444-432a-a0ea-6891f0f78c74" config-ref="File_Config1" path='#[output application/json

 

---

 

"output/" ++ (payload pluck $$)[0]]'>

<file:content><![CDATA[#output application/java --- ( payload pluck $)[0]]]></file:content>

</file:write>

</foreach>

</foreach>

 </flow>

<flow name="unzipfilestestFlow1" doc:id="fb2d2072-6446-42b2-900c-17cec597999d" >

<scheduler doc:name="Scheduler">

<scheduling-strategy>

<fixed-frequency frequency="15" timeUnit="SECONDS" />

</scheduling-strategy>

</scheduler>

<ftp:list doc:id="c90bfab4-7dcd-4a37-a67b-59b9b7f9375f" config-ref="FTP_Config" directoryPath="/Srikanth/FTPUnzips">

<ftp:matcher filenamePattern='"T7RecordDE_DEOTC_?*.zip"' />

</ftp:list>

<foreach doc:name="For Each" doc:id="50372e45-1488-46bf-838f-71acf015b0d5" collection="payload">

<compression:extract doc:name="Extract" doc:id="3fbfafd3-ee81-49c6-be66-6d7c9cc6d6d8" >

<compression:extractor >

<compression:zip-extractor />

</compression:extractor>

</compression:extract>

<foreach doc:name="For Each" doc:id="c117dbea-101d-4f93-8f2d-c55bffc04c38" >

<ftp:write doc:name="Write" doc:id="b91e2226-b0f1-4441-81bc-756e50b75336" config-ref="FTP_Config" path='#[output application/json

 

---

 

"output/" ++ (payload pluck $$)[0]]'>

<ftp:content ><![CDATA[#output application/java --- ( payload pluck $)[0]]]></ftp:content>

</ftp:write>

</foreach>

</foreach>

</flow>

 

</mule>

1 respuesta
  1. 14 jul 2020, 08:59

    It could be you are encountering case sensitivity on the remote file system vs your local windows machine which doesn't care? I'd try some tests doing lists with quite broad pattern to see what's going on. Also check if that question mark is being treated as a regex or not..

     

    Also: strongly recommend NOT using FTP as a protocol - it's missing the important "S" part (aka security).

0/9000

Hello all,

 

To comment out the source code from flow, Mule uses standard xml comments tag <!-- -->.  

This made some issues with Dataweave as it uses '---' separator and using '--' shows error in AnypointStudio 6(Mule3.x). 

I had to change from '---' to '- - -' to comment out soruce code.

 

In Mule4, this issues became much more serious, as Mule 4 uses dataweave expression instead of MEL. 

And evenmore, most of listener supports setting response types as follows 

 #output text/plan --- "vars.name : " ++ write(vars.name)

 

It is quite annoying to change whole '---' to other patterns temporary and to change back to original code.

 

Is there any alternative ways to solve this inconvenience?

How do you guys comment out some code in Mule4 flow?

 

Regards,

5 respuestas
  1. 10 oct 2019, 21:30

    We seem to be going round and round here. Let me say this...unless you externalize the dataweave script(s), you cannot comment XML code with Ctrl+Shift+/. That being said, the externalized dataweave expressions are within the same project...they are not anywhere outside of that project. By default, they are saved in src/main/resources. If writing dataweave expressions to a separate files is not an option, then my suggestion will not help in what you trying to do. IMO, externalizing the dataweave script has a couple of advantages: (1) Keeps my XML code clean i.e. it only contains xml and nothing else, so I dpn't have to deal with expressing non-xml content with CDATA element...that usually makes my code look ugly (2) If the dataweave expression needs to reusable, all I have to do is oint to the file where it is located rather than redefine it inline.

     

    my 2 cents.

    -gopal

0/9000
About this article

This article will discuss a technique that I uncovered recently that will allow Tableau to connect to virtually anything as a data source. Moreover, unlike the Web Data Connector, this technique supports live connections from Tableau server that are parameterized. The technique requires an instance of Microsoft SQL Server to serve as a proxy between Tableau and the data source. The only requirement for the underlying data source is that it must be something callable from the command line that returns output back to the command line console. As such, I'm going to give this technique the horrible acronym CLADS: "Command Line As Data Source"

 

I used CLADS to query a DB2 stored procedure, which isn't supported by Tableau. I will use that as an example herein. My stored procedure returned career statistics for any baseball player, so it required exactly one string parameter: the player name. I authored another article here to break down that specific DB2 use case in detail, but in this article I focus just on CLADS and leave the DB2 stuff out of it.

 

I also need to clarify that, in 2018, Tableau released the Tableau Connector Plugin SDK. It's still in beta, as of June 2019, but in my opinion, that SDK would be a much more fruitful way to pursue this use case. The SDK today boasts that it targets only ODBC connectivity, so CLADS might still be necessary for many use cases. I don't want to delete this discussion, but I would personally try to use that SDK versus the MSSQL/Python/StoredProc technique herein.

 

If this article is helpful to you, please click "like" and maybe add a comment, so others will see this article a little more easily in search results.

How does it work?

Step-by-step at a high level, here's how CLADS works:

  1. Tableau is configured to query a MSSQL stored procedure. Thereby, Tableau discerns from MSSQL what parameters are expected by the stored procedure, and how to satisfy each of them with either a static value or a parameter. The author can specify whether to use a Live or Extract connection as usual, and set up whatever authentication to MSSQL is required. This is all very standard behavior. Then Tableau calls an EXECUTE command on MSSQL, passing in the relevant parameters. So, for my example, Tableau called out to MSSQL with a command like this: "EXECUTE baseball_stored_procedure 'Kirby Puckett'".
  2. MSSQL now does a couple of things: first, it creates a simple temp table to store results. Then, things get exciting: our stored procedure calls out to the OS to do something else, via another procedure called "xp_cmdshell". Xp_cmdshell can take parameters, too, so before calling it, the stored procedure code needs to convert Tableau's parameters to the proper syntax. In my example, there wasn't much that needed to happen here. MSSQL called a Python script to work its magic: "insert #output (output) exec python.exe C:\myscripts\db2sp.py  'Kirby Puckett'"
  3. Now it's simply the job of the OS to issue the command, and return the results to standard output. In my case, Python queried DB2 and returned back a bunch of career statistics on one of my childhood heroes:
  4. MSSQL then stores all those results in a temp table, and returns the entire temp table back to Tableau. The temp table stores each CMD line as a single field, so Tableau would probably need to parse it to make it useful, but that's very easy to do in Tableau Desktop. In my example, I parsed "('Kirby Puckett', 'Minnesota Twins', 'AL', 1987)" into four columns using the SPLIT, MID, and similar functions.

Step-by-step example

1. Befriend your MSSQL administrator and ask him or her to create the following MSSQL stored procedure. This procedure doesn't do much -- it issues a "DIR" command returning a list of all the files in the directory of your choosing. The @string_cmd parameter reflects the directory. Note this code allows for some malicious behavior -- we're allowing MSSQL to execute an OS command, and we're just trusting that the OS command isn't 'DIR c:\temp & DEL c:\*', which would delete the entire c-drive. So please set this up carefully. It's also possible that your MSSQL instance has xp_cmdshell turned off entirely, or that the service account under which MSSQL runs has very limited privileges, so you may have to muddle your way through that as well.

 

CREATE PROCEDURE [dbo].[clads]

-- Add the parameters for the stored procedure here

@string_cmd varchar(255)

AS

DECLARE @os_command varchar(255)

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;

-- assemble the command to be sent to the OS.

SET @os_command = 'dir ' + @string_cmd

    -- Create a temp table. 

DECLARE @MyTempTable TABLE

(id int identity(1,1), output nvarchar(2000) null)

--Call the @os_command and put its output into the temp table.

insert @MyTempTable (output) exec xp_cmdshell @os_command

--Return the temp table to the calling procedure

select * from @MyTempTable where output is not null order by id

END

2. Test your new stored procedure from a MSSQL query window, using the command: exec clads 'c:\windows' or similar.

 

3. In a new workbook in Tableau Desktop, choose "Connect to Data" / "Microsoft SQL Server", then enter your credentials.

 

4. Drag the "clads" stored procedure over to the canvas, and specify your directory when prompted for parameters. "C:\windows" should be a good one. Click "Update Now" to see your result set! Author whatever dashboard you feel most compellingly displays the files in your directory of choice.

 

 

I hope that's helpful! I plan to author a companion article giving a step-by-step example of my specific Python/DB2 use case. And I welcome comments on other use cases where this might be useful. Thanks for reading!

1 respuesta
0/9000

This is a very strange problem, but maybe someone else is having it.

 

When I run a stored procedure that has a temp #Output table (where I have run inserts and calculations). for some reason, Period (Datetime) and Revenue (Money) refuses to appear, whereas all the fields from the ⌗Header table that I joined has appeared as well as some from #Output.

 

Another problem I get on occasion is Insert Data:Unbound field

No idea what this means. Seems to generate on the select from #output

 

Running all this through Sql Server 2008R2. When I run on Sql Server, I get no issues running any of the data, and get the results as expected.

 

Thank you!

2 respuestas
0/9000