eshangj/stackoverflow_q_and_a_sample huggingface dataset:
Question: I am trying to make a Mandelbrot set display, with the following code: import numpy as np import matplotlib.pyplot as plt plt.rcParams['toolbar'] = 'None' def mandelbrot(c, max_iter): z = 0 for n in range(max_iter): if abs(z) > 2: return n z = z*z + c return max_iter def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter): r1 = np.linspace(xmin, xmax, width) r2 = np.linspace(ymin, ymax, height) n3 = np.empty((width, height)) for i in range(width): for j in range(height): n3[i, j] = mandelbrot(r1[i] + 1j*r2[j], max_iter) return n3.T # Settings xmin, xmax, ymin, ymax = -2.0, 1.0, -1.5, 1.5 width, height = 800, 800 max_iter = 256 # Generate Mandelbrot set mandelbrot_image = mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter) # Window fig = plt.figure(figsize=(5, 5)) fig.canvas.manager.set_window_title('Mandelbrot Set') ax = fig.add_axes([0, 0, 1, 1]) # Fill the whole window ax.set_axis_off() # Show fractal ax.imshow(mandelbrot_image, extent=(xmin, xmax, ymin, ymax), cmap='hot') plt.show()  How could I zoom in on the fractal continuously, without taking up too many resources? I am running on a mid-range laptop, and it currently takes a long time to generate the fractal. Is there a faster way to do this when implementing a zoom feature?

Answer: You're using Python code to handle single NumPy numbers. That's the worst way. Would already be about twice as fast if you used Python numbers instead, using .tolist():  r1 = np.linspace(xmin, xmax, width).tolist() r2 = np.linspace(ymin, ymax, height).tolist()  But it's better to properly use NumPy, e.g., work on all pixels in parallel, keeping track of the values (and their indices) that still have abs ≤ 2: def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter): r1 = np.linspace(xmin, xmax, width) r2 = np.linspace(ymin, ymax, height) n3 = np.empty(width * height) z = np.zeros(width * height) c = np.add.outer(r1, 1j*r2).flatten() i = np.arange(width * height) for n in range(max_iter): outside = np.abs(z) > 2 n3[i[outside]] = n inside = ~outside z = z[inside] c = c[inside] i = i[inside] z = z*z + c n3[i] = max_iter return n3.reshape((width, height)).T  This now takes me about 0.17 seconds instead of about 6.7 seconds with your original.
Question: I am trying to assign a variable to an instance of a class such that the variable is of the same type. I want to use the instance itself in the construction of the variable. In order to be compatible with inheritance, I want to type hint it as Self rather than the class. The following works: class Foo: var: "Foo" def bar(self) -> None: self.var = self  However, var is marked as being of type Foo rather than Self. What I want is: from typing import Self class Foo: var: Self def bar(self) -> None: self.var = self  In this case, mypy gives me the following message: error: Incompatible types in assignment (expression has type "Foo", variable has type "Self") [assignment]  Clearly, self is not regarded as being of type Self but only of type Foo.

Answer: PEP 673 (ref https://peps.python.org/pep-0673/) introduced typing.Self in Python 3.11 to let you write: from typing import Self class Foo: def clone(self) -> Self: …  so that in subclasses clone() is recognized as returning the subclass type. But at the moment mypy only special‐cases Self in method signatures, not in attribute annotations at the class level. So when you write: class Foo: var: Self def bar(self) -> None: self.var = self  mypy still treats Self in var: Self as “the current class” (i.e. Foo) and complains when you assign self (which it types as plain Foo) to something it thinks is Self (the unknown late‐bound type). It’s essentially a bug/limitation in mypy’s handling of late‐bound attribute annotations. The pep has examples using TypeVar. I suggest combining that with generic to create a workaround. E.g., from typing import Generic, TypeVar T = TypeVar("T", bound="Foo") class Foo(Generic[T]): var: T # var is *exactly* whatever subclass type T is def bar(self: T) -> None: # now mypy knows `self` is of type T, and var is typed T, # so this assignment is safe self.var = self  Alternately, if you want a "quick fix", just annotate var with the class-name as you already did in your OP.
Question: I have a value that was encrypted using PHP openssl using cipher AES-CBC-256 but the passphrase for the final value was also encrypted using the same method. openssl_encrypt($key, $cipher, $passphrase, 0, $iv) I need to be able to unencrypt this data using Python but I'm running into block-size issues. Here's some of the code I have so far. I have tested decrypting this in PHP and it works properly. My final value in this example should be 'Jimmy'. import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad localKey = base64.b64decode('Po0KPxyF') localIv = base64.b64decode('s8W+/a4jkp9mhO3NkCL7Yg==') encrypted_value = base64.b64decode('hl5n6Nq5QYtgKIyLEVCupA==') encrypted_key = base64.b64decode('MGRHRFlaMzhCR0lxb2VHS1JHQXcrWkV2bkJpNWFZb3cybW9iQW5KYTlOU0xKK1FHc2pPUW1MUE9JRU5zTXN1Rg==') encrypted_iv = base64.b64decode('J31SrExr7KKIOertYIPhpQ==') # First need to encrypted key that uses the local key as the passphrase cipher_key = AES.new(pad(localKey,16), AES.MODE_CBC, localIv) decrypted_key = cipher_key.decrypt(encrypted_key) # Then decrypted the final value using the newly decrypted key cipher_key = AES.new(unpad(decrypted_key,16), AES.MODE_CBC, encrypted_iv) decrypted_value = cipher_key.decrypt(encrypted_value) 

Answer: I managed to figure out the PHP code that does the decryption: $localKey = base64_decode('Po0KPxyF'); $localIv = base64_decode('s8W+/a4jkp9mhO3NkCL7Yg=='); $encrypted_value = base64_decode('hl5n6Nq5QYtgKIyLEVCupA=='); $encrypted_key = base64_decode('MGRHRFlaMzhCR0lxb2VHS1JHQXcrWkV2bkJpNWFZb3cybW9iQW5KYTlOU0xKK1FHc2pPUW1MUE9JRU5zTXN1Rg=='); $encrypted_iv = base64_decode('J31SrExr7KKIOertYIPhpQ=='); $decrypted_key = openssl_decrypt(base64_decode($encrypted_key), 'aes-256-cbc', $localKey, OPENSSL_RAW_DATA, $localIv); $decrypted_value = openssl_decrypt($encrypted_value, 'aes-256-cbc', $decrypted_key, OPENSSL_RAW_DATA, $encrypted_iv); echo $decrypted_value;  Output: s:5:"Jimmy";  (Demo) Remarks:  $localKey is shorter than 256 bits, so openssl_decrypt() pads it with null bytes $encrypted_key was base64-encoded twice, so you need to decode it twice The value contained in $decrypted_value was serialized with serialize()  Here is a Python implementation (based on PyCryptodome): import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import unpad localKey = base64.b64decode('Po0KPxyF') localIv = base64.b64decode('s8W+/a4jkp9mhO3NkCL7Yg==') encrypted_value = base64.b64decode('hl5n6Nq5QYtgKIyLEVCupA==') encrypted_key = base64.b64decode('MGRHRFlaMzhCR0lxb2VHS1JHQXcrWkV2bkJpNWFZb3cybW9iQW5KYTlOU0xKK1FHc2pPUW1MUE9JRU5zTXN1Rg==') encrypted_iv = base64.b64decode('J31SrExr7KKIOertYIPhpQ==') # First need to encrypted key that uses the local key as the passphrase cipher_key = AES.new(localKey.ljust(32, b'\0'), AES.MODE_CBC, localIv) decrypted_key = cipher_key.decrypt(base64.b64decode(encrypted_key)) # Then decrypted the final value using the newly decrypted key cipher_key = AES.new(unpad(decrypted_key,16), AES.MODE_CBC, encrypted_iv) decrypted_value = cipher_key.decrypt(encrypted_value) value = unpad(decrypted_value,16).decode() print(value)  Output: s:5:"Jimmy";  (Demo)
Question: I have a dataframe with incomplete values as below - in particular ages with corresponding years, and I would like to make it square (i.e., all three cust_id to have correctly imputed values for age in all three years, i.e. I want to turn this: df = pl.DataFrame({ "cust_id": [1, 2 ,2, 2, 3, 3], "year": [2000,1999,2000,2001,1999,2001], "cust_age": [21,31,32,33,44,46] })  into this: df = pl.DataFrame({ "cust_id": [1, 1, 1, 2 ,2, 2, 3, 3, 3 ], "year": [1999,2000,2001,1999,2000,2001,1999,2000,2001], "cust_age": [20,21,22,31,32,33,44,45,46] })  I know I can iteratively create new dataframes and then join or shift values, and potentially use apply and/or eval_map but I was hoping to find something quick and idiomatic to polars. Thanks in advance for your help!

Answer: Here is a possible approach  # create all (year, cust_id) combinations index = df.select("year").unique().join(df.select("cust_id").unique(), how="cross") # compute the birth year of each customer as an expression birth_year = (pl.col("year") - pl.col("cust_age")).drop_nulls().first().over("cust_id") # use it to fill the missing customer ages res = ( index.join(df, on=["year", "cust_id"], how="left") .select( "cust_id", "year", (pl.col("year") - birth_year).alias("cust_age") ) .sort("cust_id", "year") # optional ) print(res)  Output: >>> res shape: (9, 3) ┌─────────┬──────┬──────────┐ │ cust_id ┆ year ┆ cust_age │ │ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ i64 │ ╞═════════╪══════╪══════════╡ │ 1 ┆ 1999 ┆ 20 │ │ 1 ┆ 2000 ┆ 21 │ │ 1 ┆ 2001 ┆ 22 │ │ 2 ┆ 1999 ┆ 31 │ │ 2 ┆ 2000 ┆ 32 │ │ 2 ┆ 2001 ┆ 33 │ │ 3 ┆ 1999 ┆ 44 │ │ 3 ┆ 2000 ┆ 45 │ │ 3 ┆ 2001 ┆ 46 │ └─────────┴──────┴──────────┘
Question: In the lxml.de website https://lxml.de/performance.html I see the following statement: A way to improve the normal attribute access time is static instantiation of the Python objects, thus trading memory for speed. Just create a cache dictionary and run: cache[root] = list(root.iter()) after parsing and: del cache[root] Can anyone provide me a suitable Python Code example about how these above mechanism can be used in a Python Function?

Answer: Setting a variable like cache[root] = list(root.iter()) will effectively cache objects in memory as demonstrated by a simple test. The cache mechanism is very simple: the whole document tree is loaded in memory and elements can be obtained in different ways but point to the same memory address. Given an XML document, get the id of an object before and after setting the cache. The id will be the same of the cache after setting it from lxml import etree, objectify otree = objectify.parse('tmp2.xml') root = otree.getroot() print(id(root.Form_1.Country), root.Form_1.Country) cache = {} cache[root] = list(otree.iter()) print(id(cache[root][3]), cache[root][3]) print(id(root.Form_1.Country), root.Form_1.Country) # both point to the same object in memory print(root.Form_1.Country is cache[root][3]) # the object can be obtained in different ways but point to the same object in the cache ele1 = root.xpath('(//Form_1/Country)[1]')[0] print(ele1 is cache[root][3])  Result 140257476833728 AFG 140257476833280 AFG 140257476833280 AFG True True  As explained in the link posted by the OP, it's trading memory for speed  A way to improve the normal attribute access time is static instantiation of the Python objects, thus trading memory for speed  Test XML <Forms> <greeting>Hello, world!</greeting> <Form_1> <Country>AFG</Country> <Country>AFG</Country> <Country>IND</Country> </Form_1> <Form_1> <Country>IND</Country> <Country>USA</Country> </Form_1> </Forms>
Question: I have a bubble chart developed using plotly library and here’s the data : import plotly.express as px import pandas as pd data = { "lib_acte":["test 98lop1", "test9665 opp1", "test QSDFR1", "test ABBE1", "testtest21","test23"], "x":[12.6, 10.8, -1, -15.2, -10.4, 1.6], "y":[15, 5, 44, -11, -35, -19], "circle_size":[375, 112.5, 60,210, 202.5, 195], "color":["green", "green", "green", "red", "red", "red"] } #load data into a DataFrame object: df = pd.DataFrame(data) fig = px.scatter( df, x="x", y="y", color="color", size='circle_size', text="lib_acte", hover_name="lib_acte", color_discrete_map={"red": "red", "green": "green"}, title="chart" ) fig.update_traces(textposition='middle right', textfont_size=14, textfont_color='black', textfont_family="Inter", hoverinfo="skip") newnames = {'red':'red title', 'green': 'green title'} fig.update_layout( { 'yaxis': { "range": [-200, 200], 'zerolinewidth': 2, "zerolinecolor": "red", "tick0": -200, "dtick":45, }, 'xaxis': { "range": [-200, 200], 'zerolinewidth': 2, "zerolinecolor": "gray", "tick0": -200, "dtick": 45, # "scaleanchor": 'y' }, "height": 800, } ) fig.add_scatter( x=[0, 0, -200, -200], y=[0, 200, 200, 0], fill="toself", fillcolor="gray", zorder=-1, mode="markers", marker_color="rgba(0,0,0,0)", showlegend=False, hoverinfo="skip" ) fig.add_scatter( x=[0, 0, 200, 200], y=[0, -200, -200, 0], fill="toself", fillcolor="yellow", zorder=-1, mode="markers", marker_color="rgba(0,0,0,0)", showlegend=False, hoverinfo="skip" ) fig.update_layout( paper_bgcolor="#F1F2F6", ) fig.show()  output :  now what I’m looking for please a way to add space between bubble if they are tight like (test 981op1 and test9665 opp1), and also a way to to increase the each bubble size 4% of its size for example. thanks for your help.

Answer: To change the size of your bubbles just do something like this:  multiplier = 1.04 # made bigger by 4% df["circle_size"] = df["circle_size"]*multiplier  But you still need to change the maximum size of the bubbles: Here i changed it to the biggest bubble size: biggest_bubble_size = max(df["circle_size"]) fig = px.scatter( df, x="x", y="y", color="color", size='circle_size', size_max= biggest_bubble_size, #change the maximum size of bubbles text="lib_acte", hover_name="lib_acte", color_discrete_map={"red": "red", "green": "green"}, title="chart" )  Now the bubbles seam too large, so i recommend setting the multiplier to something like this: multiplier = 0.1  And for the points being too close together just change the graph scale acording to the furthest point: maxrange = max(df["x"].max(), df["y"].max()) maxrange = maxrange*1.2 #to give some space to the furthest point number_of_lines = 10 #changes the number of lines in the graph  fig.update_layout( { 'yaxis': { "range": [-maxrange, maxrange], 'zerolinewidth': 2, "zerolinecolor": "red", "tick0": -maxrange, "dtick":maxrange/number_of_lines, }, 'xaxis': { "range": [-maxrange, maxrange], 'zerolinewidth': 2, "zerolinecolor": "gray", "tick0": -maxrange, "dtick": maxrange/number_of_lines, # "scaleanchor": 'y' }, "height": 800, } )
Question: How to convert multidimensional coordinate to standard coordinate in order to unify data when using xarray for nc data: import xarray as xr da = xr.DataArray( [[0, 1], [2, 3]], coords={ "lon": (["ny", "nx"], [[30, 40], [40, 50]]), "lat": (["ny", "nx"], [[10, 10], [20, 20]]), }, dims=["ny", "nx"], )  Expected conversion result: xr.DataArray( [[0, 1, np.nan], [np.nan, 2, 3]], coords={ "lat": [10, 20], "lon": [30, 40, 50], }) 

Answer: You can flatten the data into a list of points using xarray.DataArray.stack, extract unique coordinates and reassign values onto a regular grid using the unique coordinate values. import xarray as xr import numpy as np da = xr.DataArray( [[0, 1], [2, 3]], coords={ "lon": (["ny", "nx"], [[30, 40], [40, 50]]), "lat": (["ny", "nx"], [[10, 10], [20, 20]]), }, dims=["ny", "nx"], ) # Flatten flat = da.stack(z=("ny", "nx")) # Extract unique lat_vals = np.unique(da.lat.values) lon_vals = np.unique(da.lon.values) new_da = xr.DataArray( np.full((len(lat_vals), len(lon_vals)), np.nan), coords={"lat": lat_vals, "lon": lon_vals}, dims=["lat", "lon"] ) # Reassign values onto regular grid for i in range(flat.size): lat_i = float(flat.lat.values[i]) lon_i = float(flat.lon.values[i]) val = flat.values[i] new_da.loc[dict(lat=lat_i, lon=lon_i)] = val print(new_da)  Output: <xarray.DataArray (lat: 2, lon: 3)> Size: 48B array([[ 0., 1., nan], [nan, 2., 3.]]) Coordinates: * lat (lat) int64 16B 10 20 * lon (lon) int64 24B 30 40 50
Question: Package Versions:  SQLAlchemy 2.0.40 pandas 2.2.3 psycopg2-binary 2.9.10  I am trying to run a query using pandas' native param substitution, but I can't seem to get it to run without erroring. I tried simplifying the query to: select * FROM public.bq_results br WHERE cast("eventDate" as date) between TO_DATE('%test_start_date', 'YYYYMMDD') AND TO_DATE('%test_end_date', 'YYYYMMDD') limit 10000  but I get error: TypeError: dict is not a sequence  when running: df = pd.read_sql_query(query, self.__engine, params={"test_start_date": "20250101", "test_end_date": "20250131"})  where self.__engine = create_engine(f'postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}') 

Answer: The documentation of read_sql_query says the following: params : list, tuple or mapping, optional, default: None List of parameters to pass to execute method. The syntax used to pass parameters is database driver dependent. Check your database driver documentation for which of the five syntax styles, described in PEP 249’s paramstyle, is supported. Eg. for psycopg2, uses %(name)s so use params={‘name’ : ‘value’}.  Since you use the psycopg2 driver the parameters should be noted as @JonSG has mentioned. It should be: select * FROM public.bq_results br WHERE cast("eventDate" as date) between TO_DATE(%(test_start_date)s, 'YYYYMMDD') AND TO_DATE(%(test_end_date)s, 'YYYYMMDD') limit 10000  Hope this works.
Question: In Python 3.13 (haven't checked lower versions) there seem to be two locking mechanisms for the threading.Lock class. I've looked online but found no mentions of acquire_lock or release_lock and wanted to ask if anyone knows what the difference is between them and the standard acquire and release methods. Here's the threading.Lock class for reference. The methods are commented as undocumented: class Lock: def __enter__(self) -> bool: ... def __exit__( self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ... def release(self) -> None: ... def locked(self) -> bool: ... def acquire_lock(self, blocking: bool = ..., timeout: float = ...) -> bool: ... # undocumented def release_lock(self) -> None: ... # undocumented def locked_lock(self) -> bool: ... # undocumented  Just curious whether there's a difference between the call lock.acquire_lock and lock.acquire or whether this is merely a name-change that will take effect in the future.

Answer: currently, they are just aliases, and according to github history they have been like that for the past 15 years, you shouldn't be using undocumented functions, they can be removed at any time.  {"acquire_lock", _PyCFunction_CAST(lock_PyThread_acquire_lock), ... {"acquire", _PyCFunction_CAST(lock_PyThread_acquire_lock), ... {"release_lock", lock_PyThread_release_lock, ... {"release", lock_PyThread_release_lock,   the best thing to do is not use any of the 4 functions anyway, instead use a with block to properly lock and release the lock when an exception is thrown. some_lock = Lock() with some_lock: # code protected by lock here # lock released when exception is thrown
Question: I tried to create a histogram with a legend outside the axes. Here is my code: import pandas as pd import seaborn as sns df_long = pd.DataFrame({ "Category": ["A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D"], "Round": ["Round1", "Round1", "Round1", "Round1", "Round2", "Round2", "Round2", "Round2", "Round3", "Round3", "Round3", "Round3", "Round4", "Round4", "Round4", "Round4"], "Value": [10, 20, 10, 30, 20, 25, 15, 25, 12, 15, 19, 6, 10, 29, 13, 19] }) ax = sns.histplot(df_long, x="Category", hue="Round", weights="Value", multiple="stack", shrink=.8, ) ax.set_ylabel('Weight') legend = ax.get_legend() legend.set_bbox_to_anchor((1, 1))  It works fine in jupyter notebook:  But, if I try to create a png or pdf using matplotlib, the legend is not displayed completely. import matplotlib.pyplot as plt plt.savefig("histogram.png") plt.savefig("histogram.pdf")   I've already tried to adjust the size of the graph by using plt.figure(figsize=(4, 4)) and the problem still exist.

Answer: The solution is to use bbox_inches = 'tight' in the plt.savefig() function: import matplotlib.pyplot as plt plt.savefig("histogram.png",bbox_inches='tight') plt.savefig("histogram.pdf", bbox_inches='tight')
Question: When creating density heatmaps / 2d histograms, there is an automatic aggregation that can take place, which also sets the name as it appears on the legend. I'm trying to change how that aggregation is displayed on the legend. Consider the following example, taken directly from the plotly docs: import plotly.express as px df = px.data.tips() fig = px.density_heatmap(df, x="total_bill", y="tip") fig.show()   How can I pass a string that will alter the "count" as it appears on the legend? I've tried with .update_layout(legend_title_text = "Test string") but did not manage to get anywhere.

Answer: Try setting the title.text property of coloraxis_colorbar inside layout. df = px.data.tips() fig = px.density_heatmap(df, x="total_bill", y="tip") fig.update_layout(coloraxis_colorbar=dict( title=dict( text="Number of Bills per Cell") ) ) fig.show()  You can also define this in a single line using coloraxis_colorbar_title_text. import plotly.express as px df = px.data.tips() fig = px.density_heatmap(df, x="total_bill", y="tip") fig.update_layout(coloraxis_colorbar_title_text="Number of Bills per Cell") fig.show()  Colorscales - Plotly
Question: I have loaded two fact tables CDI and Population and a couple dimension tables in DuckDB. I did joins on the CDI fact table and its respective dimension tables which yields a snippet of the table below  And below is the Population fact table merged with its other dimension tables yielding this snippet below   Now what I want to basically do is filter out the Population table based only on the values of this particular row of the CDI table. In this case the current row outlined in green will somehow do this query SELECT Year, SUM(Population) AS TotalPopulation FROM Population WHERE (Year BETWEEN 2018 AND 2018) AND (Age BETWEEN 18 AND 85) AND State = 'Pennsylvania' AND Sex IN ('Male', 'Female') AND Ethnicity IN ('Multiracial') AND Origin IN ('Not Hispanic') GROUP BY Year ORDER BY Year ASC  This query aggregates the Population column values based on the row values of the CDI table. What I'm just at a loss in trying to implement is doing this aggregation operation for all row values in the CDI table. Here is a full visualization of what I'm trying to do.  How would I implement this type of varying filtering aggregation based on each row column values of the CDI table? I'm using DuckDB as the OLAP DB here so ANSI SQL is what I'm trying to use to implement this task. Could it be possible only using this kind of SQL?

Answer: I agree with Chris Maurer comment, here is a SQL query to achieve what you are looking for : SELECT YearStart, YearEnd, LocationDesc, AgeStart, AgeEnd, Sex, Ethnicity, Origin, Sun(Population) AS TotalPopulation FROM CDI LEFT JOIN Population AS pop ON (pop.Year BETWEEN CDI.YearStart AND CDI.YearEnd) AND (CDI.Sex=pop.Sex OR CDI.Sex='both') AND (pop.Age BETWEEN pop.AgeStart AND (CASE WHEN pop.AgeEnd='infinity' THEN 1000 ELSE pop.AgeEnd END)) AND (CDI.LocationDesc = pop.State) AND (CDI.Ethnicity=pop.Ethnicity OR CDI.Ethnicity='All') AND (CDI.Origin=pop.Origin OR CDI.Origin='Both') GROUP BY 1,2,3,4,5,6,7,8 ORDER BY 9 DESC  Hope this helps.
Question: matrix1=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] m2="\n".join(["\t".join([ritem for ritem in item]) for item in matrix1]) print(m2)  where am i wrong that i receive this error?

Answer: The values you try to join with str.join must be strings themselves. You're trying to join ints and this is causing the error you're seeing. You want: m2 = "\n".join(["\t".join([str(ritem) for ritem in item]) for item in matrix1])  Note that you can pass any iterable, and not just a list, so you can remove some extraneous [ and ] to create generator expressions rather than list comprehensions. "\n".join("\t".join(str(ritem) for ritem in item) for item in matrix1)  Or even just: "\n".join("\t".join(map(str, item)) for item in matrix1)